Jump to content

User:Epicgenius/capitalize.js

From Wikipedia, the free encyclopedia
Note: After saving, you have to bypass your browser's cache to see the changes. Google Chrome, Firefox, Microsoft Edge and Safari: Hold down the ⇧ Shift key and click the Reload toolbar button. For details and instructions about other browsers, see Wikipedia:Bypass your cache.
mw.loader.using("mediawiki.util", function () {
    // Only run script if user is editing an article
    if (!document.forms.editform || (mw.config.get("wgAction") !== "edit" && mw.config.get("wgAction") !== "submit")) {
        return;
    }
(function () {
    'use strict';
 
	// List of words to remain lowercased in title case mode
        const smallWords = new Set([
            'a',
            'an',
            'and',
            'as',
            'at',
            'but',
            'by',
            'for',
            'in',
            'nor',
            'of',
            'on',
            'or',
            'the',
            'to',
            'up',
            'via',
            'with'
        ]);
 
	// List of acronyms to remain uppercased in sentence,
	// title, and capitalized case modes. 
	// I might add proper nouns later, too.
        const largeWords = new Set([
            // 'US$',
            // 'CA$',
            // 'NZ$',
            'ASAP',
            'ATM',
            'CEO',
            'CFO',
            'CIA',
            'COO',
            'DIY',
            'DVD',
            'FAQ',
            'FBI',
            'FEMA',
            'GPS',
            'HTML',
            'HTTP',
            'MD',
            'MI6',
            'MP3',
            'NASA',
            'NATO',
            'OSHA',
            'PDF',
            'PhD',
            'POTUS',
            'SCOTUS',
			'TBA',
			'TBD',
            'URL',
            'USA',
            'USB',
            'VIP',
            'WiFi'
        ]);
 
        // Map of lowercase form -> canonical capitalization, shared
        // by all case-conversion functions below.
        const largeWordsLower = new Map(
            Array.from(largeWords, function (word) {
                return [word.toLowerCase(), word];
            })
        );
 
        // Regex that matches any acronym case-insensitively, used to restore 
        // its capitalization after a lowercase conversion.
        const largeWordsPattern = new RegExp(
            '\\b(' + Array.from(largeWords, function (word) {
                return word.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
            }).join('|') + ')\\b',
            'gi'
        );
 
        // Restore the canonical capitalization of any acronyms
        // found in the given (already case-converted) text.
        function restoreLargeWords(text) {
            return text.replace(largeWordsPattern, function (match) {
                return largeWordsLower.get(match.toLowerCase()) || match;
            });
        }
	
    // Convert text to sentence case.
    // The first alphabetical character after the beginning of the
    // selection, or after . ! ?, is capitalized. Other characters
    // are converted to lowercase. Acronyms keep their defined
    // capitalization regardless of where they appear.
    function sentenceCase(text) {
        text = text.toLowerCase();
 
        let capitalizeNext = true;
 
        text = text.replace(/[A-Za-zÀ-ÖØ-öø-ÿ]/g, function (char) {
            if (capitalizeNext) {
                capitalizeNext = false;
                return char.toUpperCase();
            }
 
            return char;
        }).replace(/([.!?]\s+)([a-zà-öø-ÿ])/g, function (match, punctuation, letter) {
            return punctuation + letter.toUpperCase();
        });
 
        return restoreLargeWords(text);
    }
 
    // Convert text to title case.
    // Small connecting words such as "a", "an", "the", "of",
    // "and", etc. remain lowercase unless they are the first
    // or last word.
    function titleCase(text) {
    
        const words = text.toLowerCase().split(/(\s+)/);
    
        let wordIndex = 0;
        const actualWords = words.filter(function (part) {
            return /\S/.test(part);
        }).length;
    
        return words.map(function (part) {
            // Preserve whitespace exactly as it was.
            if (!/\S/.test(part)) {
                return part;
            }
    
            const lowerWord = part;
            const isFirstWord = wordIndex === 0;
            const isLastWord = wordIndex === actualWords - 1;
    
            wordIndex++;
    
            // Remove punctuation from the beginning/end when
            // determining the actual word.
            const match = lowerWord.match(
                /^([^A-Za-zÀ-ÖØ-öø-ÿ0-9]*)(.*?)([^A-Za-zÀ-ÖØ-öø-ÿ0-9]*)$/
            );
    
            if (!match) {
                return lowerWord;
            }
    
            const prefix = match[1];
            const word = match[2];
            const suffix = match[3];
    
            // Ordinals such as 1st, 2nd, 3rd, 4th, 21st, etc.
            // are kept entirely lowercase.
            if (/^\d+(?:st|nd|rd|th)$/.test(word)) {
                return prefix + word + suffix;
            }
    
            // Preserve acronyms and other defined large words.
            if (largeWordsLower.has(word)) {
                return prefix + largeWordsLower.get(word) + suffix;
            }
    
            if (
                !isFirstWord &&
                !isLastWord &&
                smallWords.has(word)
            ) {
                return prefix + word + suffix;
            }
    
            return (
                prefix +
                word.charAt(0).toUpperCase() +
                word.slice(1) +
                suffix
            );
        }).join('');
    }
    
    
    function capitalizedCase(text) {
    
        const words = text.toLowerCase().split(/(\s+)/);
    
        return words.map(function (part) {
            // Preserve whitespace exactly as it was.
            if (!/\S/.test(part)) {
                return part;
            }
    
            const lowerWord = part;
    
            // Remove punctuation from the beginning/end when
            // determining the actual word.
            const match = lowerWord.match(
                /^([^A-Za-zÀ-ÖØ-öø-ÿ0-9]*)(.*?)([^A-Za-zÀ-ÖØ-öø-ÿ0-9]*)$/
            );
    
            if (!match) {
                return lowerWord;
            }
    
            const prefix = match[1];
            const word = match[2];
            const suffix = match[3];
    
            // Ordinals such as 1st, 2nd, 3rd, 4th, 21st, etc.
            // are kept entirely lowercase.
            if (/^\d+(?:st|nd|rd|th)$/.test(word)) {
                return prefix + word + suffix;
            }
    
            // Preserve acronyms and other defined large words.
            if (largeWordsLower.has(word)) {
                return prefix + largeWordsLower.get(word) + suffix;
            }
    
            return (
                prefix +
                word.charAt(0).toUpperCase() +
                word.slice(1) +
                suffix
            );
        }).join('');
    }
 
 
    // Convert the current selection in Wikipedia's source editor.
    function convertSelection(mode) {
        const textArea = document.getElementById('wpTextbox1');
 
        if (!textArea) {
            return;
        }
 
        const start = textArea.selectionStart;
        const end = textArea.selectionEnd;
 
        // Nothing has been selected.
        if (start === end) {
            return;
        }
 
        // Get the selected text.
        const selectedText = textArea.value.substring(start, end);
 
        let convertedText;
 
        switch (mode) {
            case 'upper':
                convertedText = selectedText.toUpperCase();
                break;
 
            case 'lower':
                convertedText = selectedText.toLowerCase();
                break;
 
            case 'sentence':
                convertedText = sentenceCase(selectedText);
                break;
 
            case 'title':
                convertedText = titleCase(selectedText);
                break;
 
            case 'capitalized':
                convertedText = capitalizedCase(selectedText);
                break;

            default:
                return;
        }
 
        // Replace the selection with the converted text.
        //
        // "select" keeps the newly converted text selected.
        textArea.setRangeText(
            convertedText,
            start,
            end,
            'select'
        );
 
        // Return focus to the editing field.
        textArea.focus();
    }
 
    // Add a link to the sidebar.
    function addLink(id, label, tooltip, mode) {
        const link = mw.util.addPortletLink(
            'p-tb',
            '#',
            label,
            id,
            tooltip
        );
 
        if (!link) {
            return;
        }
 
        link.addEventListener('click', function (event) {
            event.preventDefault();
            convertSelection(mode);
        });
    }
 
    // Create the sidebar links.
    function initialize() {
        addLink(
            'case-converter-uppercase',
            'To UPPERCASE',
            'Convert the selected text to uppercase',
            'upper'
        );
 
        addLink(
            'case-converter-lowercase',
            'To lowercase',
            'Convert the selected text to lowercase',
            'lower'
        );
 
        addLink(
            'case-converter-sentence',
            'To Sentence case',
            'Convert the selected text to sentence case',
            'sentence'
        );
 
        addLink(
            'case-converter-title',
            'To Title Case',
            'Convert the selected text to title case',
            'title'
        );

        addLink(
            'case-converter-capitalized',
            'To Capitalized Case',
            'Convert the selected text to capitalized case',
            'capitalized'
        );
    }
 
    // Wait until MediaWiki's interface is ready.
    $(initialize);
 
})();
});