1/*
2 * Copy2clipboard - copy <pre> text to clipboard.
3 * Copyright (C) 2020, 2021 Schplurtz le Déboulonné <Schplurtz@laposte.net>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the CECILL 2.1 free license. See files
7 * LICENSE and LICENSE-fr for the details in the distribution directory or
8 * http://cecill.info/licences/Licence_CeCILL_V2.1-en.html
9 */
10jQuery(function() {
11  if(!navigator.clipboard)
12    return;
13  // messageBox( 'id', 'text' ); flash a message at top of screen
14  var messageBox=function( id, txt ) {
15    const body=document.getElementsByTagName('body')[0];
16    const msg=document.createElement('div');
17    msg.setAttribute('id', id );
18    msg.classList.add('cp2clipmsg');
19    const content = document.createTextNode(txt);
20    msg.appendChild(content);
21    body.appendChild(msg);
22    window.setTimeout(function() {
23        jQuery("#"+id).fadeTo(500, 0).slideUp(500, function(){
24            jQuery(this).remove();
25        });
26    }, 1500);
27  };
28  // true on MS windows. used to set EOL
29  var iswin = (navigator.appVersion.indexOf("Win") != -1);
30  // The async function that respond to click event
31  var response=async function(event) {
32    try {
33      let text='';
34      // when line numbers are on, geshi uses <li> tag for each line
35      let lis=event.target.previousSibling.getElementsByTagName('li');
36      if( lis.length ) {
37        for( let li of lis ) {
38          text += li.textContent + '\n';
39        }
40      }
41      // no line numbers, whole text is directely in <pre> tag
42      else {
43        text = event.target.previousSibling.textContent;
44        text = text.replace( /\r\n/g, '\n' ); // can happen if page files are prepared on win and dropped in doku tree...
45      }
46      // Why replace \u00A0 ??? geshi adds an NBSP on each empty line. This is an issue
47      // with python, perl... when you want to run copied code, you get a
48      // syntax error "unexpected \xC2 character" or similar... So remove this
49      // crap. And yes it could remove a legitimate NBSP ; chances are low though.
50      text = text.replace(/^\u00A0$/gm, "");
51      // if you paste \n separated lines with right button in powershell, the lines are
52      // fed in reverse order ! Most stupidly funny bug by MS ever. Anyway, just make sure
53      // we use \r\n separated lines under windows. It just makes sense.
54      // see powershell bugs https://github.com/PowerShell/PowerShell/issues/3816 and
55      // https://github.com/PowerShell/PSReadLine/issues/496 or
56      // https://github.com/PowerShell/PSReadLine/issues/579 , they're all the same...
57      if( iswin ) {
58        text=text.replace(/\n/g, '\r\n' );
59      }
60      await navigator.clipboard.writeText(text);
61      messageBox('cp2clipok', LANG.plugins.copy2clipboard.copied);
62    } catch (err) {
63      messageBox('cp2clipnok', LANG.plugins.copy2clipboard.error);
64    }
65  };
66
67  // iterate over all <pre> node and create the needed structure.
68  // <pre>...</pre> ==> <div class="cp2clipcont"><pre>...</pre><button /></div>
69  let sup='desktop';
70  if(/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent))
71    sup='mobile';
72  let classes=['cp2clipcont', sup];
73  document.querySelectorAll('pre.code,pre.file').forEach(function(elem) {
74    // wrap current node in a div. See https://stackoverflow.com/a/46595686/1831273
75    let container=document.createElement('div');
76    container.classList.add(...classes);
77    elem.parentNode.insertBefore(container, elem);
78    elem.previousElementSibling.appendChild(elem);
79
80    let cpbutton = document.createElement('button');
81    cpbutton.setAttribute( 'title', LANG.plugins.copy2clipboard.title);
82    // In order to maintain vertical alignment use the margin-top of the <pre>
83    // elem for the container and set the <pre> elem margin-top to 0.
84    let marginTop=window.getComputedStyle(elem)['margin-top'];
85    if( marginTop != "0px" ) {
86      container.style['margin-top'] = marginTop;
87      elem.style['margin-top']=0;
88    }
89    // Do the same for margin-bottom.
90    let marginBottom=window.getComputedStyle(elem)['margin-bottom'];
91    if( marginBottom != "0px" ) {
92      container.style['margin-bottom'] = marginBottom;
93      elem.style['margin-bottom']=0;
94    }
95    container.appendChild(cpbutton);
96    cpbutton.addEventListener('click', response);
97  })
98});
99
100