/* CodeSelect Gadget - JS Initialisation, Setup, Events. Activates all .code-select fields on the site. By clicking the icon the code is copied to clipboard and tooltip is changed See detailed documentation in Dev/mediawiki deferrable:NO -- Because other scripts are dependent on it */ (function () { // -------- // Settings var targetPadding = 5; // only relevant for use with target. Distance from target borders right and top var defaultLang = 'bash'; // other option: 'none'. Or languages which are supported for highlighting (see documentation) // Additional function names that should also be highlighted for bash (currently outsourced to MediaWiki:CodeSelectHighlightList) var highlightBashAdditionalFunctionNames = window.mwDev ? window.mwDev.data.app.codeSelectHighlightBashAdditionalFunctionNames : []; // ------ // Global var innerContent = $( ` Click = Copy Copied to clipboard! `); var cbuttonIcons = { normal: 'fa-regular fa-clone fa-rotate-90', copied: 'fa-solid fa-check' }; var highlightLangBashIsExtended = false; function extendHighlightLangBash() { if( ! highlightLangBashIsExtended ) { // Extend language bash with extra keywords let bashFnPattern = Prism.languages.bash.function.pattern; // We're using apt as a fixpoint, because it's very common and it's surrounded by pipes | let newBashFnPattern = new RegExp( bashFnPattern.source.replace( '|apt|', '|' + ['apt', ...highlightBashAdditionalFunctionNames].join('|') + '|' ), bashFnPattern.flags ); Prism.languages.bash = Prism.languages.extend( 'bash', { 'function': { lookbehind: true, pattern: newBashFnPattern }} ); highlightLangBashIsExtended = true; } } function markSelection( jqDom ) { let selection = window.getSelection(); selection.removeAllRanges(); let range = document.createRange(); range.selectNodeContents( jqDom[0] ); selection.addRange(range); } // ---------------- // jQuery Extension $.fn.codeSelect = function( action ) { // Only allow 'init' at the moment (extendable later) if( action != 'init' ) return; $(this).each( function() { // Prevent double initialization if( $(this).hasClass('js-fully-loaded') ) return; // Setup const codeSelect = $(this); const htmlMode = codeSelect.hasClass('insert-mode-html'); let content = codeSelect[ htmlMode ? 'html' : 'text' ](); codeSelect .empty() .append( innerContent.clone() ) .find('.code')[ htmlMode ? 'html' : 'text' ]( content ); let target = codeSelect.attr('data-target'); if( target && $(target).length ) { target = $(target).eq(0); // If we have a target and no content (only white space) was given, copy target's content if( ! content.match(/\S/) ) codeSelect.find('.code').text( target.text() ); let helper = $('
'); helper.append( codeSelect ); // Position over target codeSelect.css( { position: 'absolute', top: targetPadding - target.outerHeight() - ( parseInt( target.css('marginBottom') ) || 0 ), right: targetPadding, }); helper.insertAfter( target ); // Fixate styles from the target to prevent content shift let targetStyles = window.getComputedStyle( target[0] ); let getStyle = (name) => targetStyles.getPropertyValue(name); target.css( { margin: getStyle('margin'), lineHeight: getStyle('line-height'), padding: getStyle('padding'), fontSize: getStyle('font-size') } ); if( ! codeSelect.attr('data-button-image-src' ) ) codeSelect.attr('data-button-image-src',''); } else target = null; let imageButton = false; let imageSrc = codeSelect.attr('data-button-image-src'); if( imageSrc && imageSrc.match(/\S/) ) { $(`