User:Jberkel/visibilityToggles.js

From Wiktionary, the free dictionary
Jump to navigation Jump to search

Note: You may have to bypass your browser’s cache to see the changes. In addition, after saving a sitewide CSS file such as MediaWiki:Common.css, it will take 5-10 minutes before the changes take effect, even if you clear your cache.

  • Mozilla / Firefox / Safari: hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (Command-R on a Macintosh);
  • Konqueror and Chrome: click Reload or press F5;
  • Opera: clear the cache in Tools → Preferences;
  • Internet Explorer: hold Ctrl while clicking Refresh, or press Ctrl-F5.

var VisibilityToggles = window.VisibilityToggles = {
	// toggles[category] = [[show, hide],...]; statuses[category] = [true, false,...]; buttons = <li>
	toggles: {},
	statuses: {},
	buttons: null,
	
	// Add a new toggle, adds a Show/Hide category button in the toolbar,
	// and will call showFunction and hideFunction once on register, and every alternate click.
	register: function (category, showFunction, hideFunction, visibleByDefault) {
		if (!this.toggles[category]) {
			this.toggles[category] = [];
			this.statuses[category] = [];
		} 
		var id = this.toggles[category].length;
		this.toggles[category].push([showFunction, hideFunction]);
		this.statuses[category].push(this.currentStatus(category, visibleByDefault));
		this.addGlobalToggle(category);
		
		(this.statuses[category][id] ? showFunction : hideFunction)();
		
		return function() {
			this.statuses[category][id] = !this.statuses[category][id];
			this.checkGlobalToggle(category);
			return (this.statuses[category][id] ? showFunction : hideFunction)();
		}.bind(this);
	},
	
	// Add a new global toggle to the side bar
	addGlobalToggle: function (category) {
		if (this.globalToggleElement(category)) {
			return;
		}
		if (this.buttons === null) {
			this.buttons = $('<ul>');
			var collapsed = mw.cookie.get('vector-nav-p-visibility') === 'false';
			var toolbox = $('<div>')
				.attr('id', 'p-visibility')
				.addClass('portal portlet')
				.addClass(collapsed ? 'collapsed' : 'expanded')
				.append('<h3>Visibility</h3>')
				.append(
					$('<div>').addClass('pBody body')
					          .css('display', 'block')
					          .append(this.buttons)
				);
			var insert = document.getElementById('p-lang') || 
			             document.getElementById('p-feedback');
			if (insert) {
				$(insert).before(toolbox);
			} else {
				var sidebar = document.getElementById('mw-panel') || document.getElementById('column-one');
				$(sidebar).appendChild(toolbox);
			}
		}
		var status = this.statuses[category][0];
		
		var newToggle = $('<li>').append($('<a>')
			.attr('id', 'p-visibility-' + category)
			.attr('href', '#visibility-' + category)
			.css('cursor', 'pointer')
			.text((status ? 'Hide ' : 'Show ') + category)
			.click(function() {
				this.toggleGlobal(category);
				return false;
			}.bind(this)));
		
		this.buttons.children().filter(function(i, elem) {
			return elem.id < newToggle.id;
		}).first().before(newToggle);

		this.buttons.append(newToggle);
	},
	
	// Update the toggle-all buttons when all things are toggled one way
	checkGlobalToggle: function (category) {
		var statuses = this.statuses[category];
		var status = statuses[0];
		for (var i = 1; i < statuses.length; i++) {
			if (status != statuses[i])
				return;
		}
		this.globalToggleElement(category).innerHTML = (status ? 'Hide ' : 'Show ') + category;
	},
	
	// Toggle all un-toggled elements when the global button is clicked
	toggleGlobal: function (category) {
		var status = this.globalToggleElement(category).innerHTML.indexOf('Show ') === 0;
		for (var i = 0; i < this.toggles[category].length; i++) {
			if (this.statuses[category][i] != status) {
				this.toggles[category][i][status ? 0 : 1]();
				this.statuses[category][i] = status;
			}
		}
		this.globalToggleElement(category).innerHTML = (status ? 'Hide ' : 'Show ') + category;
		this.cookie(category).set(status);
	},
	
	currentStatus: function (category, visibleByDefault) {
		if (location.hash.toLowerCase().split('_')[0] == '#' + category.toLowerCase())
			return true;
		else if (location.href.search(/[?](.*&)?hidecats=/) > 0) {
			var hidecats = location.href.replace(/^[^?]+[?]((?!hidecats=)[^&]*&)*hidecats=/, '')
				.replace(/&.*/, '')
				.split(',');
			for (var i=0; i<hidecats.length; ++i)
				if (hidecats[i] == category || hidecats[i] == 'all')
					return false;
				else if (hidecats[i] == '!' + category || hidecats[i] == 'none')
					return true;
		}
		else if (mw.cookie.get('WiktionaryPreferencesShowNav') == 'true')
			return true;
		// TODO check category-specific cookies
		else return this.cookie(category).get(visibleByDefault);
	},
	
	globalToggleElement: function(category) {
		return document.getElementById('p-visibility-' + category);
	},
	
	cookie: function(category) {
		var name = 'Visibility';
		var regex = new RegExp(';' + category + '(?:=(\\d))?;', 'g');
		return {
			get: function(defaultValue) {
				var matches = regex.exec(mw.cookie.get(name) || '');
				if (matches) {
					return matches.length > 1 ? parseInt(matches[1]) == 1 : true;
				} else {
					return defaultValue || false;
				}
			},
			set: function(status) {
				var value = (mw.cookie.get(name) || ';').replace(regex, ';');
				mw.cookie.set(name, value + category + '=' + (status ? '1' : '0') + ';');
			}
		};
	}
};