Template:DekiScript:Wiki

<% var wiki = module.exports = buildAPI({
    /*
    * Given a MediaWiki path attempt to update it to a Kuma path 
    * This is not a DekiScript function
    */
    kumaPath: function(in_path) {
        // Strip the base path, allows this to replace Template:getRelativeURL
        path_strip = in_path.replace(RegExp('^https:\/\/developer\.mozilla\.org','i'),'');
        // Get/fix/update/add language
        var pathLang = (path_strip.match(/^\/?(\w{2}(?:[-|_]\w{2})?)?(?=\/)/)[1] || env.locale).replace(/^en$/i,'en-US').replace(/^(?:zh_)?cn$/i,'zh-CN').replace(/zh_tw/i,'zh-TW').replace(/^pt$/i,'pt-PT');
        // Add fixed language and make sure there is docs and convert spaces to underscore
        var path = '/' + pathLang + path_strip.replace(/^(\/?\w{2}(?:[-|_]\w{2})?)?\/(?:docs\/)?/i,'/docs/').replace(/ /g,'_').replace(/%20/g,'_');
        return path;
    },
    
    //
    // Given a string, escape any quotes within it so it can be
    // passed to other functions.
    //
    escapeQuotes: function(a) {
        var b = "";
        for (var i = 0, len = a.length; i < len; i++) {
          var c = a[i];
          if (c=="\"") {
              c = "&quot;";
          }/* else if (c=='<') {
              c = "&lt;";
          } else if (c=='>') {
              c = "&gt;";
          }*/
          b += c;
        }
        return b.replace(/(<([^>]+)>)/ig, "");
    },

    // Given a path, attempt to construct an absolute URL to the wiki.
    // This is not a DekiScript function, but it's used by many of those below.
    buildAbsoluteURL: function (path) {
        var p = kuma.url.parse(env.url, true);
        var base_url = p.protocol + '//' + p.host;

        if (path.indexOf('/docs') == -1) {
            // HACK: If this looks like a legacy wiki URL, throw /en-US/docs 
            // in front of it. That will trigger the proper redirection logic 
            // until/unless URLs are corrected in templates
            base_url += '/en-US/docs';
        }
        var re1 = / /gi;
        var re2 = /%20/gi;

        path = path.replace(re1, "_");
        path = path.replace(re2, "_");

        if (path.charAt(0) != '/') { base_url += '/'; }

        return base_url + path;
    },
    
    // Check if the given wiki page exists.
    // [See also](http://developer.mindtouch.com/en/docs/DekiScript/Reference/Wiki_Functions_and_Variables/Wiki.PageExists)
    pageExists: function (path) {
        // Temporarily disabling this.
        // See: https://bugzilla.mozilla.org/show_bug.cgi?id=775590#c4
        return true;
        
        var key = 'kuma:page_exists:' + md5(path.toLowerCase());
        
        // This is an experiment to exempt wiki.pageExists 
        // from shift-refresh cache busting:
        var mdn = require('MDN:Common');

        //return cacheFn(key, 3600, function (next) {
        return mdn.cacheFnIgnoreCacheControl(key, 3600, function (next) {            
            var opts = { method: 'HEAD', url: wiki.buildAbsoluteURL(path) };

            try {
                request(opts, function (err, resp, body) {
                    var result = false;
                    if (resp && 200 == resp.statusCode) {
                        result = true;
                    }
                    next(result);
                });
            } catch (e) {
                next(false);
            }
        });
    },
    
    // Adjusts the visibility and heading levels of the specified HTML.
    //
    // The show parameter indicates whether or not the top level heading/title
    // should be displayed. The heading parameter sets the heading level of the
    // top level of the text to the specified value and adjusts all subsequent
    // headings accordingly. This adjustment happens regardless of the value of
    // show.
    // The heading parameter uses the values 0-5, as did DekiScript, 0 represents
    // a page header or H1, 1 - H2, 2 - H3 etc
    _adjustHeadings: function(html, section, show, heading) {
        if (html && heading) {
            // Get header level of page or section level
            var level = 1;
            if (section) {
                level = Number(html.match(/^<h(\d)[^>]*>/i)[1]);
            }
            var offset = 1 - level + Number(heading);
            // Change content header levels, there is probably a better way of doing this...
            var re;
            if (offset > 0) {
                for(i = 6; i >= level; i--) {
                    re = new RegExp("(<\/?h)" + i + "([^>]*>)", "gi");
                    html = html.replace(re, "$1" + (i + offset) + "$2");
                }
            }
            else if  (offset < 0) {
                for(i = level; i <= 6; i++) {
                    re = new RegExp("(<\/?h)" + i + "([^>]*>)", "gi");
                    html = html.replace(re, "$1" + (i + offset) + "$2");
                }
            }
        }

        if (show) { return html; }
        
        // Rip out the section header
        if (html) { html = html.replace(/^<h\d[^>]*>[^<]*<\/h\d>/ig,"") + ""; }
        
        return html;
    },
        
    // Retrieve the content of a document for inclusion, optionally filtering 
    // for a single section.
    //
    // Doesn't support the revision parameter offered by DekiScript
    //
    // [See also](http://developer.mindtouch.com/en/docs/DekiScript/Reference/Wiki_Functions_and_Variables/Wiki.Page)
    page: function (path, section, revision, show, heading, ignore_cache_control) {
        var key_text = path.toLowerCase();
        if (section) {
            key_text += '?section' + section;
        }
        var key = 'kuma:include:' + md5(key_text);

        var regenerate = function (next) {            
            var params = ['raw=1', 'macros=1', 'include=1'];

            if (section) { params.push('section='+encodeURIComponent(section)); }

            var opts = {
                method: 'GET',
                headers: { 'Cache-Control': env.cache_control },
                url: wiki.buildAbsoluteURL(path) + '?' + params.join('&')
            };

            try {
                request(opts, function (err, resp, body) {
                    var result = '';
                    if (resp && 200 == resp.statusCode) {
                        result = body || '';
                        if (show == undefined) {
                            show = 0;
                        }
                        result = wiki._adjustHeadings(result, section, show, heading);
                    }
                    next(result);
                });
            } catch (e) {
                next('');
            }
        };
        if (ignore_cache_control) {
            var mdn = require('MDN:Common');
            return mdn.cacheFnIgnoreCacheControl(key, 3600, regenerate);
        } else {
            return cacheFn(key, 3600, regenerate);
        }
    },

    // Readable shortcut to wiki.page with optional parameters
    // and ignore_cache_control=true
    pageIgnoreCacheControl: function (path, section, revision, show, heading) {
        return wiki.page(path, section, revision, show, heading, true);
    },

    // Returns the page object for the specified page.
    // http://developer.mindtouch.com/en/docs/DekiScript/Reference/Wiki_Functions_and_Variables/Wiki.GetPage
    getPage: function (path) {
        var key = 'kuma:get_page:' + md5(path.toLowerCase());
        return cacheFn(key, 3600, function (next) {
            var opts = {
                method: 'GET',
                headers: { 'Cache-Control': env.cache_control },
                url: wiki.buildAbsoluteURL(path) + "$json"
            };
            try {
                request(opts, function (err, resp, body) {
                    var result = {};
                    if (resp && 200 == resp.statusCode) {
                        result = JSON.parse(body);
                    }
                    next(result);
                });
            } catch (e) {
                next({});
            }
        });
    },
     
    // Returns a list of the headings for the specified page.
    // Each item in the returned list is an object with these fields:
    //
    //  level:  the heading level (1-6)
    //  title:  the heading's text title, as displayed to the user
    //
    // Parameters:
    //
    //  path    The path of the page whose headings should be returned
    //  depth   The maximum header level to return
    
    getHeadings: function(path, depth) {
        var html = wiki.page(path);
                
        if (!html || html.length == 0) {
            return NULL;
        }
        
        if (!depth) {
            depth = 3;
        }

        var re = /\<h([1-6]).*?\>(.+)\<\/h[1-6]\>/gi;
        var result;
        var list = [];
        
        while ((result = re.exec(html))) {
            var theLevel = result[1];
            var theTitle = result[2];
            
            if (theLevel <= depth) {
                var obj = {level: theLevel, title: theTitle };
                list.push(obj);
            }
        }
        return list;
    },

    // Retrieve the full uri of a given wiki page.
    // [See also](http://developer.mindtouch.com/en/docs/DekiScript/Reference/Wiki_Functions_and_Variables/Wiki.Uri)
    uri: function (path, query) {
        var out = wiki.buildAbsoluteURL(path);

        if (query) { out += '?' + query; }

        return out;
    },
 
    // A link to the wiki page that you will add, that will be in a different language.
    // [See also](http://developer.mindtouch.com/en/docs/DekiScript/Reference/Wiki_Functions_and_Variables/Wiki.Languages)
    languages: function (langs) {
        // TODO
        var out = [];
        _.each(langs, function (url, lang) {
            out.push('<li><a href="', kuma.htmlEscape(url), '">',
                     kuma.htmlEscape(lang), '</a></li>');
        });
        return "<ul>" + out.join('') + "<\/ul>";
    },

    // Inserts a pages sub tree
    // [See also](http://developer.mindtouch.com/en/docs/DekiScript/Reference/Wiki_Functions_and_Variables/Wiki.Tree)
    // if reverse is non-zero, the sort is backward
    // if ordered is true, the output is an <ol> instead of <ul>
    //
    // Special note: If ordered is true, pages whose locale differ from
    // the current page's locale are omitted, to work around misplaced
    // localizations showing up in navigation.
    
    tree: function(path, depth, self, reverse, ordered) {
        var page = require('DekiScript:Page');
        
        // If the path ends with a slash, remove it.
        
        if (path.substr(-1, 1) === '/') {
            path = path.slice(0, -1);
        }
        
        var pages = page.subpages(path, depth, self);
        
        if (reverse == 0) {
            pages.sort(alphanumForward);
        } else {
            pages.sort(alphanumBackward);
        }
        
        return process_array(null, pages, ordered != 0);

    	function chunkify(t) {
			var tz = [], x = 0, y = -1, n = 0, i, j;

			while (i = (j = t.charAt(x++)).charCodeAt(0)) {
                var m = (i == 46 || (i >=48 && i <= 57));
				if (m !== n) {
					tz[++y] = "";
	    			n = m;
				}
				tz[y] += j;
			}
			return tz;
		}

        function alphanumForward(a, b) {

			var aa = chunkify(a.title);
			var bb = chunkify(b.title);

			for (x = 0; aa[x] && bb[x]; x++) {
				if (aa[x] !== bb[x]) {
					var c = Number(aa[x]), d = Number(bb[x]);
					if (c == aa[x] && d == bb[x]) {
						return c - d;
					} else return (aa[x] > bb[x]) ? 1 : -1;
				}
			}
			return aa.length - bb.length;
		}

        function alphanumBackward(a, b) {

    		var bb = chunkify(a.title);
			var aa = chunkify(b.title);

			for (x = 0; aa[x] && bb[x]; x++) {
				if (aa[x] !== bb[x]) {
					var c = Number(aa[x]), d = Number(bb[x]);
					if (c == aa[x] && d == bb[x]) {
						return c - d;
					} else return (aa[x] > bb[x]) ? 1 : -1;
				}
			}
			return aa.length - bb.length;
		}

        function process_array(folderItem, arr, ordered) {
            var result = '';
            var openTag = '<ul>';
            var closeTag = '</ul>';
            
            if (ordered) {
                openTag = '<ol>';
                closeTag = '</ol>';
            }
            
            if(arr.length) {
                result += openTag;

                // First add an extra item for linking to the folder's page
                // (only for ordered lists)
                if (folderItem != null && ordered) {
                    result += '<li><a href="' + folderItem.url + '">' + kuma.htmlEscape(folderItem.title) + '</a></li>';
                }
                
                // Now dive into the child items
                
                arr.forEach(function(item) {
                    if (!item) { return; }
                    if (ordered && (item.locale != env.locale)) { return; }
                    result += '<li><a href="' + item.url + '">' + kuma.htmlEscape(item.title) + '</a>' +
                              process_array(item, item.subpages || [], ordered) + '</li>';
                    
                });
                result += closeTag;
            }
            return result;
        }   
    }
     
}); %>
Search for pages that use Template:DekiScript:Wiki to see example use cases and how many pages use this macro.

Document Tags and Contributors

Tags: 
Last updated by: Sheppy,