[IMP] ws doc: affix language switcher to page top
[odoo/odoo.git] / doc / _themes / odoodoc / static / app.js
1 $(function () {
2     var $body = $(document.body);
3     $body.scrollspy({ target: '.sphinxsidebarwrapper' });
4     $(window).on('load', function () {
5         $body.scrollspy('refresh');
6     });
7
8     // Sidenav affixing
9     setTimeout(function () {
10         var $sideBar = $('.sphinxsidebarwrapper');
11
12         $sideBar.affix({
13             offset: {
14                 top: function () {
15                     var offsetTop = $sideBar.offset().top;
16                     var sideBarMargin = parseInt($sideBar.children(0).css('margin-top'), 10);
17                     var navOuterHeight = $('.docs-nav').height();
18
19                     return (this.top = offsetTop - navOuterHeight - sideBarMargin);
20                 },
21                 bottom: function () {
22                     return (this.bottom = $('div.footer').outerHeight(true));
23                 }
24             }
25         });
26     }, 100);
27
28     /*
29     for clipboard:
30     * add per-language setup code to document, hidden
31     * adds button to each switchable language block except when they're setup
32       stuff because fuck'em
33     * per-language, add clipboard hook to prefix with setup bit on-copy
34     * setup bit is... ?
35     * actually not all blocks because we don't want to add the setup bits to
36       the setup bits, so that's kinda shit
37      */
38
39     document.addEventListener('copy', copyCode);
40
41     ZeroClipboard.config({
42         swfPath: '../_static/zeroclipboard-2.1.6/ZeroClipboard.swf',
43         flashLoadTimeout: 3e3,
44     });
45     var zc = new ZeroClipboard();
46     zc.on('ready', function () {
47         var $highlighted = $('.switchable:not(.setup) .highlight').addClass('with-btn-clipboard');
48         var $clipboard_buttons =
49             $('<button type="button" class="btn-clipboard">Copy</button>')
50             .on('transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd', function () {
51                 $(this).removeClass('active');
52             })
53             .prependTo($highlighted);
54         zc.clip($clipboard_buttons);
55     });
56     zc.on('copy', function (e) {
57         // yellow flash
58         $(e.target).addClass('active');
59         copyCode(e);
60     });
61
62     // stripe page stuff
63     if ($('div.document-super').hasClass('stripe')) { (function () {
64         // iterate on highlighted PL blocks (but not results because that'd
65         // be gross), extract all switchable PLs in the document and add
66         // clipboard-copy buttons
67         var languages = {};
68         $('div.switchable').each(function () {
69             var language = getHighlightLanguage(this);
70             if (language) {
71                 languages[language] = true;
72             }
73         });
74
75         // if can't find CSS where base rule lives something's probably
76         // broken, bail
77         var sheet = findSheet(/style\.css$/);
78         if (!sheet) { return; }
79         // build PL switcher UI and hook toggle event
80         var $switcher = $(buildSwitcher(Object.keys(languages)))
81             .prependTo('div.documentwrapper')
82             .on('click', 'li', function (e) {
83                 $(e.target).addClass('active')
84                     .siblings().removeClass('active');
85                 var id = e.target.textContent;
86                 var lastIndex = sheet.cssRules.length - 1;
87                 var content = sheet.cssRules[lastIndex].style.cssText;
88                 // change rule in CSS because why not (also can add new
89                 // languages without having to e.g. change CSS or anything)
90                 var sel = [
91                     '.stripe .only-', id, ', ',
92                     '.stripe .highlight-', id, ' > .highlight'
93                 ].join('');
94                 sheet.deleteRule(lastIndex);
95                 sheet.insertRule(sel + '{' + content + '}', lastIndex);
96             });
97         $switcher.affix();
98     })(); }
99
100
101     function copyCode(e) {
102         // works for both C-c and "Copy" button if copy button is injected
103         // inside highlighted code section
104         var target = $(e.target).closest('.switchable:not(.setup)').get(0);
105         // not in a switchable
106         if (!target) { return; }
107         var lang = getHighlightLanguage(target);
108         if (!lang) {
109             // switchable without highlight (e.g. language-specific notes),
110             // don't munge
111             return;
112         }
113
114         // get generic setup code
115         var setup_selector = '.setupcode.highlight-' + lang + ' pre';
116         var setup = document.querySelector(setup_selector).textContent;
117
118         // prepend setup code to current snippet, get all of current snippet
119         // in case only part of it was selected. Ensure we don't get e.g.
120         // button text around snippet itself
121         var data = setup + '\n' + target.querySelector('pre').textContent;
122         // sane browsers & ZeroClipboard
123         e.clipboardData.setData('text/plain', data);
124         // MSIE
125         e.clipboardData.setData('Text', data);
126
127         // no preventDefault on ZC event
128         e.preventDefault && e.preventDefault();
129     }
130     /**
131      * @param {Node} node highlight node to get the language of
132      * @returns {String|null} either the highlight language or null
133      */
134     function getHighlightLanguage(node) {
135         var classes = node.className.split(/\s+/);
136         for (var i = 0; i < classes.length; ++i) {
137             var cls = classes[i];
138             if (/^highlight-/.test(cls)) {
139                 return cls.slice(10);
140             }
141         }
142         return null;
143     }
144     // programming language switcher
145     function findSheet(pattern, fromSheet) {
146         if (fromSheet) {
147             for(var i=0; i<fromSheet.cssRules.length; ++i) {
148                 var rule = fromSheet.cssRules[i];
149                 if (rule.type !== CSSRule.IMPORT_RULE) { continue; }
150                 if (pattern.test(rule.href)) {
151                     return rule.styleSheet;
152                 }
153             }
154             return null;
155         }
156         var sheets = document.styleSheets;
157         for(var j=0; j<sheets.length; ++j) {
158             var sheet = sheets[j];
159             if (pattern.test(sheet.href)) {
160                 return sheet;
161             }
162             var subSheet;
163             if (subSheet = findSheet(pattern, sheet)) {
164                 return subSheet;
165             }
166         }
167         return null;
168     }
169     function buildSwitcher(languages) {
170         var root = document.createElement('ul');
171         root.className = "switcher";
172         for(var i=0; i<languages.length; ++i) {
173             var item = document.createElement('li');
174             item.textContent = languages[i];
175             if (i === 0) {
176                 item.className = "active";
177             }
178             root.appendChild(item);
179         }
180         return root;
181     }
182 });