xref: /dokuwiki/lib/scripts/page.js (revision 28c7c067399b7a0c1844ca0f7d46d260b632ec08)
1/**
2 * Page behaviours
3 *
4 * This class adds various behaviours to the rendered page
5 */
6dw_page = {
7    /**
8     * initialize page behaviours
9     */
10    init: function(){
11        dw_page.sectionHighlight();
12        jQuery('a.fn_top').mouseover(dw_page.footnoteDisplay);
13        dw_page.makeToggle('#dw__toc h3','#dw__toc > div');
14    },
15
16    /**
17     * Highlight the section when hovering over the appropriate section edit button
18     *
19     * @author Andreas Gohr <andi@splitbrain.org>
20     */
21    sectionHighlight: function() {
22        jQuery('form.btn_secedit')
23            .mouseover(function(){
24                var $tgt = jQuery(this).parent(),
25                    nr = $tgt.attr('class').match(/(\s+|^)editbutton_(\d+)(\s+|$)/)[2];
26
27                // Walk the DOM tree up (first previous siblings, then parents)
28                // until boundary element
29                while($tgt.length > 0 && !$tgt.hasClass('sectionedit' + nr)) {
30                    // go down when the sectionedit begin marker is below $tgt
31                    if ($tgt.find('.sectionedit' + nr).length > 0) {
32                        $tgt = $tgt.children().last();
33                    } else {
34                        // $.last gives the DOM-ordered last element:
35                        // prev if present, else parent.
36                        $tgt = $tgt.prev().add($tgt.parent()).last();
37                    }
38                    $tgt.addClass('section_highlight');
39                }
40            })
41            .mouseout(function(){
42                jQuery('.section_highlight').removeClass('section_highlight');
43            });
44    },
45
46    /**
47     * Create/get a insitu popup used by the footnotes
48     *
49     * @param target - the DOM element at which the popup should be aligned at
50     * @param popup_id - the ID of the (new) DOM popup
51     * @return the Popup jQuery object
52     */
53    insituPopup: function(target, popup_id) {
54        // get or create the popup div
55        var $fndiv = jQuery('#' + popup_id);
56
57        // popup doesn't exist, yet -> create it
58        if($fndiv.length === 0){
59            $fndiv = jQuery(document.createElement('div'))
60                .attr('id', popup_id)
61                .addClass('insitu-footnote JSpopup')
62                .mouseleave(function () {jQuery(this).hide();});
63            jQuery('.dokuwiki:first').append($fndiv);
64        }
65
66        // position() does not support hidden elements
67        $fndiv.show().position({
68            my: 'left top',
69            at: 'left center',
70            of: target
71        }).hide();
72
73        return $fndiv;
74    },
75
76    /**
77     * Display an insitu footnote popup
78     *
79     * @author Andreas Gohr <andi@splitbrain.org>
80     * @author Chris Smith <chris@jalakai.co.uk>
81     */
82    footnoteDisplay: function () {
83        var content = jQuery(jQuery(this).attr('href')) // Footnote text anchor
84                      .closest('div.fn').html();
85
86        if (content === null){
87            return;
88        }
89
90        // strip the leading content anchors and their comma separators
91        content = content.replace(/((^|\s*,\s*)<sup>.*?<\/sup>)+\s*/gi, '');
92
93        // prefix ids on any elements with "insitu__" to ensure they remain unique
94        content = content.replace(/\bid=(['"])([^"']+)\1/gi,'id="insitu__$2');
95
96        // now put the content into the wrapper
97        dw_page.insituPopup(this, 'insitu__fn').html(content).show();
98    },
99
100    /**
101     * Makes an element foldable by clicking its handle
102     *
103     * This is used for the TOC toggling, but can be used for other elements
104     * as well. A state indicator is inserted into the handle and can be styled
105     * by CSS.
106     *
107     * @param selector handle What should be clicked to toggle
108     * @param selector content This element will be toggled
109     */
110    makeToggle: function(handle, content, state){
111        var $handle, $content, $clicky, $child, setClicky;
112        $handle = jQuery(handle);
113        if(!$handle.length) return;
114        $content = jQuery(content);
115        if(!$content.length) return;
116
117        // we animate the children
118        $child = $content.children();
119
120        // class/display toggling
121        setClicky = function(hiding){
122            if(hiding){
123                $clicky.html('<span>+</span>');
124                $handle.addClass('closed');
125                $handle.removeClass('open');
126            }else{
127                $clicky.html('<span>−</span>');
128                $handle.addClass('open');
129                $handle.removeClass('closed');
130            }
131        };
132
133        $handle[0].setState = function(state){
134            var hidden;
135            if(!state) state = 1;
136
137            // Assert that content instantly takes the whole space
138            $content.css('min-height', $content.height()).show();
139
140            // stop any running animation
141            $child.stop(true, true);
142
143            // was a state given or do we toggle?
144            if(state === -1) {
145                hidden = false;
146            } else if(state === 1) {
147                hidden = true;
148            } else {
149                hidden = $child.is(':hidden');
150            }
151
152            // update the state
153            setClicky(!hidden);
154
155            // Start animation and assure that $toc is hidden/visible
156            $child.dw_toggle(hidden, function () {
157                $content.toggle(hidden);
158                $content.css('min-height',''); // remove min-height again
159            });
160        };
161
162        // the state indicator
163        $clicky = jQuery(document.createElement('strong'));
164
165        // click function
166        $handle.css('cursor','pointer')
167               .click($handle[0].setState)
168               .prepend($clicky);
169
170        // initial state
171        $handle[0].setState(state);
172    }
173};
174
175jQuery(dw_page.init);
176