1/**
2 * Text selection related functions.
3 */
4
5/**
6 * selection prototype
7 *
8 * Object that capsulates the selection in a textarea. Returned by DWgetSelection.
9 *
10 * @author Andreas Gohr <andi@splitbrain.org>
11 */
12function selection_class(){
13    this.start     = 0;
14    this.end       = 0;
15    this.obj       = null;
16    this.scroll    = 0;
17    this.fix       = 0;
18
19    this.getLength = function(){
20        return this.end - this.start;
21    };
22
23    this.getText = function(){
24        return (!this.obj) ? '' : this.obj.value.substring(this.start,this.end);
25    };
26}
27
28/**
29 * Get current selection/cursor position in a given textArea
30 *
31 * @link   http://groups.drupal.org/node/1210
32 * @author Andreas Gohr <andi@splitbrain.org>
33 * @link   http://linebyline.blogspot.com/2006/11/textarea-cursor-position-in-internet.html
34 * @returns object - a selection object
35 */
36function DWgetSelection(textArea) {
37    var sel = new selection_class();
38
39    textArea.focus();
40    sel.obj   = textArea;
41    sel.start  = textArea.selectionStart;
42    sel.end    = textArea.selectionEnd;
43    sel.scroll = textArea.scrollTop;
44    return sel;
45}
46
47/**
48 * Set the selection
49 *
50 * You need to get a selection object via DWgetSelection() first, then modify the
51 * start and end properties and pass it back to this function.
52 *
53 * @link http://groups.drupal.org/node/1210
54 * @author Andreas Gohr <andi@splitbrain.org>
55 * @param {selection_class} selection  a selection object as returned by DWgetSelection()
56 */
57function DWsetSelection(selection){
58    selection.obj.setSelectionRange(selection.start, selection.end);
59    if(selection.scroll) selection.obj.scrollTop = selection.scroll;
60}
61
62/**
63 * Inserts the given text at the current cursor position or replaces the current
64 * selection
65 *
66 * @author Andreas Gohr <andi@splitbrain.org>
67 * @param {string}  text           the new text to be pasted
68 * @param {selection_class}  selection     selection object returned by DWgetSelection
69 * @param {int}     opts.startofs  number of charcters at the start to skip from new selection
70 * @param {int}     opts.endofs    number of characters at the end to skip from new selection
71 * @param {boolean} opts.nosel     set true if new text should not be selected
72 */
73function pasteText(selection,text,opts){
74    if(!opts) opts = {};
75    // replace the content
76
77    selection.obj.value =
78        selection.obj.value.substring(0, selection.start) + text +
79        selection.obj.value.substring(selection.end, selection.obj.value.length);
80
81    // set new selection
82    if (is_opera) {
83        // Opera replaces \n by \r\n when inserting text.
84        selection.end = selection.start + text.replace(/\r?\n/g, '\r\n').length;
85    } else {
86        selection.end = selection.start + text.length;
87    }
88
89
90    // modify the new selection if wanted
91    if(opts.startofs) selection.start += opts.startofs;
92    if(opts.endofs)   selection.end   -= opts.endofs;
93
94    // no selection wanted? set cursor to end position
95    if(opts.nosel) selection.start = selection.end;
96
97    DWsetSelection(selection);
98}
99
100
101/**
102 * Format selection
103 *
104 * Apply tagOpen/tagClose to selection in textarea, use sampleText instead
105 * of selection if there is none.
106 *
107 * @author Andreas Gohr <andi@splitbrain.org>
108 */
109function insertTags(textAreaID, tagOpen, tagClose, sampleText){
110    var txtarea = jQuery('#' + textAreaID)[0];
111
112    var selection = DWgetSelection(txtarea);
113    var text = selection.getText();
114    var opts;
115
116    // don't include trailing space in selection
117    if(text.charAt(text.length - 1) == ' '){
118        selection.end--;
119        text = selection.getText();
120    }
121
122    if(!text){
123        // nothing selected, use the sample text and select it
124        text = sampleText;
125        opts = {
126            startofs: tagOpen.length,
127            endofs: tagClose.length
128        };
129    }else{
130        // place cursor at the end
131        opts = {
132            nosel: true
133        };
134    }
135
136    // surround with tags
137    text = tagOpen + text + tagClose;
138
139    // do it
140    pasteText(selection,text,opts);
141}
142
143/**
144 * Wraps around pasteText() for backward compatibility
145 *
146 * @author Andreas Gohr <andi@splitbrain.org>
147 */
148function insertAtCarret(textAreaID, text){
149    var txtarea = jQuery('#' + textAreaID)[0];
150    var selection = DWgetSelection(txtarea);
151    pasteText(selection,text,{nosel: true});
152}
153