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