MediaWiki:Gadget-colortoggle.js

来自希灵百科
跳转至: 导航搜索

注意:在保存之后,您可能需要清除浏览器缓存才能看到所作出的变更的影响。

  • Firefox或Safari:按住Shift的同时单击刷新,或按Ctrl-F5Ctrl-R(Mac为⌘-R
  • Google Chrome:Ctrl-Shift-R(Mac为⌘-Shift-R
  • Internet Explorer:按住Ctrl的同时单击刷新,或按Ctrl-F5
  • Opera:前往菜单 → 设置(Mac为Opera → Preferences),然后隐私和安全 → 清除浏览数据 → 缓存的图片和文件
var dropMenu = $('<div id="p-colorconv" role="navigation" class="vectorMenu" aria-labelledby="p-colorconv-label" style="background: linear-gradient(rgba(255,255,255,0),#fff);"><h3 id="p-colorconv-label" tabindex="0"><span data-color="yellow" style="padding:1px 3px;margin-left: 0.7em;margin-top: 1.375em;">颜表立</span><a href="#" tabindex="-1"></a></h3><div class="menu"><ul></ul></div></div>');

function cachedFactory(factory) {
	var cache = {};
	return function(key) {
		if (!(key in cache)) {
			cache[key] = factory(key);
		}
		return cache[key];
	};
}

var colorToRgba = (function() {
	var canvas = $('<canvas>')[0];
	canvas.width = canvas.height = 1;
	var ctx = canvas.getContext('2d');

	return cachedFactory(function(col) {
		ctx.clearRect(0, 0, 1, 1);
		ctx.fillStyle = col;
		ctx.fillRect(0, 0, 1, 1);
		var ret = $.makeArray(ctx.getImageData(0, 0, 1, 1).data);
		ret[3] /= 255;
		return ret;
	});
})();

function rgbaToColor(color) {
	if (color.length === 3) {
		return 'rgb(' + color[0] + ',' + color[1] + ',' + color[2] + ')';
	} else {
		return 'rgba(' + color[0] + ',' + color[1] + ',' + color[2] + ',' + color[3] + ')';
	}
}

function luminance(color) {
	var output = [];
	for (var i = 0; i < 3; i++) {
		var c = color[i] / 255;
		if (c <= 0.03928) output[i] = c / 12.92;
		else output[i] = Math.pow((c + 0.055) / 1.055, 2.4);
	}
	return 0.2126 * output[0] + 0.7152 * output[1] + 0.0722 * output[2];
}

function contrastRatio(c1, c2) {
	var l1 = luminance(c1) + 0.05;
	var l2 = luminance(c2) + 0.05;
	if (l1 > l2) {
		return l1 / l2;
	} else {
		return l2 / l1;
	}
}

function hslToRgb(color) {
	var h = color[0],
		s = color[1],
		l = color[2];
	var r, g, b;

	if (s === 0) {
		r = g = b = l;
	} else {
		var hue2rgb = function hue2rgb(p, q, t) {
			if (t < 0) t += 1;
			if (t > 1) t -= 1;
			if (t < 1 / 6) return p + (q - p) * 6 * t;
			if (t < 1 / 2) return q;
			if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
			return p;
		};

		var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
		var p = 2 * l - q;
		r = hue2rgb(p, q, h + 1 / 3);
		g = hue2rgb(p, q, h);
		b = hue2rgb(p, q, h - 1 / 3);
	}

	return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)];
}

function rgbToHsl(color) {
	var r = color[0] / 255,
		g = color[1] / 255,
		b = color[2] / 255;
	var max = Math.max(r, g, b),
		min = Math.min(r, g, b);
	var h, s, l = (max + min) / 2;

	if (max == min) {
		h = s = 0; // achromatic
	} else {
		var d = max - min;
		s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
		switch (max) {
			case r:
				h = (g - b) / d + (g < b ? 6 : 0);
				break;
			case g:
				h = (b - r) / d + 2;
				break;
			case b:
				h = (r - g) / d + 4;
				break;
		}
		h /= 6;
	}

	return [h, s, l];
}

var white = colorToRgba('#f6f6f6');

var lessBrightColor = cachedFactory(function(colortxt) {
	var rgb = colorToRgba(colortxt);
	var lum = contrastRatio(rgb, white);
	if (lum >= 2) {
		return colortxt;
	}
	var hsl = rgbToHsl(rgb);
	do {
		hsl[2] -= 0.02;
		rgb = hslToRgb(hsl);
	} while (contrastRatio(rgb, white) < 2);
	return rgbaToColor(rgb);
});

var highContrastColor = cachedFactory(function(colortxt) {
	var rgb = colorToRgba(colortxt);
	var lum = contrastRatio(rgb, white);
	if (lum >= 3) {
		return colortxt;
	}
	var hsl = rgbToHsl(rgb);
	do {
		hsl[2] -= 0.02;
		rgb = hslToRgb(hsl);
	} while (contrastRatio(rgb, white) < 3);
	return rgbaToColor(rgb);
});

function black(span) {
	span.css('color', 'black');
	span.css('background-color', '');
	span.css('text-shadow', '');
}

function lowBrightness(span) {
	var color = lessBrightColor(span.attr('data-color'));
	span.css('color', color);
	span.css('background-color', '');
	span.css('text-shadow', '');
}

function highContrast(span) {
	var color = highContrastColor(span.attr('data-color'));
	span.css('color', color);
	span.css('background-color', '');
	span.css('text-shadow', '');
}

function original(span) {
	span.css('color', span.attr('data-color'));
	span.css('background-color', '');
	span.css('text-shadow', '');
}

function originalWBackground(span) {
	var color = span.attr('data-color');
	span.css('color', color);
	if (contrastRatio(white, colorToRgba(color)) < 3) {
		span.css('background-color', '#3D3D3D');
	} else {
		span.css('background-color', '');
	}
	span.css('text-shadow', '');
}

function originalWShadow(span) {
	var color = span.attr('data-color');
	span.css('color', color);
	if (contrastRatio(white, colorToRgba(color)) < 3) {
		span.css('text-shadow', 'black 0 0 0.2em, black 0 0 0.2em, black 0 0 0.2em');
	} else {
		span.css('text-shadow', '');
	}
	span.css('background-color', '');
}

function makeOption(caption, style) {
	var item = $('<li id="ca-colorconv-0"><a>' + caption + '</a></li>');
	dropMenu.find('ul').append(item);
	item.click(function() {
		dropMenu.find('.selected').removeClass('selected');
		item.addClass('selected');
		localStorage.colorconv = style;
		applyStyle(style);
	});
}

function applyStyle(style) {
	$('[data-color]').each(function(i, obj) {
		var item = $(obj);
		styles[style](item);
	});
}

var styles = {
	'black': black,
	'lowBrightness': lowBrightness,
	'highContrast': highContrast,
	'original': original,
	'originalWBackground': originalWBackground,
	'originalWShadow': originalWShadow
};

makeOption('黑色', 'black');
makeOption('较高对比度', 'lowBrightness');
makeOption('高对比度', 'highContrast');
makeOption('原色', 'original');
makeOption('原色+背景', 'originalWBackground');
makeOption('原色+阴影', 'originalWShadow');

$(function() {
	$('#left-navigation').append(dropMenu);
	applyStyle(localStorage.colorconv || 'lowBrightness');
});