summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--inc/toolbar.php3
-rw-r--r--lib/exe/js.php1
-rw-r--r--lib/scripts/edit.js75
-rw-r--r--lib/scripts/textselection.js175
-rw-r--r--lib/scripts/toolbar.js206
5 files changed, 251 insertions, 209 deletions
diff --git a/inc/toolbar.php b/inc/toolbar.php
index af1dc8d05..3188c9ac9 100644
--- a/inc/toolbar.php
+++ b/inc/toolbar.php
@@ -172,6 +172,9 @@ function toolbar_JSdefines($varname){
'icon' => 'sig.png',
'key' => 'y',
),
+
+
+
));
} // end event TOOLBAR_DEFINE default action
$evt->advise_after();
diff --git a/lib/exe/js.php b/lib/exe/js.php
index 26323e9b0..7c5ad021c 100644
--- a/lib/exe/js.php
+++ b/lib/exe/js.php
@@ -51,6 +51,7 @@ function js_out(){
);
if($edit){
if($write){
+ $files[] = DOKU_INC.'lib/scripts/textselection.js';
$files[] = DOKU_INC.'lib/scripts/toolbar.js';
$files[] = DOKU_INC.'lib/scripts/edit.js';
}
diff --git a/lib/scripts/edit.js b/lib/scripts/edit.js
index 34305c53d..517daa086 100644
--- a/lib/scripts/edit.js
+++ b/lib/scripts/edit.js
@@ -126,81 +126,6 @@ function showPicker(pickerid,btn){
}
/**
- * Create a toolbar
- *
- * @param string tbid ID of the element where to insert the toolbar
- * @param string edid ID of the editor textarea
- * @param array tb Associative array defining the buttons
- * @author Andreas Gohr <andi@splitbrain.org>
- */
-function initToolbar(tbid,edid,tb){
- var toolbar = $(tbid);
- if(!toolbar) return;
-
- //empty the toolbar area:
- toolbar.innerHTML='';
-
- var cnt = tb.length;
- for(var i=0; i<cnt; i++){
- // create new button
- var btn = createToolButton(tb[i]['icon'],
- tb[i]['title'],
- tb[i]['key']);
-
- var actionFunc = 'addBtnAction'+tb[i]['type'].charAt(0).toUpperCase()+tb[i]['type'].substring(1);
- var exists = eval("typeof("+actionFunc+") == 'function'");
- if(exists)
- {
- if(eval(actionFunc+"(btn, tb[i], edid, i)"))
- toolbar.appendChild(btn);
- }else{
- alert('unknown type: '+tb[i]['type']);
- }
- } // end for
-}
-
-/**
- * Add button action for format buttons
- *
- * @param DOMElement btn Button element to add the action to
- * @param array props Associative array of button properties
- * @param string edid ID of the editor textarea
- * @return boolean If button should be appended
- * @author Gabriel Birke <birke@d-scribe.de>
- */
-function addBtnActionFormat(btn, props, edid)
-{
- var sample = props['title'];
- if(props['sample']){ sample = props['sample']; }
- eval("btn.onclick = function(){insertTags('"+
- jsEscape(edid)+"','"+
- jsEscape(props['open'])+"','"+
- jsEscape(props['close'])+"','"+
- jsEscape(sample)+
- "');return false;}");
-
- return true;
-}
-
-/**
- * Add button action for insert buttons
- *
- * @param DOMElement btn Button element to add the action to
- * @param array props Associative array of button properties
- * @param string edid ID of the editor textarea
- * @return boolean If button should be appended
- * @author Gabriel Birke <birke@d-scribe.de>
- */
-function addBtnActionInsert(btn, props, edid)
-{
- eval("btn.onclick = function(){insertAtCarret('"+
- jsEscape(edid)+"','"+
- jsEscape(props['insert'])+
- "');return false;}");
- return true;
-}
-
-/**
* Add button action for signature button
*
* @param DOMElement btn Button element to add the action to
diff --git a/lib/scripts/textselection.js b/lib/scripts/textselection.js
new file mode 100644
index 000000000..537e8d348
--- /dev/null
+++ b/lib/scripts/textselection.js
@@ -0,0 +1,175 @@
+/**
+ * Text selection related functions.
+ */
+
+/**
+ * selection prototype
+ *
+ * Object that capsulates the selection in a textarea. Returned by getSelection.
+ *
+ * @author Andreas Gohr <andi@splitbrain.org>
+ */
+function selection_class(){
+ this.start = 0;
+ this.end = 0;
+ this.obj = null;
+ this.rangeCopy = null;
+
+ this.getLength = function(){
+ return this.end - this.start;
+ };
+
+ this.getText = function(){
+ if(!this.obj) return '';
+ return this.obj.value.substring(this.start,this.end);
+ }
+}
+
+/**
+ * Get current selection/cursor position in a given textArea
+ *
+ * @link http://groups.drupal.org/node/1210
+ * @author Andreas Gohr <andi@splitbrain.org>
+ * @returns object - a selection object
+ */
+function getSelection(textArea) {
+ var sel = new selection_class();
+
+ sel.obj = textArea;
+ sel.start = textArea.value.length;
+ sel.end = textArea.value.length;
+
+ textArea.focus();
+ if(document.getSelection) { // Mozilla et al.
+ sel.start = textArea.selectionStart;
+ sel.end = textArea.selectionEnd;
+ } else if(document.selection) { // MSIE
+ // The current selection
+ var range = document.selection.createRange();
+ sel.rangeCopy = range.duplicate();
+ // Select all text
+ sel.rangeCopy.moveToElementText(textArea);
+ // Now move 'dummy' end point to end point of original range
+ sel.rangeCopy.setEndPoint( 'EndToEnd', range );
+ // Now we can calculate start and end points
+ sel.start = sel.rangeCopy.text.length - range.text.length;
+ sel.end = sel.start + range.text.length;
+ }
+ return sel;
+}
+
+/**
+ * Set the selection
+ *
+ * You need to get a selection object via getSelection() first, then modify the
+ * start and end properties and pass it back to this function.
+ *
+ * @link http://groups.drupal.org/node/1210
+ * @author Andreas Gohr <andi@splitbrain.org>
+ * @param object selection - a selection object as returned by getSelection()
+ */
+function setSelection(selection){
+ if(document.getSelection){ // FF
+ // what a pleasure in FF ;)
+ selection.obj.setSelectionRange(selection.start,selection.end);
+ } else if(document.selection) { // IE
+ // count number of newlines in str to work around stupid IE selection bug
+ var countNL = function(str) {
+ var m = str.split("\n");
+ if (!m || !m.length) return 0;
+ return m.length-1;
+ };
+ var fix = countNL(selection.obj.value.substring(0,selection.start));
+
+ selection.rangeCopy.collapse(true);
+ selection.rangeCopy.moveStart('character',selection.start - fix);
+ selection.rangeCopy.moveEnd('character',selection.end - selection.start);
+ selection.rangeCopy.select();
+ }
+}
+
+/**
+ * Inserts the given text at the current cursor position or replaces the current
+ * selection
+ *
+ * @author Andreas Gohr <andi@splitbrain.org>
+ * @param string text - the new text to be pasted
+ * @param objct selecttion - selection object returned by getSelection
+ * @param int opts.startofs - number of charcters at the start to skip from new selection
+ * @param int opts.endofs - number of charcters at the end to skip from new selection
+ * @param bool opts.ofs - set tru if new text should not be selected
+ */
+function pasteText(selection,text,opts){
+ if(!opts) opts = {};
+ // replace the content
+ selection.obj.value =
+ selection.obj.value.substring(0, selection.start) + text +
+ selection.obj.value.substring(selection.end, selection.obj.value.length);
+
+ // set new selection
+ selection.end = selection.start + text.length;
+
+ // modify the new selection if wanted
+ if(opts.startofs) selection.start += opts.startofs;
+ if(opts.endofs) selection.end -= opts.endofs;
+
+ // no selection wanted? set cursor to end position
+ if(opts.nosel) selection.start = selection.end;
+
+ setSelection(selection);
+}
+
+
+/**
+ * Format selection
+ *
+ * Apply tagOpen/tagClose to selection in textarea, use sampleText instead
+ * of selection if there is none.
+ *
+ * @author Andreas Gohr <andi@splitbrain.org>
+ */
+function insertTags(textAreaID, tagOpen, tagClose, sampleText){
+ var txtarea = $(textAreaID);
+
+ var selection = getSelection(txtarea);
+ var text = selection.getText();
+ var opts;
+
+ // don't include trailing space in selection
+ if(text.charAt(text.length - 1) == ' '){
+ selection.end--;
+ text = selection.getText();
+ }
+
+ if(!text){
+ // nothing selected, use the sample text and select it
+ text = sampleText;
+ opts = {
+ startofs: tagOpen.length,
+ endofs: tagClose.length
+ };
+ }else{
+ // place cursor at the end
+ opts = {
+ nosel: true
+ };
+ }
+
+ // surround with tags
+ text = tagOpen + text + tagClose;
+
+ // do it
+ pasteText(selection,text,opts);
+}
+
+/**
+ * Wraps around pasteText() for backward compatibility
+ *
+ * @author Andreas Gohr <andi@splitbrain.org>
+ */
+function insertAtCarret(textAreaID, text){
+ var txtarea = $(textAreaID);
+ var selection = getSelection(txtarea);
+ pasteText(selection,text,{nosel: true});
+}
+
diff --git a/lib/scripts/toolbar.js b/lib/scripts/toolbar.js
index f31e12887..18d2daede 100644
--- a/lib/scripts/toolbar.js
+++ b/lib/scripts/toolbar.js
@@ -1,161 +1,99 @@
/**
- * selection prototype
+ * Create a toolbar
*
- * Object that capsulates the selection in a textarea. Returned by getSelection.
+ * @param string tbid ID of the element where to insert the toolbar
+ * @param string edid ID of the editor textarea
+ * @param array tb Associative array defining the buttons
+ * @author Andreas Gohr <andi@splitbrain.org>
*/
-function selection_class(){
- this.start = 0;
- this.end = 0;
- this.obj = null;
- this.rangeCopy = null;
-
- this.getLength = function(){
- return this.end - this.start;
- };
-
- this.getText = function(){
- if(!this.obj) return '';
- return this.obj.value.substring(this.start,this.end);
- }
-}
+function initToolbar(tbid,edid,tb){
+ var toolbar = $(tbid);
+ if(!toolbar) return;
+
+ //empty the toolbar area:
+ toolbar.innerHTML='';
+
+ var cnt = tb.length;
+ for(var i=0; i<cnt; i++){
+ var actionFunc;
+
+ // create new button
+ var btn = createToolButton(tb[i]['icon'],
+ tb[i]['title'],
+ tb[i]['key']);
+
+
+ // type is a tb function -> assign it as onclick
+ actionFunc = 'tb_'+tb[i]['type'];
+ if( isFunction(window[actionFunc]) ){
+ addEvent(btn,'click', function(func,btn, props, edid){
+ return function(){
+ window[func](btn, props, edid);
+ return false;
+ }
+ }(actionFunc,btn,tb[i],edid) );
+ //above fixes the scope problem as descried at http://www.mennovanslooten.nl/blog/post/62
+ toolbar.appendChild(btn);
+ continue;
+ }
+
+ // type is a init function -> execute it
+ actionFunc = 'addBtnAction'+tb[i]['type'].charAt(0).toUpperCase()+tb[i]['type'].substring(1);
+ if( isFunction(window[actionFunc]) ){
+ if(window[actionFunc](btn, tb[i], edid, i)){
+ toolbar.appendChild(btn);
+ }
+ continue;
+ }
+
+ console.log('unknown toolbar type: '+tb[i]['type']+' '+actionFunc); //FIXME make alert
+ } // end for
-/**
- * Get current selection/cursor position in a given textArea
- *
- * @link http://groups.drupal.org/node/1210
- * @returns object - a selection object
- */
-function getSelection(textArea) {
- var sel = new selection_class();
-
- sel.obj = textArea;
- sel.start = textArea.value.length;
- sel.end = textArea.value.length;
-
- textArea.focus();
- if(document.getSelection) { // Mozilla et al.
- sel.start = textArea.selectionStart;
- sel.end = textArea.selectionEnd;
- } else if(document.selection) { // MSIE
- // The current selection
- var range = document.selection.createRange();
- sel.rangeCopy = range.duplicate();
- // Select all text
- sel.rangeCopy.moveToElementText(textArea);
- // Now move 'dummy' end point to end point of original range
- sel.rangeCopy.setEndPoint( 'EndToEnd', range );
- // Now we can calculate start and end points
- sel.start = sel.rangeCopy.text.length - range.text.length;
- sel.end = sel.start + range.text.length;
- }
- return sel;
}
/**
- * Set the selection
+ * Button action for format buttons
*
- * You need to get a selection object via getSelection() first, then modify the
- * start and end properties and pass it back to this function.
- *
- * @link http://groups.drupal.org/node/1210
- * @param object selection - a selection object as returned by getSelection()
+ * @param DOMElement btn Button element to add the action to
+ * @param array props Associative array of button properties
+ * @param string edid ID of the editor textarea
+ * @author Gabriel Birke <birke@d-scribe.de>
+ * @author Andreas Gohr <andi@splitbrain.org>
*/
-function setSelection(selection){
- if(document.getSelection){ // FF
- // what a pleasure in FF ;)
- selection.obj.setSelectionRange(selection.start,selection.end);
- } else if(document.selection) { // IE
- // count number of newlines in str to work around stupid IE selection bug
- var countNL = function(str) {
- var m = str.split("\n");
- if (!m || !m.length) return 0;
- return m.length-1;
- };
- var fix = countNL(selection.obj.value.substring(0,selection.start));
-
- selection.rangeCopy.collapse(true);
- selection.rangeCopy.moveStart('character',selection.start - fix);
- selection.rangeCopy.moveEnd('character',selection.end - selection.start);
- selection.rangeCopy.select();
+function tb_format(btn, props, edid) {
+ var sample = props['title'];
+ if(props['sample']){
+ sample = props['sample'];
}
+ insertTags(edid,
+ fixtxt(props['open']),
+ fixtxt(props['close']),
+ fixtxt(sample));
+ return false;
}
/**
- * Inserts the given text at the current cursor position or replaces the current
- * selection
+ * Button action for insert buttons
*
+ * @param DOMElement btn Button element to add the action to
+ * @param array props Associative array of button properties
+ * @param string edid ID of the editor textarea
+ * @author Gabriel Birke <birke@d-scribe.de>
* @author Andreas Gohr <andi@splitbrain.org>
- * @param string text - the new text to be pasted
- * @param objct selecttion - selection object returned by getSelection
- * @param int opts.startofs - number of charcters at the start to skip from new selection
- * @param int opts.endofs - number of charcters at the end to skip from new selection
- * @param bool opts.ofs - set tru if new text should not be selected
*/
-function pasteText(selection,text,opts){
- if(!opts) opts = {};
- // replace the content
- selection.obj.value =
- selection.obj.value.substring(0, selection.start) + text +
- selection.obj.value.substring(selection.end, selection.obj.value.length);
-
- // set new selection
- selection.end = selection.start + text.length;
-
- // modify the new selection if wanted
- if(opts.startofs) selection.start += opts.startofs;
- if(opts.endofs) selection.end -= opts.endofs;
-
- // no selection wanted? set cursor to end position
- if(opts.nosel) selection.start = selection.end;
-
- setSelection(selection);
+function tb_insert(btn, props, edid) {
+ insertAtCarret(edid,fixtxt(props['insert']));
}
-/**
- * Format selection
- *
- * Apply tagOpen/tagClose to selection in textarea, use sampleText instead
- * of selection if there is none.
- *
- * @author Andreas Gohr <andi@splitbrain.org>
- */
-function insertTags(textAreaID, tagOpen, tagClose, sampleText){
- var txtarea = document.getElementById(textAreaID);
-
- var selection = getSelection(txtarea);
- var text = selection.getText();
- // don't include trailing space in selection
- if(text.charAt(text.length - 1) == ' '){
- selection.end--;
- text = selection.getText();
- }
-
- // nothing selected, use the sample text
- if(!text) text = sampleText;
-
- // surround with tags
- text = tagOpen + text + tagClose;
- // prepare options
- var opts = {
- startofs: tagOpen.length,
- endofs: tagClose.length
- };
- // do it
- pasteText(selection,text,opts);
-}
/**
- * Wraps around pasteText() for backward compatibility
- *
- * @author Andreas Gohr <andi@splitbrain.org>
+ * Replaces \n with linebreaks
*/
-function insertAtCarret(textAreaID, text){
- var txtarea = document.getElementById(textAreaID);
- var selection = getSelection(txtarea);
- pasteText(selection,text,{nosel: true});
+function fixtxt(str){
+ return str.replace(/\\n/g,"\n");
}