User:Polygnotus/Scripts/WikiTextExpander.js
Appearance
From Wikipedia, the free encyclopedia
Code that you insert on this page could contain malicious content capable of compromising your account. If you import a script from another page with "importScript", "mw.loader.load", "iusc", or "lusc", take note that this causes you to dynamically load a remote script, which could be changed by others. Editors are responsible for all edits and actions they perform, including by scripts. User scripts are not centrally supported and may malfunction or become inoperable due to software changes. A guide to help you find broken scripts is available. If you are unsure whether code you are adding to this page is safe, you can ask at the appropriate village pump.
This code will be executed when previewing this page.
This code will be executed when previewing this page.
This user script seems to have a documentation page at User:Polygnotus/Scripts/WikiTextExpander.
// WikiTextExpander // This script allows you to expand acronyms and shorthand phrases using a configurable hotkey // - Acronyms with colons (e.g. "WP:COI" and "[[WP:COI]]") are expanded as wiki links [[WP:COI|the conflict of interest guideline]] // - Regular phrases are expanded without wiki links // Default configuration vartextExpanderConfig={ // Define your acronyms and phrases with their expansions here expansionMap:{ // Wiki acronyms (will be expanded with [[ ]] format) "WP:COI":"the conflict of interest guideline", "WP:NPOV":"the neutral point of view policy", "WP:RS":"the reliable sources guideline", "WP:V":"the verifiability policy", "WP:NOR":"the no original research policy", "WP:BLP":"the biographies of living persons policy", "WP:CITE":"the citation needed guideline", "WP:N":"the notability guideline", "MOS:LAYOUT":"the layout guideline", "WP:TALK":"the talk page guideline", // Regular phrases (will be expanded without wiki formatting) "dupe":"This appears to be a duplicate of a previous submission. Please check the existing entries before submitting.", "notref":"This is not a reliable reference according to our guidelines. Please provide a source that meets our reliability criteria.", "format":"Please format your submission according to our style guide before resubmitting.", "thanks":"Thank you for your contribution. I've reviewed it and made some minor edits for clarity.", "sorry":"I apologize for the confusion. Let me clarify what I meant in my previous comment." // Add more phrases as needed }, // Default hotkey configuration: Ctrl+Shift+Z hotkey:{ ctrlKey:true, shiftKey:true, altKey:false, key:'z' } }; // Try to load user configuration from localStorage if it exists try{ varsavedConfig=localStorage.getItem('textExpanderConfig'); if(savedConfig){ varparsedConfig=JSON.parse(savedConfig); // Merge saved configuration with defaults if(parsedConfig.expansionMap){ textExpanderConfig.expansionMap=parsedConfig.expansionMap; } if(parsedConfig.hotkey){ textExpanderConfig.hotkey=parsedConfig.hotkey; } } }catch(e){ console.error('Error loading text expander config:',e); } // Function to save the configuration functionsaveTextExpanderConfig(){ try{ localStorage.setItem('textExpanderConfig',JSON.stringify(textExpanderConfig)); }catch(e){ console.error('Error saving text expander config:',e); } } // Function to create a regular expression pattern for all expandable text functiongetExpansionRegex(){ varescapedKeys=Object.keys(textExpanderConfig.expansionMap).map(function(key){ returnkey.replace(/[.*+?^${}()|[\]\\]/g,'\\$&');// Escape special characters }); // Pattern to match both plain text and those inside wiki brackets returnnewRegExp( '(?<!\\[)\\b('+escapedKeys.join('|')+')\\b(?!\\])'+'|'+ '\\[\\[('+escapedKeys.join('|')+')(?:\\|[^\\]]*?)?\\]\\]', 'g' ); } // Function to determine if a key should be formatted as a wiki link functionshouldFormatAsWikiLink(key){ returnkey.indexOf(':')>-1; } // Function to expand all text in the selected text functionexpandAllText(){ // Get the active editor input element varactiveElement=document.activeElement; // Check if we're in an editable field if(activeElement&&( activeElement.isContentEditable|| activeElement.tagName==='TEXTAREA'|| (activeElement.tagName==='INPUT'&&activeElement.type==='text') )){ varselectedText=''; varexpandedCount=0; // Handle different editor types if(activeElement.isContentEditable){ // Visual editor varselection=window.getSelection(); if(selection.rangeCount>0){ varrange=selection.getRangeAt(0); selectedText=selection.toString(); // Only proceed if there's selected text if(selectedText){ // Create a document fragment for the new content varnewContent=selectedText; varexpansionRegex=getExpansionRegex(); // Replace all expandable text in the selected text newContent=newContent.replace(expansionRegex,function(match,plainText,bracketedText){ expandedCount++; if(plainText){ // This is plain text varexpansion=textExpanderConfig.expansionMap[plainText]; if(shouldFormatAsWikiLink(plainText)){ // Format as wiki link return'[['+plainText+'|'+expansion+']]'; }else{ // Just replace with the expansion returnexpansion; } }elseif(bracketedText){ // This is already in brackets if(match.indexOf('|')>-1){ // Already has a pipe, don't modify returnmatch; }else{ // Add the expansion varexpansion=textExpanderConfig.expansionMap[bracketedText]; return'[['+bracketedText+'|'+expansion+']]'; } } returnmatch; }); // Replace the selected text with the expanded text if(expandedCount>0){ document.execCommand('insertText',false,newContent); returnexpandedCount; } } } }else{ // Source editor (textarea or input) varselStart=activeElement.selectionStart; varselEnd=activeElement.selectionEnd; selectedText=activeElement.value.substring(selStart,selEnd); // Only proceed if there's selected text if(selectedText){ varexpansionRegex=getExpansionRegex(); // Replace all expandable text in the selected text varnewContent=selectedText.replace(expansionRegex,function(match,plainText,bracketedText){ expandedCount++; if(plainText){ // This is plain text varexpansion=textExpanderConfig.expansionMap[plainText]; if(shouldFormatAsWikiLink(plainText)){ // Format as wiki link return'[['+plainText+'|'+expansion+']]'; }else{ // Just replace with the expansion returnexpansion; } }elseif(bracketedText){ // This is already in brackets if(match.indexOf('|')>-1){ // Already has a pipe, don't modify returnmatch; }else{ // Add the expansion varexpansion=textExpanderConfig.expansionMap[bracketedText]; return'[['+bracketedText+'|'+expansion+']]'; } } returnmatch; }); // Replace the selected text with the expanded text if(expandedCount>0){ activeElement.value= activeElement.value.substring(0,selStart)+ newContent+ activeElement.value.substring(selEnd); // Position cursor after the expansion activeElement.setSelectionRange(selStart+newContent.length,selStart+newContent.length); returnexpandedCount; } } } } // If we get here, no expansion happened if(selectedText&&expandedCount===0){ mw.notify('No expandable text found in the selection',{type:'info'}); }elseif(!selectedText){ mw.notify('Please select text to expand',{type:'info'}); } return0; } // Add keydown event listener for the hotkey $(document).on('keydown',function(e){ varconfig=textExpanderConfig.hotkey; if( e.ctrlKey===config.ctrlKey&& e.shiftKey===config.shiftKey&& e.altKey===config.altKey&& e.key.toLowerCase()===config.key.toLowerCase() ){ varexpandedCount=expandAllText(); if(expandedCount>0){ e.preventDefault(); mw.notify('Expanded '+expandedCount+' item'+(expandedCount>1?'s':''),{type:'success'}); } } }); // Create the settings dialog functioncreateSettingsDialog(){ var$dialog=$('<div>') .attr('id','text-settings-dialog') .attr('title','WikiTextExpander Settings') .css({ 'display':'none' }); // Create the dialog content var$content=$('<div>'); // Create tabs var$tabs=$('<div>').addClass('mw-widget-aeTabs'); var$tabList=$('<ul>'); $tabList.append($('<li>').append($('<a>').attr('href','#expansion-tab').text('Expansions'))); $tabList.append($('<li>').append($('<a>').attr('href','#hotkey-tab').text('Hotkey'))); $tabs.append($tabList); // Expansions tab var$expansionTab=$('<div>').attr('id','expansion-tab'); $expansionTab.append($('<p>').text('Edit your shorthand text and their expansions:')); var$expansionTable=$('<table>').addClass('wikitable').css('width','100%'); // Table header var$tableHeader=$('<tr>'); $tableHeader.append($('<th>').text('Shorthand')); $tableHeader.append($('<th>').text('Expansion')); $tableHeader.append($('<th>').text('Type')); $tableHeader.append($('<th>').text('Actions')); $expansionTable.append($tableHeader); // Add rows for each expansion $.each(textExpanderConfig.expansionMap,function(key,expansion){ addExpansionRow($expansionTable,key,expansion); }); // Add new row button var$addButton=$('<button>') .text('Add New Expansion') .click(function(){ addExpansionRow($expansionTable,'',''); }); // Import/Export area var$importExportArea=$('<div>').css('margin-top','15px'); var$exportButton=$('<button>') .text('Export to JSON') .css('margin-right','10px') .click(function(){ varcurrentMap={}; $expansionTable.find('tr').each(function(index){ if(index===0)return;// Skip header row var$row=$(this); varkey=$row.find('input.shorthand').val(); varexpansion=$row.find('input.expansion').val(); if(key&&expansion){ currentMap[key]=expansion; } }); varjsonData=JSON.stringify(currentMap,null,2); var$textarea=$('<textarea>') .val(jsonData) .css({ 'width':'100%', 'height':'100px', 'margin-top':'10px', 'font-family':'monospace' }); $importExportArea.find('textarea').remove(); $importExportArea.append($textarea); $textarea.select(); }); var$importButton=$('<button>') .text('Import from JSON') .click(function(){ var$textarea=$('<textarea>') .css({ 'width':'100%', 'height':'100px', 'margin-top':'10px', 'font-family':'monospace' }) .attr('placeholder','{"WP:ABC": "example expansion", "thanks": "Thank you for your contribution"}'); var$importConfirm=$('<button>') .text('Process Import') .css('margin-top','5px') .click(function(){ try{ varimportedData=JSON.parse($textarea.val()); // Clear existing rows (except header) $expansionTable.find('tr:gt(0)').remove(); // Add new rows $.each(importedData,function(key,expansion){ addExpansionRow($expansionTable,key,expansion); }); // Remove the import UI $textarea.remove(); $importConfirm.remove(); mw.notify('Expansions imported successfully',{type:'success'}); }catch(e){ mw.notify('Error parsing JSON: '+e.message,{type:'error'}); } }); $importExportArea.find('textarea, button:not(:first-child)').remove(); $importExportArea.append($textarea); $importExportArea.append($importConfirm); }); $importExportArea.append($exportButton); $importExportArea.append($importButton); $expansionTab.append($expansionTable); $expansionTab.append($('<div>').css('margin-top','10px').append($addButton)); $expansionTab.append($importExportArea); // Hotkey tab var$hotkeyTab=$('<div>').attr('id','hotkey-tab'); $hotkeyTab.append($('<p>').text('Configure the hotkey for expanding text:')); var$hotkeyForm=$('<div>').addClass('mw-widget-aeInputs'); // Checkboxes for modifier keys var$modifiers=$('<div>').css('margin-bottom','10px'); var$ctrlLabel=$('<label>').css('margin-right','10px'); var$ctrlCheck=$('<input>').attr('type','checkbox').prop('checked',textExpanderConfig.hotkey.ctrlKey); $ctrlLabel.append($ctrlCheck).append(' Ctrl'); var$shiftLabel=$('<label>').css('margin-right','10px'); var$shiftCheck=$('<input>').attr('type','checkbox').prop('checked',textExpanderConfig.hotkey.shiftKey); $shiftLabel.append($shiftCheck).append(' Shift'); var$altLabel=$('<label>').css('margin-right','10px'); var$altCheck=$('<input>').attr('type','checkbox').prop('checked',textExpanderConfig.hotkey.altKey); $altLabel.append($altCheck).append(' Alt'); $modifiers.append($ctrlLabel).append($shiftLabel).append($altLabel); // Key input var$keyLabel=$('<label>').css('display','block').css('margin-bottom','5px').text('Key:'); var$keyInput=$('<input>') .attr('type','text') .css('width','50px') .val(textExpanderConfig.hotkey.key) .on('keydown',function(e){ e.preventDefault(); $(this).val(e.key.toLowerCase()); }); $hotkeyForm.append($modifiers); $hotkeyForm.append($keyLabel); $hotkeyForm.append($keyInput); // Current hotkey display var$currentHotkey=$('<div>').css('margin-top','15px'); functionupdateCurrentHotkey(){ varhotkeyText=[]; if($ctrlCheck.prop('checked'))hotkeyText.push('Ctrl'); if($shiftCheck.prop('checked'))hotkeyText.push('Shift'); if($altCheck.prop('checked'))hotkeyText.push('Alt'); hotkeyText.push($keyInput.val().toUpperCase()); $currentHotkey.html('<strong>Current Hotkey:</strong> '+hotkeyText.join('+')); } // Update on any change $ctrlCheck.on('change',updateCurrentHotkey); $shiftCheck.on('change',updateCurrentHotkey); $altCheck.on('change',updateCurrentHotkey); $keyInput.on('input',updateCurrentHotkey); updateCurrentHotkey();// Initial update $hotkeyTab.append($hotkeyForm); $hotkeyTab.append($currentHotkey); // Add the tabs to the content $tabs.append($expansionTab); $tabs.append($hotkeyTab); $content.append($tabs); // Save button var$saveButton=$('<button>') .text('Save Settings') .css('margin-top','15px') .click(function(){ // Save expansions varnewExpansionMap={}; $expansionTable.find('tr').each(function(index){ if(index===0)return;// Skip header row var$row=$(this); varkey=$row.find('input.shorthand').val(); varexpansion=$row.find('input.expansion').val(); if(key&&expansion){ newExpansionMap[key]=expansion; } }); // Save hotkey configuration varnewHotkey={ ctrlKey:$ctrlCheck.prop('checked'), shiftKey:$shiftCheck.prop('checked'), altKey:$altCheck.prop('checked'), key:$keyInput.val().toLowerCase() }; // Update the configuration textExpanderConfig.expansionMap=newExpansionMap; textExpanderConfig.hotkey=newHotkey; // Save to localStorage saveTextExpanderConfig(); // Close the dialog $dialog.dialog('close'); // Notify the user mw.notify('WikiTextExpander settings saved',{type:'success'}); }); $content.append($saveButton); // Append the content to the dialog $dialog.append($content); // Add to the body and initialize as a jQuery UI dialog $('body').append($dialog); $dialog.dialog({ autoOpen:false, width:600, height:500, modal:true, title:'WikiTextExpander settings', close:function(){ // Cleanup the dialog on close $(this).dialog('destroy'); $(this).remove(); } }); // Initialize tabs $tabs.tabs(); return$dialog; } // Function to add a row to the expansions table functionaddExpansionRow($table,key,expansion){ var$row=$('<tr>'); var$keyCell=$('<td>'); var$keyInput=$('<input>') .addClass('shorthand') .attr('type','text') .val(key) .css('width','100%'); $keyCell.append($keyInput); var$expansionCell=$('<td>'); var$expansionInput=$('<input>') .addClass('expansion') .attr('type','text') .val(expansion) .css('width','100%'); $expansionCell.append($expansionInput); var$typeCell=$('<td>').css('text-align','center'); vartypeText=shouldFormatAsWikiLink(key)?'Wiki Link':'Plain Text'; $typeCell.text(typeText); // Update type display when key changes $keyInput.on('input',function(){ varnewKey=$(this).val(); varnewType=shouldFormatAsWikiLink(newKey)?'Wiki Link':'Plain Text'; $typeCell.text(newType); }); var$actionsCell=$('<td>').css('text-align','center'); var$deleteButton=$('<button>') .text('Delete') .click(function(){ $(this).closest('tr').remove(); }); $actionsCell.append($deleteButton); $row.append($keyCell); $row.append($expansionCell); $row.append($typeCell); $row.append($actionsCell); $table.append($row); } // Add the settings item to the "More" menu mw.hook('wikipage.content').add(function(){ // For the modern Vector skin and other skins with a "More" menu if($('#p-cactions').length){ // Make sure we don't add it twice if(!$('#ca-text-expander').length){ var$moreList=$('#p-cactions ul'); var$settingsItem=$('<li>') .attr('id','ca-text-expander') .addClass('mw-list-item mw-list-item-js') .append( $('<a>') .attr('href','#') .text('WikiTextExpander settings') .click(function(e){ e.preventDefault(); createSettingsDialog().dialog('open'); }) ); $moreList.append($settingsItem); } } }); // Add a notification about the hotkey when in edit mode mw.hook('ve.activationComplete').add(function(){ // For Visual Editor varhotkeyText=[]; varconfig=textExpanderConfig.hotkey; if(config.ctrlKey)hotkeyText.push('Ctrl'); if(config.shiftKey)hotkeyText.push('Shift'); if(config.altKey)hotkeyText.push('Alt'); hotkeyText.push(config.key.toUpperCase()); //mw.notify('Text Expander activated. Use ' + hotkeyText.join('+') + ' to expand selected text.', {type: 'info'}); }); // Also show notification in wikitext editor $(document).ready(function(){ if(mw.config.get('wgAction')==='edit'||mw.config.get('wgAction')==='submit'){ varhotkeyText=[]; varconfig=textExpanderConfig.hotkey; if(config.ctrlKey)hotkeyText.push('Ctrl'); if(config.shiftKey)hotkeyText.push('Shift'); if(config.altKey)hotkeyText.push('Alt'); hotkeyText.push(config.key.toUpperCase()); //mw.notify('Text Expander activated. Use ' + hotkeyText.join('+') + ' to expand selected text.', {type: 'info'}); } });