Finalised Tone is color

By Serge Bertrand Last update Aug 13, 2009 — Installed 223 times.

There are 2 previous versions of this script.

// ==UserScript==
// @name          Finalised Tone is color
// @namespace     http://www.bertrand.asia/
// @description   Colorise chinese character according to tone
// @include        *     
// @resource      Adso adso.dat
// @resource      AdsoIdx simp.idx
// ==/UserScript==
if(top != self) {GM_log (window.location+"  est DANS UNE FRAME (unsafe) de  "+unsafeWindow.parent.location);return;}
// pas dans les iframes
var color= new Array('black','blue','orange','green','red','grey');// this is no tone, first tone....fourth tone, light tone
var myDico = GM_getResourceText("Adso");
var myIdx = GM_getResourceText("AdsoIdx");
var myIdxl=myIdx.length;
const WORD=2;
const PINYIN=3;
const DEF=4;
const TONE=5;
var tdata = Array();
tdata.prevTarget=null;
tdata.prevRangeNode=null;
tdata.prevRangeOfs=0;
tdata.popX=0;
tdata.popY=0;
// position of the tooltip relative to the mouse in pixel //
var offsetx = 12;
var offsety =  8;
var txtref=' ';


function ligne() {// lit une ligne de myidx
	var ligneContent="";
	var c="";
	while (myIdx.charAt(current)!='\r'){
			ligneContent+=myIdx.charAt(current);;
			current++;
	}
	current++;
	ligneContent+="\n";
	current++;
	return ligneContent;
}
function getCarCode(line) {
	return line.charCodeAt(0);
}

if ( typeof(dic) == "undefined") {
	//alert ("je passe par là");
	var current=0;
	var dictrie="";
	var nl=0;
	var code=0;
	var mincode=99999999;
	var maxcode=0
	dic = Array();
	
	while (current <myIdxl-2) { //
		l=ligne();
		nl++;
		code=l.charCodeAt(0);
		if ((code<mincode)&(code>200)) {mincode=code;}
		if (code>maxcode) {maxcode=code;}
		if (dic[code]==undefined) {dic[code]="\n"+l;}
		else {dic[code]+=l;}
	}
}
else {alert ("好"+"好".charCodeAt(0)+dic["好".charCodeAt(0)]);}


//alert('cest commencé');
window.addEventListener("load", function(e) {
  GM_log ('cademarre :'+window.location+'  charset='+document.characterSet);init();
}, false);
if (typeof(unsafeWindow.parent)!="undefined"){GM_log (window.location+"  est dans une frame (unsafe) de  "+unsafeWindow.parent.location);}

/*window.setTimeout(,10000);
GM_registerMenuCommand( "Colorise!", colorise, "e", "control", "h" );
*/
function colorise(node){
	//GM_log ('ca a demarre apres click');
	//var node =document.getElementsByTagName("body")[0];
//GM_log(node.attributes[0].name+'-->'+node.attributes[0].value);
	//GM_log ('text"'+node.textContent+'"\n'+node.toString());
//while ((node.nodeValue!=3)||(node=='null')){node=nextSibling(node);}
//alert (node.textContent);
	var textnodes = document.evaluate("//text()",node,null,XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,null);
	for (var i = 0; i < textnodes.snapshotLength; i++) {
		if (textnodes.snapshotItem(i).parentNode.getAttribute('colorised')!='yes'){
			replaceTextOfTextNode( textnodes.snapshotItem(i));
		}
	}
}
function init(){
var node =document.body;
var style=' #tooltip {padding: 3px; background: #C0C0C0; border: 1px solid #eee; text-align: left; font-size: 15px;} span.tip { border-bottom: 1px solid #eee;}';
var testing = false;
var now= new Date();
var timer=now.getTime();
GM_log(timer);
colorise(node);
now= new Date();timer=now.getTime()-timer;
GM_log('letemps de colorisation est '+timer);
//node.addEventListener("DOMSubtreeModified", f1=function(e){test("DOMSubTreeModified",e);}, false);
node.addEventListener("DOMNodeInserted", f2=function(e){test("DOMNodeInserted",e);}, false);
newelement('tooltip');
GM_addStyle(style);
node.addEventListener("mousemove",f4=function(event){sourisBouge(event);},false);
//node.addEventListener("DOMCharacterDataModified", f3=function(e){test("DOMCharacterModified",e);}, false);
GM_log('colorise static finished !');
}
function test(nom,e) {
	//GM_log (nom+'  : '+e.explicitOriginalTarget.nodeName+'\n');
	if (nom=="DOMNodeInserted") {
		//GM_log('Node Inserted text :'+e.explicitOriginalTarget.textContent);
		if (e.explicitOriginalTarget.nodeName!='#text'){
			//document.body.removeEventListener("DOMSubtreeModified", f1, false);
			document.body.removeEventListener("DOMNodeInserted", f2, false);
			//document.body.removeEventListener("DOMCharacterDataModified", f3, false);
			colorise(e.explicitOriginalTarget);
			//document.body.addEventListener("DOMSubtreeModified", f1, false);
			document.body.addEventListener("DOMNodeInserted", f2, false);
			//document.body.addEventListener("DOMCharacterDataModified", f3, false);
		}
		
		else {
			//document.body.removeEventListener("DOMSubtreeModified", f1, false);
			document.body.removeEventListener("DOMNodeInserted", f2, false);
			//document.body.removeEventListener("DOMCharacterDataModified", f3, false);
			replaceTextOfTextNode(e.explicitOriginalTarget);
			//document.body.addEventListener("DOMSubtreeModified", f1, false);
			document.body.addEventListener("DOMNodeInserted", f2, false);
			//document.body.addEventListener("DOMCharacterDataModified", f3, false);
		}
		
	}
		
}
function replaceTextOfTextNode(node){
	var frag = document.createDocumentFragment();
	//A faire tester si on a bien un text node
	try {
		var text=node.textContent; // ca pourrait etre data
	}
	catch(err)  {
		txt="There was an error on this page.\n\n";
		txt+="Error description: " + err.description + "\n\n";
		GM_log(txt);
		return
	}

	//GM_log(text);
	var split=splitNodeChinese(text);
	if (split=='noHanzi'){return;}
	for (i=0;i<split[0].length;i++){
		if (split[1][i]=='8') {frag.appendChild(document.createTextNode(split[0][i]));}
		else {
			var font = document.createElement("FONT");
			var att = document.createAttribute("color");
			att.nodeValue = color[split[1][i]];
			var att2= document.createAttribute('colorised');
			att2.nodeValue='yes';
			font.setAttributeNode(att);
			font.setAttributeNode(att2);
			font.appendChild(document.createTextNode(split[0][i]));
			frag.appendChild(font);
		}
	}
	node.parentNode.replaceChild(frag,node);
}
function decreaseIndex(index,word,exact) {
	//GM_log('decreaseIndex  word='+word+'  exact='+exact);
	var reducedIndex='\n';
	var car=word;
	if (exact) {car+=',';}
	var i=0;
	i=index.indexOf('\n'+car,0);
	while (i!=-1){
		i++;
		//alert(myIdx.substr(i-10,20));
		do{
			c=index.charAt(i);
			reducedIndex+=c;
			i++;
		}while (c!='\n');
		i=index.indexOf('\n'+car,i-1);
	}
	//GM_log('reduced index '+reducedIndex);
	return reducedIndex;
}
	
function getIndexEntries(word){
	//GM_log('getIndexentries  word='+word);
	var inter='';
	var trouveIdx=/,(\d*)/;
	var isHanzi=/[\u4E00-\u9FFF]/;
	var dictLine=/([\u4E00-\u9FFF]*) ([\u4E00-\u9FFF]*)\s*\[([\u0000-\u00FF]*)]\s*\/([\u0000-\u00FF]*)\//;
	var u=new Array;
	var i; var j; var k;var l;
	var entry='';var c='';
	var entries=new Array();
	var goodEntry=new Array();
	var entry2="bonjour";
	var valid='';
	if (word==''){return false}
	//entry=decreaseIndex(myIdx,word.substr(0,1),false);
	entry=dic[getCarCode(word)];
	if (entry==undefined){GM_log('un car pas connu'+word.substr(0,1)+'in word'+word);return 'inconnu';} // ya un pb
	entry2=decreaseIndex(entry,word.substr(0,1),true);
	if (entry2!='\n'){valid+=entry2.substr(1,entry.length-1);}
	if (word.length==1){return valid;}
	for (i=2;i<=word.length;i++){
		entry=decreaseIndex(entry,word.substr(0,i),false);
		if (entry=='\n') break;
		entry2=decreaseIndex(entry,word.substr(0,i),true);
		if (entry2!=='\n'){valid+=entry2.substr(1,entry.length-1);}
	}
	return valid;
}
function searchDict(word){
	//GM_log ('SearchDict  word:'+word);
	var trouveIdx=/,(\d*)/;
	var isHanzi=/[\u4E00-\u9FFF]/;
	var dictLine=/([\u4E00-\u9FFF]*) ([\u4E00-\u9FFF]*)\s*\[([\u0000-\u00FF]*)]\s*\/([\u0000-\u9FFF]*)\//;
	var u=new Array;
	var i; var j; var k;var l;
	var entry='';var c='';
	var entries=new Array();
	var goodEntry=new Array();
	valid=getIndexEntries(word);
	if (valid=='inconnu') {
		var t=new Array();
		t[0]=word.substr(0,1);
		t[1]=word.substr(0,1);
		t[2]=word.substr(0,1);
		t[3]='?8';
		t[4]='inconnu';
		t[5]=8;
		goodEntry[0]=t;
		return goodEntry;
	}
		
	//GM_log ('valid:'+valid);
	entries=valid.split('\n');
	if (entries==null) alert (word+'\n'+reduceDict);
	//alert(entries.toString());
	for (i=0;i<entries.length-1;i++){
		u=trouveIdx.exec(entries[i]);
		if (u==null){alert('mauvaiseligne'+line);return entry;}
		j=parseInt(u[1]);
		//alert(u[1]);
		k=0;
		entry='';
		while((u=myDico.charAt(j+k))!='\n'){
			entry +=u;
			k++;
		}
		goodEntry[i]=dictLine.exec(entry);
		if (goodEntry[i]==null) {GM_log( 'pour '+word+' une entree ['+i+']: '+entry);}
		//alert(entry+'\n'+goodEntry[i].toString());
		goodEntry[i][TONE]=goodEntry[i][PINYIN].replace(/\D/g,'');
		//if(goodEntry[i][TONE].length!=goodEntry[i][WORD].length) {alert(' on a rate une marche'+word+' '+goodEntry[i].toString());}
	}
	//alert (goodEntry.toString());
	return goodEntry;
}
function getTones(chineseTxt){
	//GM_log('getTones  chineseTxt='+chineseTxt);
	var dictLine=/([\u4E00-\u9FFF]*) ([\u4E00-\u9FFF]*)\s*\[([\u0000-\u00FF]*)]\s*\/([\u0000-\u00FF]*)\//;
	var tab=new Array();
	var l=12; // longueur de la cahine de caractere
	if (l>chineseTxt.length) {l=chineseTxt.length;}
	var tones='';
	var i=0;var k=0;
	var delta;
	var pinyin;
	var ton;
	var entries;
	var max;
	while(i<chineseTxt.length){
		car=chineseTxt.substr(i,l);
		entries=searchDict(car);
		if (entries.length==0){
			console.log('allo Houston on a un pb un caractere inconnu !');
			tones+='0';
		}
		else{
			if (entries[entries.length-1][TONE].length==entries[entries.length-1][WORD].length){
				tones+=entries[entries.length-1][TONE];
			}
			else {tones+='0';console.log('good entry sans tons',entries[entries.length-1]);}
			
		}
		i=tones.length;
	}
	if (i!=chineseTxt.length){
		// alert('allo Houston on a un autre pb !');
		GM_log('ya un pb avec le texte:'+chineseTxt+'et les tons '+tones.toString());
		return tones.substr(0,chineseTxt.length-1);
	}
	// ce qui est au dessus et pas beau va falloir ameliorer
	return tones
}

function splitNodeChinese(txt) { //to be replaced by textNode
	//GM_log('SplitNodeChinese  txt='+txt);
	var haveHanzi=/([^\u4E00-\u9FFF]*)([\u4E00-\u9FFF]*)([\u0000-\uFFFF]*)/;
	var hanzi=/[\u4E00-\u9FFF]/;
	//if (txtnode.nodeName!='#text') {return 'false';}
	//txt=txtnode.textContent;
	var tab=haveHanzi.exec(txt);
	if (tab[2]=='') { return 'noHanzi';}
	var split=new Array();
	var cars=new Array();
	var tones=new Array();
	var i=0;
	do{
		if (tab[1]!='') {cars[i]=tab[1];tones[i]=8;}
		if (tab[2]!='') {
			tt=getTones(tab[2]);
			if (tt==false){GM_log('car sans ton: car= "'+tab[2]+'"  ton=false');}
			cars=cars.concat(tab[2].split(""));
			tones=tones.concat(tt.split(""));
		}
		suite=tab[3];
		tab=haveHanzi.exec(suite);
		i=tones.length;
	}while(suite!='');
	split[0]=cars;
	split[1]=tones;
	if (split[0].length!=split[1].length){alert( 'Houston moins de ton que de car');}
	return split;
}

function newelement(newid){ 
    if(document.createElement)    { 
        var el = document.createElement('div'); 
        el.id = newid;     
        with(el.style){ 
            display = 'none';
            position = 'absolute';
        } 
        el.innerHTML = txtref; 
        document.body.appendChild(el); 
    } 
} 

function exit() { document.getElementById('tooltip').style.display = 'none';}

function sourisBouge(ev) {
		var rp = ev.rangeParent;
		var ro = ev.rangeOffset;

		if (ev.target == tdata.prevTarget) {
			if ((rp == tdata.prevRangeNode) && (ro == tdata.prevRangeOfs)) return;
		}

		if ((ev.explicitOriginalTarget.nodeType != 3) && !('form' in ev.target)) {
			rp = null;
			ro = -1;
		}

		tdata.prevTarget = ev.target;
		tdata.prevRangeNode = rp;
		tdata.prevRangeOfs = ro;
		if ((rp) && (rp.data) && (ro < rp.data.length)) {
			//GM_log('sourisbouge'+ rp.nodeName+ 'rangeofs'+ro+' data '+rp.data);
			tdata.popX = ev.clientX;
			tdata.popY = ev.clientY;
			show (tdata)//afficher new popup
		}
			// dont close just because we moved from a valid popup slightly over to a place with nothing
		var dx = tdata.popX - ev.clientX;
		var dy = tdata.popY - ev.clientY;
		var distance = Math.sqrt(dx * dx + dy * dy);
		if (distance > 4) {	exit();return;}
	return;
}
function show(tdata) {
	var rp = tdata.prevRangeNode;
	var ro = tdata.prevRangeOfs;
	var u;

		if (!rp) {exit();return;}
		u = rp.data.charCodeAt(ro);
		// if we have '   XYZ', where whitespace is compressed, X never seems to get selected
		while (((u = rp.data.charCodeAt(ro)) == 32) || (u == 9) || (u == 10)) {
			++ro;
			if (ro >= rp.data.length) {	exit();return;}
		}
		if ( isNaN(u) || u < 0x4E00 || u > 0x9FFF ){exit();return;}
		var text = rp.data.substr(ro, 12);
		fin='false'
		while ((text.length < 12) && (fin=='false' )) {
	
			if (rp.nextSibling==null){
				if (rp.parentNode.nextSibling==null) { fin='true';}
				else {
					rp=rp.parentNode.nextSibling;
					var txt=rp.textContent;
					for (var i=0;i<txt.length;i++){
						u=txt.charCodeAt(i);
						if ( isNaN(u) || u < 0x4E00 || u > 0x9FFF|| txt.length>=12) { fin='true';break}
						text+=txt.charAt(i);
					}
				}
			}
			else {
				rp=rp.nextSibling; 
				var txt=rp.textContent;
				for (var i=0;i<txt.length;i++){
						u=txt.charCodeAt(i);
						if ( isNaN(u) || u < 0x4E00 || u > 0x9FFF|| txt.length>=12) { fin='true';break}
						text+=txt.charAt(i);
				}
			}
		}
		var e = null;
		var html='';
		var dico=sortSearchDict(text);
		for (var i=0;i<dico.length;i++){
			var split=splitNodeChinese();
			for (var j=0;j<dico[i][WORD].length;j++){
				html+='<font color="'+color[parseInt(dico[i][TONE].charAt(j))]+'">'+dico[i][WORD].charAt(j)+'</font>';
			}
			//GM_log(html);
			html+='   '+dico[i][PINYIN]+'  '+dico[i][DEF]+'<br/>';
		}
		if(!document.getElementById('tooltip')) newelement('tooltip');
		var lixlpixel_tooltip = document.getElementById('tooltip');
		document.body.removeEventListener("DOMNodeInserted", f2, false);
		lixlpixel_tooltip.innerHTML = html;
		lixlpixel_tooltip.style.display = 'block';
		var ww=window.innerWidth;
		lixlpixel_tooltip.style.left = (window.pageXOffset+1)+'px';
		var width=document.defaultView.getComputedStyle(lixlpixel_tooltip, null).getPropertyValue("width");
		width=width.substr(0,width.length-2);
		if ((tdata.popX+offsetx+parseInt(width))>ww) {lixlpixel_tooltip.style.left = (window.pageXOffset+ww-parseInt(width)-15)+'px';}
		else {lixlpixel_tooltip.style.left = window.pageXOffset+tdata.popX+offsetx+'px';}
        lixlpixel_tooltip.style.top = window.pageYOffset+tdata.popY+offsety+'px'//(mousey+pagey+offsety) + 'px';
		var width=document.defaultView.getComputedStyle(lixlpixel_tooltip, null).getPropertyValue("width");
		
		document.body.addEventListener("DOMNodeInserted", f2, false);

		// pour la selection il faut que je modifie le code pour trouver la fin 
		//var sel=window.getselection();
		//sel.removeAllRanges();
}
function sortSearchDict(word){
	var sortDic=Array();
	var dico=searchDict(word);
	var refi='';
	var refj='';
	var k=0
	for (var i=0;i<dico.length;i++){
		if (dico[i][6]!='done'){
		    refi=dico[i][WORD]+dico[i][PINYIN];
			sortDic[k]= new Array();
			sortDic[k][WORD]=dico[i][WORD];
			sortDic[k][PINYIN]=dico[i][PINYIN];
			sortDic[k][TONE]=dico[i][TONE];
			sortDic[k][DEF]=dico[i][DEF];
			for( var j=i+1;j<dico.length;j++){
				if (refi==(dico[j][WORD]+dico[j][PINYIN])) {sortDic[k][DEF]=union(sortDic[k][DEF],dico[j][DEF]);dico[j][6]='done';}
			}
			k++
		}
	}
	return sortDic
}
function union(tab1,tab2){
	var ta1= (tab1+'/'+tab2).split('/');
	var ti= new Array();
	ti[0]=ta1[0];
	for (var i=1;i<ta1.length;i++){
		var test= new Boolean(false);
		for (var j=0;j<ti.length;j++) {if (ta1[i]==ti[j]) test=true;}
		if (test==false) {ti[ti.length]=ta1[i];}
	}
	return ti.join('/');
}
			
	/*	
		// don't try to highlight form elements
		if ((this.cfg.highlight) && (!('form' in tdata.prevTarget))) {
			var doc = rp.ownerDocument;
			if (!doc) {
				this.clearHi();
				this.hidePopup();
				return;
			}
			var r = doc.createRange();
			r.setStart(rp, ro);
			r.setEnd(rp, ro + (e.matchLen ? e.matchLen : 1));

			var sel = doc.defaultView.getSelection();
			sel.removeAllRanges();
			sel.addRange(r);
			tdata.prevSelView = doc.defaultView;
		}

		this.showPopup(this.dict.makeHtml(e), tdata.prevTarget, tdata.popX, tdata.popY, false);
	*/