사용자:토끼군/customized.js

위키백과 ― 우리 모두의 백과사전.

참고: 설정을 저장한 후에 바뀐 점을 확인하기 위해서는 브라우저의 캐시를 무시해야 합니다. 모질라 / 파이어폭스 / 사파리: '시프트' 키를 누르면서 '새로고침'을 클릭하거나, Ctrl-F5를 입력; 컨커러: 단순히 '새로고침'을 클릭하거나 F5를 입력; 오페라 사용자는 '도구→설정'에서 캐시를 완전히 비워야 합니다.

<!-- // --> <pre>
/*******************************************************************************
customized javascript for [[사용자:토끼군]].
all scripts here is distributed under MIT license, unless explicitly specified.

USAGE:
1. copy and paste the following lines to [[사용자:(your user name)/monobook.js]].
   you can uncomment oldid argument to url for avoiding problem during development.

document.write('<script type="text/javascript" src="http://ko.wikipedia.org/w/' +
    'index.php?title=User:%ED%86%A0%EB%81%BC%EA%B5%B0/customized.js&' +
    'action=raw&ctype=text/javascript&dontcountme=s' + // '&oldid=(OLDID HERE)' +
    '"></'+'script>');

2. add appropriate activation code ABOVE them.
   it is explained in a comment of each module, but normally like the following:
     $ModuleName = {option1: 'value1', option2: 'value2'};
*******************************************************************************/

////////////////////////////////////////////////////////////////////////////////
// COMMON JAVASCRIPT LIBRARY

// make quoted string like 'asdf\'asdf'
String.prototype.$escape = function() {
    return "'" + this.replace(/'/g, "\\'").replace(/\\n/g, "\\n") + "'";
};

// prefix/suffix test
String.prototype.$prefix = function(s) {
    return (this.substring(0, s.length) == s);
};
String.prototype.$suffix = function(s) {
    return (this.substring(this.length - s.length) == s);
};

//------------------------------------------------------------------------------

// copied from [[en:User:Lupin/popups.js]]
var $$nscanonical = ['Media', 'Special', 'Talk', 'User', 'User talk', 'Wikipedia', 'Wikipedia talk', 'Image', 'Image talk', 'MediaWiki', 'MediaWiki talk', 'Template', 'Template talk', 'Help', 'Help talk', 'Category', 'Category talk', 'Portal', 'Portal talk'];
var $$nslocalized = {
    'de': ['Media', 'Spezial', 'Diskussion', 'Benutzer', 'Benutzer Diskussion', 'Wikipedia', 'Wikipedia Diskussion', 'Bild', 'Bild Diskussion', 'MediaWiki', 'MediaWiki Diskussion', 'Vorlage', 'Vorlage Diskussion', 'Hilfe', 'Hilfe Diskussion', 'Kategorie', 'Kategorie Diskussion', 'Portal', 'Portal Diskussion'],
    'fr': ['Media', 'Special', 'Discuter', 'Utilisateur', 'Discussion Utilisateur', 'Wikipédia', 'Discussion Wikipédia', 'Image', 'Discussion Image', 'MediaWiki', 'Discussion MediaWiki', 'Modèle', 'Discussion Modèle', 'Aide', 'Discussion Aide', 'Catégorie', 'Discussion Catégorie', 'Portail', 'Discussion Portail'],
    'ja': ['Media', '特別', 'ノート', '利用者', '利用者‐会話', 'Wikipedia', 'Wikipedia‐ノート', '画像', '画像‐ノート', 'MediaWiki', 'MediaWiki‐ノート', 'Template', 'Template‐ノート', 'Help', 'Help‐ノート', 'Category', 'Category‐ノート'],
    'ko': ['Media', '특수기능', '토론', '사용자', '사용자토론', '위키백과', '위키백과토론', '그림', '그림토론', 'MediaWiki', 'MediaWiki talk', '틀', '틀토론', '도움말', '도움말토론', '분류', '분류토론'],
};

// returns default language used by given site
function $siteLang(site) {
    // TODO -- guess out language from site name
    var pos = site.lastIndexOf('.');
    return (pos < 0 ? 'en' : site.substring(0, pos));
}

// returns localized namespace prefix for given site
function $nsToPrefix(site, ns) {
    var langlist = $$nslocalized[$siteLang(site)] || $$nscanonical;
    return (ns == 0 ? '' : langlist[ns < 0 ? ns + 2 : ns + 1] + ':');
}

// splits namespace prefix from full pagename
function $splitPrefix(site, pagename) {
    pagename = pagename.replace(/_/g, ' ');
    var nsmap = [-2, -1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17];
    for (var i = 0; i < $$nscanonical.length; ++i) {
        if (pagename.$prefix($$nscanonical[i] + ':')) {
            return [nsmap[i], pagename.substring($$nscanonical[i].length+1)];
        }
    }
    var sitelang = $siteLang(site);
    if (sitelang != 'en') {
        var prefixes = $$nslocalized[sitelang];
        for (var i = 0; i < prefixes.length; ++i) {
            if (pagename.$prefix(prefixes[i] + ':')) {
                return [nsmap[i], pagename.substring(prefixes[i].length+1)];
            }
        }
    }
    return [0, pagename];
}

//------------------------------------------------------------------------------
// $Page class

// constructor
$Page = function(site, pagename) {
    this.site = site;
    this.pagename = pagename;
    this.query = arguments[2] || {};
    this.fragment = arguments[3] || '';
    this._cache = null;
};

$Page.prototype = {
    // get namespace and real page name
    split: function() {
        if (this._cache == null) this._cache = $splitPrefix(this.site, this.pagename);
        return this._cache;
    },

    // make copy of itself except query string
    action: function(action) {
        var query = arguments[1] || {};
        query.action = action;
        return new $Page(this.site, this.pagename, query);
    },

    // make URL from page object
    toURL: function() {
        var pos = this.site.lastIndexOf('.');
        var path;
        if (pos < 0) {
            switch (this.site) {
            case 'meta': path = 'http://meta.wikimedia.org/wiki/'; break;
            case 'commons': path = 'http://commons.wikimedia.org/wiki/'; break;
            case 'sep11': path = 'http://sep11.wikipedia.org/wiki/'; break;
            case 'foundation': path = 'http://wikimediafoundation.org/wiki/'; break;
            case 'mediawiki': path = 'http://mediawiki.org/wiki/'; break;
            case 'source': case 'wikisource': path = 'http://wikisource.org/wiki/'; break;
            case 'species': case 'wikispecies': path = 'http://species.wikimedia.org/wiki/'; break;
            default: return null;
            }
        } else {
            var lang = this.site.substring(0, pos);
            switch (this.site.substring(pos+1)) {
            case 'wp': case 'wikipedia': path = 'http://' + lang + '.wikipedia.org/wiki/'; break;
            case 'wikt': case 'wiktionary': path = 'http://' + lang + '.wiktionary.org/wiki/'; break;
            case 'books': case 'wikibooks': path = 'http://' + lang + '.wikibooks.org/wiki/'; break;
            case 'news': case 'wikinews': path = 'http://' + lang + '.wikinews.org/wiki/'; break;
            case 'quote': case 'wikiquote': path = 'http://' + lang + '.wikiquote.org/wiki/'; break;
            case 'source': case 'wikisource': path = 'http://' + lang + '.wikisource.org/wiki/'; break;
            case 'wikiversity': path = 'http://' + lang + '.wikiversity.org/wiki/'; break;
            default: return null;
            }
        }

        path += encodeURIComponent(this.pagename).replace(/%20/g, '_');
        if (this.query) {
            var delim = '?';
            for (var x in this.query) {
                path += delim + x + '=' + this.query[x];
                delim = '&';
            }
        }
        if (this.fragment) {
            path += '#' + this.fragment;
        }
        return path;
    },
};

// parse given URL into page object
$Page.fromURL = function(url) {
    var pos = url.substring(8).indexOf('/') + 8;
    var hostname = url.substring(0, pos), path = url.substring(pos);
    var site, pagename;
    if (hostname == 'https://secure.wikimedia.org') { // special case for SSL
        var m = path.match(/^\/([a-z]+)\/([a-z-]+)\/(.*)$/);
        if (m == null) return null;
        switch (m[1]) {
        case 'wikipedia':
            site = (m[2] == 'meta' || m[2] == 'commons' || m[2] == 'foundation' || m[2] == 'mediawiki' ? m[2] : m[2] + '.wp');
            break;
        case 'wiktionary': site = m[2] + '.wikt'; break;
        case 'wikibooks': site = m[2] + '.books'; break;
        case 'wikinews': site = m[2] + '.news'; break;
        case 'wikiquote': site = m[2] + '.quote'; break;
        case 'wikisource': site = m[2] + '.source'; break;
        default: return null;
        }
        path = '/' + m[3];
    } else if (hostname == 'http://wikimediafoundation.org') {
        site = 'foundation';
    } else if (hostname == 'http://mediawiki.org') {
        site = 'mediawiki';
    } else {
        var m = hostname.match(/^http:\/\/(?:([a-z-]+)\.)?(wiki(?:media|pedia|books|quote|source|news|versity)|wiktionary)\.org$/);
        if (m == null) return null;
        switch (m[2]) {
        case 'wikimedia': site = m[1]; break;
        case 'wikipedia': site = (m[1] == 'sep11' ? m[1] : m[1] + '.wp'); break;
        case 'wiktionary': site = m[1] + '.wikt'; break;
        case 'wikibooks': site = m[1] + '.books'; break;
        case 'wikinews': site = m[1] + '.news'; break;
        case 'wikiquote': site = m[1] + '.quote'; break;
        case 'wikisource': site = (m[1] ? m[1] + '.source' : 'source'); break;
        case 'wikiversity': site = m[1] + '.wikiversity'; break;
        default: return null;
        }
    }

    var m = path.match(/^(.*?)(?:\?(.*?))?(?:#(.*?))?$/);
    var queries = (m[2] || '').split(/&/), query = {};
    for (var i = 0; i < queries.length; ++i) {
        var pos = queries[i].indexOf('=');
        if (pos >= 0) {
            var key = decodeURIComponent(queries[i].substring(0, pos));
            var value = decodeURIComponent(queries[i].substring(pos+1));
            query[key] = value;
        }
    }
    if (m[1].$prefix('/wiki/')) {
        pagename = decodeURIComponent(m[1].substring(6));
    } else if (m[1] == '/w/index.php') {
        pagename = query.title;
        delete query.title;
    }
    return new $Page(site, pagename.replace(/_/g, ' '), query, decodeURIComponent(m[3] || ''));
};

// current page
$Page.current = $Page.fromURL(document.location.href);

////////////////////////////////////////////////////////////////////////////////
// REDESIGNING EDIT PAGE
// usage: $EditPageRedesign = {chartable: [...]};
// - remove toolbar and character table
// - add new customized character table

if (typeof $EditPageRedesign == 'object') {

var $EditPageRedesign = {
    /* chartable: customizable character table.
     *
     * each entry consists of:
     *   - accesskey (optional), normally inputed with alt
     *     one of: 1234567890~`!@#$%^&*()-_\|[]{};:'"<>/?
     *   - link text, which will be displayed
     *   - replacement (text or [open, close] array), or a function returning it (or null)
     *     it also could be object like {text: REPLACEMENT, deftext: DEFAULT VALUE,
     *                                   prompt: PROMPT TEXT, mark: MARK (default '$')}
     */
    label: $EditPageRedesign.label || '특수 문자 입력:',
    chartable: $EditPageRedesign.chartable || [
        ['', '·', '·'],
        ['', '…', '…'],
        ['', '〈〉', ['〈', '〉']],
        ['', '《》', ['《', '》']],
        ['', '‘’', ['‘', '’']],
        ['', '“”', ['“', '”']],
        ['', '[[]]', ['[[', ']]']],
        ['', '¹', '¹'],
        ['', '²', '²'],
        ['', '³', '³'],
    ],

    //------------------------------

    _insert: function(k) {
        repl = $EditPageRedesign.chartable[k][2];
        if (typeof repl == 'function') {
            repl = repl();
            if (repl == null) return;
        }
        if (typeof repl == 'string') {
            // TODO: it should replace selected text if any.
            insertTags(repl, '', '');
        } else {
            insertTags(repl[0], repl[1], '');
        }
    },

    _entrywrapper: function(entry, value, message, mark) {
        filter = function(str, needle, repl) {
            str = str.split(needle);
            repr = str[0].$escape();
            for (i = 1; i < str.length; ++i) repr += ' + ' + repl + ' + ' + str[i].$escape();
            return repr;
        };

        prev = value;
        body = 'l = prompt(' + message.$escape() + ', prev); if (!l) return null; prev = l; return ';
        if (typeof entry == 'string') body += filter(entry, replacement, 'l');
        else body += '[' + filter(entry[0], mark, 'l') + ', ' + filter(entry[1], mark, 'l') + ']';
        return new Function('', body);
    },

    process: function() {
        // ensure this page is edit page
        var textarea = document.getElementById('wpTextbox1');
        if (!textarea) textarea = document.getElementById('wpUploadDescription');
        if (!textarea) return;

        // remove useless toolbar and character table
        var toolbar = document.getElementById('toolbar');
        if (toolbar) toolbar.parentNode.removeChild(toolbar);
        var chartables = document.getElementById('editpage-specialchars');
        if (chartables) chartables.parentNode.removeChild(chartables);

        // insert new character table
        var chartables = document.createElement('DIV');
        chartables.id = 'editpage-specialchars';
        var delim = $EditPageRedesign.label + ' ';
        var entry, link, shortcut;
        for (var i = 0; i < $EditPageRedesign.chartable.length; ++i) {
            entry = $EditPageRedesign.chartable[i];
            if (entry[2].text) {
                $EditPageRedesign.chartable[i][2] = $EditPageRedesign._entrywrapper(
                        entry[2].text, entry[2].deftext, entry[2].prompt, entry[2].mark || '$');
            }
            link = document.createElement('A');
            link.href = '#';
            link.accessKey = entry[0];
            link.onclick = new Function('', '$EditPageRedesign._insert(' + i + '); return false;');
            link.appendChild(document.createTextNode(entry[1]));
            chartables.appendChild(document.createTextNode(delim));
            chartables.appendChild(link);
            if (entry[0]) {
                shortcut = document.createElement('SMALL');
                shortcut.appendChild(document.createTextNode(entry[0]));
                chartables.appendChild(shortcut);
            }
            delim = ' ';
        }
        textarea.parentNode.insertBefore(chartables, textarea);
    },
};

addOnloadHook($EditPageRedesign.process);

} // end if (typeof == 'object')

////////////////////////////////////////////////////////////////////////////////
// JAVASCRIPT CONSOLE
// usage: $JavascriptConsole = {};
// - attach simple javascript console below document (double-click footer to show)

if (typeof $JavascriptConsole == 'object') {

$JavascriptConsole = {
    _toggleform: function() {
        var node = document.getElementById('z-console');
        if (node.style.display == 'none') {
            node.style.display = 'block';
            document.location.href = '#console';
        } else {
            node.style.display = 'none';
        }
        return false;
    },

    _objdump: function(obj) { // TODO - better inspection is needed
        var tmp;
        var output = 'typeof = ' + typeof(obj) + '\n\n';
        for (var x in obj) {
            if (x[0] == '$') continue; // ignore $-prefixed internal property
            tmp = ((x >= '0' && x < ':') || x[0] == '-' ? 'obj[' + x + ']' : 'obj.' + x);
            output += x + ' = ' + eval(tmp) + '\n';
        }
        return output;
    },

    _execute: function(flag) {
        var res = document.getElementById('z-console-res');
        var obj = eval(document.getElementById('z-console-cmd').value);
        if (flag) {
            res.value += this._objdump(obj);
        } else if (typeof obj != 'undefined') {
            res.value += obj + '\n';
        }
        return false;
    },

    process: function() {
        var footer = document.getElementById('footer');

        var evalhtml =
            '<form id="console" name="console" onsubmit="return $JavascriptConsole._execute(false);">' +
            '<textarea id="z-console-cmd" style="width:59%" cols="60" rows="25" tabindex="1000"></textarea>' +
            '<textarea id="z-console-res" style="width:39%" cols="40" rows="25"></textarea>' +
            '<br /><input type="button" id="z-console-exec" value="Execute" tabindex="1001" ' +
                'onclick="return $JavascriptConsole._execute(false);" /> ' +
            '<input type="button" id="z-console-dump" value="Execute w/ objdump" tabindex="1002" ' +
                'onclick="return $JavascriptConsole._execute(true);" /> ' +
            '<input type="button" id="z-console-clear" value="Clear" tabindex="1003" ' +
                'onclick="document.getElementById(\'z-console-res\').value=\'\'; return false;" />' +
            '</form>';
        var evalnode = document.createElement('div');
        evalnode.id = 'z-console';
        evalnode.style.display = 'none';
        evalnode.innerHTML = evalhtml;
        footer.parentNode.insertBefore(evalnode, footer);
        footer.ondblclick = $JavascriptConsole._toggleform;

        // utility function for console
        window.$debug = function(obj) {
            document.getElementById('z-console-res').value += obj + '\n';
        };
        window.$dump = function(obj) {
            document.getElementById('z-console-res').value += $JavascriptConsole._objdump(obj);
        };
    },
};

addOnloadHook($JavascriptConsole.process);

} // end if (typeof == 'object')

////////////////////////////////////////////////////////////////////////////////
// SIMPLE INTERWIKI
// usage: $SimpleInterwiki = {targets: {...}, targetmap: {document: [...], media: [...]}, skipcurrent: true};
// - shows selected interwikis with title below title

if (typeof $SimpleInterwiki == 'object') {

$SimpleInterwiki = {
    targets: $SimpleInterwiki.targets || {0: 'document', 2: 'user', 4: 'document', 6: 'media',
                                          8: 'system', 10: 'document', 12: 'system', 14: 'document'},
    targetmap: $SimpleInterwiki.targetmap || {document: ['ko.wp', 'en.wp', 'ja.wp'],
                                              media: ['ko.wp', 'en.wp', 'ja.wp', 'commons']},
    site: $SimpleInterwiki.site || $Page.current.site,
    skipcurrent: $SimpleInterwiki.skipcurrent || true,

    //------------------------------

    _harvestlinks: function() {
        var result = {};

        // search for known interwikis
        var node = document.getElementById('p-lang');
        if (node) {
            var nodes = document.getElementsByTagName('li');
            for (var i = 0; i < nodes.length; ++i) {
                if (nodes[i].className.substring(0, 10) != 'interwiki-') continue;
                var parsed = $Page.fromURL(nodes[i].firstChild.href);
                if (parsed == null) continue; // TODO
                result[parsed.site] = parsed.pagename;
            }
        }

        return result;
    },

    process: function() {
        var targets = $SimpleInterwiki.targetmap[$SimpleInterwiki.targets[wgNamespaceNumber] || 'misc'];
        if (!targets) return;
        var links = $SimpleInterwiki._harvestlinks();

        var info = document.createElement('div');
        info.id = 'infoSub';
        var pagename, anchor, node, flag = false;
        for (var i = 0; i < targets.length; ++i) {
            pagename = $nsToPrefix(targets[i], wgNamespaceNumber) + wgTitle;
            if (targets[i] == $SimpleInterwiki.site) {
                if ($SimpleInterwiki.skipcurrent) continue;
                anchor = document.createElement('strong');
                anchor.className = 'selflink';
            } else {
                anchor = document.createElement('a');
                if (links[targets[i]]) pagename = links[targets[i]]; else anchor.className = 'new';
            }
            anchor.href = new $Page(targets[i], pagename).toURL();
            anchor.appendChild(document.createTextNode(pagename));
            node = document.createElement('span');
            node.className = 'site-' + targets[i].replace(/\./g, '-');
            node.appendChild(document.createTextNode(targets[i] + ': '));
            node.appendChild(anchor);
            if (flag) {
                info.appendChild(document.createTextNode(' / '));
            } else {
                flag = true;
            }
            info.appendChild(node);
        }

        var body = document.getElementById('bodyContent');
        body.insertBefore(info, body.firstChild);
    },
};

addOnloadHook($SimpleInterwiki.process);

} // end if (typeof == 'object')

////////////////////////////////////////////////////////////////////////////////
// PURGE BUTTON
// usage: $PurgeButton = {label: '... (optional)'};
// - adds purge button to all pages except special namespace

if (typeof $PurgeButton == 'object') {

$PurgeButton = {
    label: $PurgeButton.label || '새로고침',

    //------------------------------

    process: function() {
        // do not show purge button in special pages
        if ($Page.current.split()[0] < 0) return;

        var node = document.getElementById('p-cactions');
        for (var i = 0; i < node.childNodes.length; ++i) {
            if (node.childNodes[i].tagName == 'UL') {
                var anchor = document.createElement('A');
                anchor.href = $Page.current.action('purge').toURL();
                anchor.appendChild(document.createTextNode($PurgeButton.label));
                var item = document.createElement('LI');
                item.id = 'ca-purge';
                item.appendChild(anchor);
                node.childNodes[i].appendChild(item);
            }
        }
    },
};

addOnloadHook($PurgeButton.process);

} // end if (typeof == 'object')

//////////////////////////////////////////////////////////////////////////////// </pre>