Toggle menu
Toggle preferences menu
Toggle personal menu
Not logged in
Your IP address will be publicly visible if you make any edits.
DOORS Site Logo

Welcome to the Official DOORS Wiki!
Please read the Wiki Rules the Manual of Style and familiarise yourself with our Wiki Policies before contributing to get a better understanding of what content is allowed on our wiki and how to display it properly, if you need help don't hesitate to reach out to a DOORS Wiki Staff Member.

MediaWiki:Gadget-RefRevision.js

MediaWiki interface page

Note: After publishing, you may have to bypass your browser's cache to see the changes.

  • Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (⌘-R on a Mac)
  • Google Chrome: Press Ctrl-Shift-R (⌘-Shift-R on a Mac)
  • Internet Explorer / Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5
  • Opera: Press Ctrl-F5.
$(function () {
	if ((window.dev = window.dev || {}).refRevision_Loaded) {return;}
	var api, refs;
	var config = mw.config.get(['wgPageName', 'wgArticleId', 'wgAction', 'wgNamespaceNumber']);
	var loadingDefault = '<img src="https://www.superiorlawncareusa.com/wp-content/uploads/2020/05/loading-gif-png-5.gif" width="25px" style="vertical-align: baseline;" border="0" /> Loading...';
	
	var refRevision = {
		init: function() {
			refs = {
				_default: {},
				_callbacks: [],
				_conflicts: {},
				_undefined: {},
				_pages: { _list: [] },
			};
			if (['edit', 'submit'].includes(config.wgAction)) {
				refRevision.initEdit();
			} else if (config.wgAction == 'view') {
				refRevision.initView();
			}
		},
		initEdit: function () {
			var wrapper = 
				'<div tabindex="0" role="button" aria-expanded="true" class="mw-brokenRefsExplanation mw-editfooter-toggler mw-icon-arrow-collapsed">' +
					'<p>Broken references on this page:</p>' +
				'</div>' +
				'<small class="mw-editfooter-list brokenRefsResetter-wrapper" style="display: none;"><i>Click <a class="brokenRefsResetter" href="#brokenRefs">here</a> to reset the checker</i></small>' +
				'<div class="brokenRefsList mw-editfooter-list mw-collapsible mw-made-collapsible mw-collapsed" style="display: none;">' +
					loadingDefault +
				'</div>';
			if (document.querySelector('.brokenRefs')) {
				document.querySelector('.brokenRefs').innerHTML = wrapper;
			} else {
				$('.hiddencats').before( $('<div id="brokenRefs" class="brokenRefs">' + wrapper + '</div>') );
			}
			var toggler = document.querySelector('.brokenRefs .mw-editfooter-toggler');
			document.querySelector('.mw-brokenRefsExplanation').addEventListener('click', function (event) {
				if (document.querySelector('.brokenRefs .mw-icon-arrow-collapsed')) {
					toggler.classList.add('mw-icon-arrow-expanded');
					toggler.classList.remove('mw-icon-arrow-collapsed');
					document.querySelector('.brokenRefs .brokenRefsList').style.display = '';
					document.querySelector('.brokenRefsResetter-wrapper').style.display = '';
				} else {
					toggler.classList.add('mw-icon-arrow-collapsed');
					toggler.classList.remove('mw-icon-arrow-expanded');
					document.querySelector('.brokenRefs .brokenRefsList').style.display = 'none';
					document.querySelector('.brokenRefsResetter-wrapper').style.display = 'none';
				}
				if (!document.querySelector('.brokenRefs .brokenRefsList.listLoaded')) {
					document.querySelector('.brokenRefs .brokenRefsList').classList.add('listLoaded');
					refRevision.parseCurrent($('#wpTextbox1').textSelection('getContents'));
				}
			});
		},
		initView: function () {
			if (document.querySelector('.brokenRefs')) {
				document.querySelector('.brokenRefs').classList.add('wds-is-collapsed');
				var list = document.querySelector('.brokenRefsList');
				list.classList.remove('listLoaded');
				list.innerHTML = loadingDefault;
			} else {
				$('.page-footer > .license-description').before(
					$(
						'<div id="brokenRefs" class="brokenRefs wds-collapsible-panel page-footer__references wds-is-collapsed">' +
							'<header class="wds-collapsible-panel__header" aria-controls="collapsible-content-references" aria-expanded="false">References<svg class="wds-icon wds-icon-small"><use xlink:href="#wds-icons-menu-control-small"></use></svg></header>' +
							'<div class="wds-collapsible-panel__content" id="collapsible-content-references">' +
								'<nav id="articleReferences" class="article-references">' +
									'<div id="reflinks" class="reflinks" data-mw="interface"><div id="mw-normal-reflinks" class="mw-normal-reflinks">' +
										'<small class="brokenRefsResetter-wrapper"><i>Click <a class="brokenRefsResetter" href="#brokenRefs">here</a> to reset the checker</i></small>' +
										'<div class="brokenRefsList">' +
											loadingDefault +
										'</div>' +
									'</div></div>' +
								'</nav>' +
							'</div>' +
						'</div>'
					)
				);
			}
			function startCheck() {
				api
					.get({
						action: 'query',
						prop: 'revisions',
						titles: config.wgPageName,
						rvslots: '*',
						rvprop: 'content',
					})
					.then(function (data) {
						var page_content = data.query.pages[config.wgArticleId].revisions[0].slots.main['*'];
						refRevision.parseCurrent(page_content);
					});
			}
			document.querySelector('.brokenRefs').addEventListener('click', function (event) {
				if (!document.querySelector('.brokenRefs .brokenRefsList.listLoaded')) {
					document.querySelector('.brokenRefs .brokenRefsList').classList.add('listLoaded');
					startCheck();
				}
			});
		},
		renderList: function () {
			console.log(refs);
			var list = '';
			if (Object.keys(refs._conflicts).length > 0) {
				var header = false;
				Object.keys(refs._conflicts).forEach(function (group) {
					if (Object.keys(refs._conflicts[group]).length > 0) {
						if (!header) {
							header = true;
							list += '<h2>Conflicting Initializations</h2>';
						}
						list += '<h3>' + (group == '_default' ? 'Ungrouped' : group) + '</h3><ul>';
						Object.keys(refs._conflicts[group]).forEach(function (name) {
							list += '<li>' + name + ':<ul>';
							refs._conflicts[group][name].forEach(function (conflict) {
								list += '<li>In <a href=/wiki/"' + conflict.page + '">' + conflict.page + '</a>: <code>' + conflict.content + '</code></li>';
							});
							list += '</ul></li>';
						});
						list += '</ul>';
					}
				});
			}
			if (Object.keys(refs._undefined).length > 0) {
				var header = false;
				Object.keys(refs._undefined).forEach(function (group) {
					if (Object.keys(refs._undefined[group]).length > 0) {
						if (!header) {
							header = true;
							list += '<h2>Uninitialized Callbacks</h2>';
						}
						list += '<h3>' + (group == '_default' ? 'Ungrouped' : group) + '</h3><ul>';
						Object.keys(refs._undefined[group]).forEach(function (name) {
							var _pagelist = [];
							refs._undefined[group][name].forEach(function (_page) {
								_pagelist.push('<a href=/wiki/"' + _page + '">' + _page + '</a>');
							});
							list += '<li>' + name + ': ' + _pagelist.join(', ') + '</li>';
						});
						list += '</ul>';
					}
				});
			}
			if (list == '') {
				list = 'No broken references detected. Good job!';
			}
			document.querySelector('.brokenRefsList').innerHTML = list;
		},
		parseCurrent: function (page_content) {
			if (/\{\{Transclude\s*\|[^\}]+?\}\}/.test(page_content)) {
				// Get transclusions
				page_content.match(/\{\{Transclude\s*\|[^\}]+?\}\}/g).forEach(function (str) {
					var _a = str.replace(/\{\{Transclude\s*\|/, '').replace(/\}\}$/, '').split('|');
					_a.forEach(function(param){
						if (/=/.test(param)) {
							if (/^\s*1\s*=/.test(param)) {page = param;}
							else if (/^\s*2\s*=/.test(param)) {section = param;}
							else if (/^\s*section\s*=/.test(param)) {tag = true;}
						} else {
							if (!page) {page = param;}
							else if (!section) {section = param;}
						}
					});
					var page, section, tag;
					refs._pages[page] = refs._pages[page] || {
						title: page,
						sections: [],
						tags: []
					};
					refs._pages._list.push(page);
					if (tag) {refs._pages[page]['tags'].push(section);}
					else {refs._pages[page].sections.push(section);}
					
				});
			}

			// Get references
			refRevision.parseReferences(page_content, config.wgPageName);
			if (refs._pages._list.length > 0) {
				var _t = 0;
				for (var i = 0; i < refs._pages._list.length; i = i + 49) {
					var _page = refs._pages._list.slice(i, i + 49);
					api
						.get({
							action: 'query',
							prop: 'revisions',
							titles: _page,
							rvslots: '*',
							rvprop: 'content',
						})
						.then(function (data) {
							if (data && data.query && data.query.pages && Object.keys(data.query.pages).length > 0) {
								Object.keys(data.query.pages).forEach(function (id) {
									if (data.query.pages[id] && data.query.pages[id].revisions && data.query.pages[id].revisions[0].slots.main['*']) {
										var pageName = data.query.pages[id].title;
										var split = refRevision.splitSections(data.query.pages[id].revisions[0].slots.main['*'], pageName);
										console.log(refs._pages[pageName], 'refs._pages[pageName]')
										console.log(split, 'split')
										refs._pages[pageName].sections.forEach(function (name) {
											if (split.sections && split.sections[name] && split.sections[name].length > 0) {
												refRevision.parseReferences(split.sections[name], pageName);
											}
										});
										refs._pages[pageName]['tags'].forEach(function (name) {
											if (split['tags'] && split['tags'][name] && split['tags'][name].length > 0) {
												refRevision.parseReferences(split['tags'][name], pageName);
											}
										});
									}
								});
								_t++;
							}
						});
				}
				function waitforPages() {
					if (_t >= Math.ceil((refs._pages._list.length - 1) / 50)) {
						refRevision.findUndefined();
						refRevision.renderList();
					} else {
						setTimeout(waitforPages, 500);
					}
				}
				setTimeout(waitforPages, 500);
			} else {
				refRevision.findUndefined();
				refRevision.renderList();
			}
		},
		parseReferences: function (page_content, page) {
			// Parse initializers
			if (/<ref\s*[^\/>]*?>[\s\S]+?<\/ref>/.test(page_content)) {
				page_content.match(/<ref\s*[^\/>]*?>[\s\S]+?<\/ref>/g).forEach(function (str) {
					var _a = /<ref\s*([^\/>]*?)>([\s\S]+?)<\/ref>/.exec(str);
					var settings = { group: '_default' };
					if (_a[1].length > 0 && /\w[\w\s]*\s*=\s*".+?"/.test(_a[1])) {
						_a[1].match(/\w[\w\s]*\s*=\s*".+?"/g).forEach(function (sett) {
							var _b = /(\w[\w\s]*)\s*=\s*"(.+?)"/.exec(sett);
							if (_b[1].length > 0 && _b[2].length > 0) {
								settings[_b[1]] = _b[2];
							}
						});
						if (settings.name) {
							refs[settings.group] = refs[settings.group] || {};
							refs._conflicts[settings.group] = refs._conflicts[settings.group] || {};
							if (refs[settings.group][settings.name] && refs[settings.group][settings.name].content !== _a[2].trim()) {
								refs._conflicts[settings.group][settings.name] = refs._conflicts[settings.group][settings.name] || [refs[settings.group][settings.name]];
								refs._conflicts[settings.group][settings.name].push({
									name: settings.name,
									group: settings.group,
									content: _a[2].trim(),
									page: page,
								});
							} else {
								refs[settings.group][settings.name] = {
									name: settings.name,
									group: settings.group,
									content: _a[2].trim(),
									page: page,
								};
							}
						}
					}
				});
			}

			// Parse callbacks
			if (/<ref\s*[^\/>]*?\/>/.test(page_content)) {
				page_content.match(/<ref\s*[^\/>]*?\/>/g).forEach(function (str) {
					var _a = /<ref\s*([^\/>]*?)\/>/.exec(str);
					var settings = { group: '_default' };
					if (_a[1].length > 0 && /\w[\w\s]*\s*=\s*".+?"/.test(_a[1])) {
						_a[1].match(/\w[\w\s]*\s*=\s*".+?"/g).forEach(function (sett) {
							var _b = /(\w[\w\s]*)\s*=\s*"(.+?)"/.exec(sett);
							if (_b[1].length > 0 && _b[2].length > 0) {
								settings[_b[1]] = _b[2];
							}
						});
						if (settings.name) {
							refs[settings.group] = refs[settings.group] || {};
							refs._callbacks.push({
								name: settings.name,
								group: settings.group,
								page: page,
							});
						}
					}
				});
			}
		},
		splitSections: function (str, page) {
			var sorted = {
				sections: {},
				tags: {}
			};
			str = str.replace(/<!--[\s\S]*?-->/g, '');
			if (/<section/.test(str)) {
				str.match(/<section.*?begin=".*?".*?\/\s*>[\s\S]*?<section.*?end=".*?".*?\/\s*>/g).forEach(function(group){
					var _a = /<section.*?begin="(.*?)".*?\/\s*>([\s\S]*?)<section.*?end=".*?".*?\/\s*>/.exec(group);
					if (_a[1] && _a[2] && _a[1].length>0 && _a[2].length>0) {
						sorted['tags'][_a[1]] = _a[2];
					}
				});
			}
			str = str.replace(/^[\s\S]*?==/, '==');
			function split(content, level) {
				var indexes = [];
				content.replace(RegExp('='.repeat(level) + '[^=]+' + '='.repeat(level), 'g'), function (a, b) {
					indexes.push(b);
				});
				indexes.forEach(function (curr, index) {
					var _s = RegExp('\\s*' + '='.repeat(level) + '([^=]+)' + '='.repeat(level) + 's*([\\s\\S]+)s*$', 'g').exec(content.substring(curr, indexes[index + 1] ? indexes[index + 1] : undefined));
					if (_s && _s[1].length > 0 && _s[2]) {
						sorted.sections[_s[1]] = _s[2];
						if (_s[2].length > 0) {
							split(_s[2], level + 1);
						}
					}
				});
			}
			split(str, 2);
			return sorted;
		},
		findUndefined: function () {
			refs._callbacks.forEach(function (callback) {
				if (!(refs[callback.group] || refs[callback.group][callback.name])) {
					refs._undefined[callback.group] = refs._undefined[callback.group] || {};
					refs._undefined[callback.group][callback.name] = refs._undefined[callback.group][callback.name] || [];
					if (refs._undefined[callback.group][callback.name].indexOf(callback.page) == -1) {
						refs._undefined[callback.group][callback.name].push(callback.page);
					}
				}
			});
		}
	};
	mw.loader.using('mediawiki.api').then(function () {
		window.dev.refRevision_Loaded = true;
		if ([2, 0].includes(config.wgNamespaceNumber)) {
			api = new mw.Api();
			var style = document.createElement('style');
			style.innerHTML =
				'.brokenRefs ul { margin: 6px 0 6px 36px; list-style-type: disc; } ' +
				'.brokenRefs :is(h2, h3) { margin: .5em 0 .2em; font-size: 18px; font-weight: 500; overflow: initial; font-family: var(--theme-page	-headings-font),rubik,helvetica,arial,sans-serif; line-height: 1.25; overflow-wrap: break-word; } ' +
				'.brokenRefs h3 { font-size: 18px; } ' +
				'.brokenRefs h2 { font-size: 24px; padding: 6px 0; } ';
			document.body.append(style);
			refRevision.init();
			document.addEventListener('click', function(event){
				if (event.target.classList.contains('brokenRefsResetter')) {
					refRevision.init();
				}
			});
		}
	});
});