xref: /dokuwiki/lib/scripts/toolbar.js (revision 7e35897ac5211dac14f90356eb59f982d61c3c7a)
1// used to identify pickers
2var pickercounter=0;
3
4/**
5 * Create a toolbar
6 *
7 * @param  string tbid       ID of the element where to insert the toolbar
8 * @param  string edid       ID of the editor textarea
9 * @param  array  tb         Associative array defining the buttons
10 * @param  bool   allowblock Allow buttons creating multiline content
11 * @author Andreas Gohr <andi@splitbrain.org>
12 */
13function initToolbar(tbid,edid,tb, allowblock){
14    var $toolbar, $edit;
15    if (typeof tbid == 'string') {
16        $toolbar = jQuery('#' + tbid);
17    } else {
18        $toolbar = jQuery(tbid);
19    }
20
21    $edit = jQuery('#' + edid);
22
23    if ($toolbar.length == 0 || $edit.length == 0 || $edit.attr('readOnly')) {
24        return;
25    }
26
27    if (typeof allowblock === 'undefined') {
28        allowblock = true;
29    }
30
31    //empty the toolbar area:
32    $toolbar.html('');
33
34    jQuery.each(tb, function (k, val) {
35        if (!tb.hasOwnProperty(k) || (!allowblock && val.block === true)) {
36            return;
37        }
38        var actionFunc, $btn;
39
40        // create new button (jQuery object)
41        $btn = jQuery(createToolButton(val.icon, val.title, val.key, val.id,
42                                       val['class']));
43
44        // type is a tb function -> assign it as onclick
45        actionFunc = 'tb_'+val.type;
46        if( jQuery.isFunction(window[actionFunc]) ){
47            $btn.on('click', bind(window[actionFunc],$btn,val,edid) );
48            $toolbar.append($btn);
49            return;
50        }
51
52        // type is a init function -> execute it
53        actionFunc = 'addBtnAction'+val.type.charAt(0).toUpperCase()+val.type.substring(1);
54        if( jQuery.isFunction(window[actionFunc]) ){
55            var pickerid = window[actionFunc]($btn, val, edid);
56            if(pickerid !== ''){
57                $toolbar.append($btn);
58                $toolbar.append(jQuery('#'+pickerid));
59                $btn.attr('aria-controls', pickerid);
60                if (actionFunc === 'addBtnActionPicker') {
61                    $btn.attr('aria-haspopup', 'true');
62                }
63            }
64            return;
65        }
66
67        alert('unknown toolbar type: '+val.type+'  '+actionFunc);
68    });
69}
70
71/**
72 * Button action for format buttons
73 *
74 * @param  DOMElement btn   Button element to add the action to
75 * @param  array      props Associative array of button properties
76 * @param  string     edid  ID of the editor textarea
77 * @author Gabriel Birke <birke@d-scribe.de>
78 * @author Andreas Gohr <andi@splitbrain.org>
79 */
80function tb_format(btn, props, edid) {
81    var sample = props.sample || props.title;
82    insertTags(edid,
83               fixtxt(props.open),
84               fixtxt(props.close),
85               fixtxt(sample));
86    pickerClose();
87    return false;
88}
89
90/**
91 * Button action for format buttons
92 *
93 * This works exactly as tb_format() except that, if multiple lines
94 * are selected, each line will be formatted seperately
95 *
96 * @param  DOMElement btn   Button element to add the action to
97 * @param  array      props Associative array of button properties
98 * @param  string     edid  ID of the editor textarea
99 * @author Gabriel Birke <birke@d-scribe.de>
100 * @author Andreas Gohr <andi@splitbrain.org>
101 */
102function tb_formatln(btn, props, edid) {
103    var sample = props.sample || props.title,
104        opts,
105        selection = DWgetSelection(jQuery('#'+edid)[0]);
106
107    sample = fixtxt(sample);
108    props.open  = fixtxt(props.open);
109    props.close = fixtxt(props.close);
110
111    // is something selected?
112    if(selection.getLength()){
113        sample = selection.getText();
114        opts = {nosel: true};
115    }else{
116        opts = {
117            startofs: props.open.length,
118            endofs: props.close.length
119        };
120    }
121
122    sample = sample.split("\n").join(props.close+"\n"+props.open);
123    sample = props.open+sample+props.close;
124
125    pasteText(selection,sample,opts);
126
127    pickerClose();
128    return false;
129}
130
131/**
132 * Button action for insert buttons
133 *
134 * @param  DOMElement btn   Button element to add the action to
135 * @param  array      props Associative array of button properties
136 * @param  string     edid  ID of the editor textarea
137 * @author Gabriel Birke <birke@d-scribe.de>
138 * @author Andreas Gohr <andi@splitbrain.org>
139 */
140function tb_insert(btn, props, edid) {
141    insertAtCarret(edid,fixtxt(props.insert));
142    pickerClose();
143    return false;
144}
145
146/**
147 * Button action for the media popup
148 *
149 * @param  DOMElement btn   Button element to add the action to
150 * @param  array      props Associative array of button properties
151 * @param  string     edid  ID of the editor textarea
152 * @author Andreas Gohr <andi@splitbrain.org>
153 */
154function tb_mediapopup(btn, props, edid) {
155    window.open(
156        DOKU_BASE+props.url+encodeURIComponent(NS)+'&edid='+encodeURIComponent(edid),
157        props.name,
158        props.options);
159    return false;
160}
161
162/**
163 * Button action for automatic headlines
164 *
165 * Insert a new headline based on the current section level
166 *
167 * @param  DOMElement btn   Button element to add the action to
168 * @param  array      props Associative array of button properties
169 * @param  string     edid  ID of the editor textarea
170 * @author Andreas Gohr <andi@splitbrain.org>
171 */
172function tb_autohead(btn, props, edid){
173    var lvl = currentHeadlineLevel(edid),
174        tags;
175
176    // determine new level
177    lvl += props.mod;
178    if(lvl < 1) lvl = 1;
179    if(lvl > 5) lvl = 5;
180
181    tags = (new Array(8 - lvl)).join('=');
182    insertTags(edid, tags+' ', ' '+tags+"\n", props.text);
183    pickerClose();
184    return false;
185}
186
187
188/**
189 * Add button action for picker buttons and create picker element
190 *
191 * @param  jQuery      btn   Button element to add the action to
192 * @param  array      props Associative array of button properties
193 * @param  string     edid  ID of the editor textarea
194 * @return boolean    If button should be appended
195 * @author Gabriel Birke <birke@d-scribe.de>
196 */
197function addBtnActionPicker($btn, props, edid) {
198    var pickerid = 'picker'+(pickercounter++);
199    var picker = createPicker(pickerid, props, edid);
200    jQuery(picker).attr('aria-hidden', 'true');
201
202    $btn.click(
203        function(e) {
204            pickerToggle(pickerid,$btn);
205            e.preventDefault();
206            return '';
207        }
208    );
209
210    return pickerid;
211}
212
213/**
214 * Add button action for the link wizard button
215 *
216 * @param  DOMElement btn   Button element to add the action to
217 * @param  array      props Associative array of button properties
218 * @param  string     edid  ID of the editor textarea
219 * @return boolean    If button should be appended
220 * @author Andreas Gohr <gohr@cosmocode.de>
221 */
222function addBtnActionLinkwiz($btn, props, edid) {
223    dw_linkwiz.init(jQuery('#'+edid));
224    jQuery($btn).click(function(e){
225        dw_linkwiz.val = props;
226        dw_linkwiz.toggle();
227        e.preventDefault();
228        return '';
229    });
230    return 'link__wiz';
231}
232
233
234/**
235 * Show/Hide a previously created picker window
236 *
237 * @author Andreas Gohr <andi@splitbrain.org>
238 */
239function pickerToggle(pickerid,$btn){
240    var $picker = jQuery('#' + pickerid),
241        pos = $btn.offset();
242    if ($picker.hasClass('a11y')) {
243        $picker.removeClass('a11y').attr('aria-hidden', 'false');
244    } else {
245        $picker.addClass('a11y').attr('aria-hidden', 'true');
246    }
247    var picker_left = pos.left + 3,
248        picker_width = $picker.width(),
249        window_width = jQuery(window).width();
250    if (picker_width > 300) {
251        $picker.css("max-width", "300");
252        picker_width = 300;
253    }
254    if ((picker_left + picker_width + 40) > window_width) {
255        picker_left = window_width - picker_width - 40;
256    }
257    if (picker_left < 0) {
258        picker_left = 0;
259    }
260    $picker.offset({left: picker_left, top: pos.top+$btn[0].offsetHeight+3});
261}
262
263/**
264 * Close all open pickers
265 *
266 * @author Andreas Gohr <andi@splitbrain.org>
267 */
268function pickerClose(){
269    jQuery('.picker').addClass('a11y').attr('aria-hidden', 'true');
270}
271
272
273/**
274 * Replaces \n with linebreaks
275 */
276function fixtxt(str){
277    return str.replace(/\\n/g,"\n");
278}
279
280jQuery(function () {
281    initToolbar('tool__bar','wiki__text',toolbar);
282    jQuery('#tool__bar').attr('role', 'toolbar');
283});
284