您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Adds a small panel to the top of the chat window with a list of macros, allowing you to fire chat macros with mouse actions.
// ==UserScript== // @name Chat Control Panel // @namespace kol.interface.unfinished // @description Adds a small panel to the top of the chat window with a list of macros, allowing you to fire chat macros with mouse actions. // @include https://*kingdomofloathing.com/lchat.php* // @include https://*kingdomofloathing.com/mchat.php* // @grant GM_getValue // @grant GM_setValue // @version 2.021 // ==/UserScript== //Version 2.021 // - trying to correct some spacing issues //Version 2.02 // - change to https //Version 2.01 // - add @grant, convert GM_log to console.log //Version 2.0 // - modified heavily to work with the new tabbed chat. This // changes the way the docking works, and there is now an // icon on the top right corner that toggles the appearance // of the panel instead of the bar on the right. //Version 1.0.3 // - more minor interface changes // - resizing is now granular, always shrinking or growing by // a full entry. // - the toggle bar now stays on the right of the chat control // panel so you can quickly toggle on/off without moving // the mouse. // - the control panel sticks to the top when moved very close // to the top of the chat pane. //Version 1.0.2 // - a minor aesthetic change, using partial transparency to // hide slightly less of the underlying chap panel text. //Version 1.0.1 // - fix mouse-over message for resize dragging //Version 1.0 // - changed the docking method, so you now click on a bar // on the right to dock it on the right // - added a pull bar next to the docking bar so you can // slide it anywhere in the chat pane // - the former docking tab (line) at the bottom is now a // pull tab so you can resize it to as many entries as // you want (or can fit). //Version 0.9 var height=unitHeight(5); var ccmds; var playername; var dims; function rollHandler() { var cp = document.getElementById('chatcp'); var cph = document.getElementById('chatcp_handle'); if (cp && cph) { var v = cp.getAttribute('style'); var w = cph.getAttribute('style'); if (v.match(/display\s*:\s*none/)) { cp.setAttribute('style',removeStyle(v,'display')); cph.setAttribute('style',removeStyle(w,'display')); saveDock(false); } else { cp.setAttribute('style','display:none;'+v); cph.setAttribute('style','display:none;'+w); saveDock(true); } } } function replaceOrAddStyle(s,a,v) { var r = new RegExp(a+'\\s*:','i'); var sa = s.split(';'); for (var i=0;i<sa.length;i++) { var x = sa[i].match(r); if (x) { sa[i] = a+':'+v; return sa.join(';'); } } return a+':'+v+';'+s; } function removeStyle(s,a) { var r = new RegExp(a+'\\s*:','i'); var sa = s.split(';'); for (var i=0;i<sa.length;i++) { var x = sa[i].match(r); if (x) { sa[i] = ''; return sa.join(';').replace(';;',';'); } } return s; } function getStyleAttr(s,a) { var r = new RegExp('(^|;\\s*)'+a+'\\s*:\\s*([0-9]+)','i'); var x = s.match(r); if (x) return Number(x[2]); //console.log('could not find style: "' +a+'" in "'+s+'"'); return -1; } function setTopBorder(s) { return replaceOrAddStyle(s,'border-top','1px solid black'); } function removeTopBorder(s) { return removeStyle(s,'border-top'); } function setWidths(e) { getMaxDimensions(); var cp = document.getElementById('chatcp'); var cph = document.getElementById('chatcp_handle'); var cpd = document.getElementById('chatcp_dock'); if (cp && cph && cpd) { var w = (dims.headerw) ? dims.headerw : dims.width; //document.body.clientWidth-19; //console.log("Setting width to "+w); cph.setAttribute('style',cph.getAttribute('style').replace(/width\s*:\s*[0-9;px]*/,'width:'+(w+1)+'px;')); cp.setAttribute('style',cp.getAttribute('style').replace(/width\s*:\s*[0-9;px]*/,'width:'+(w+1)+'px;')); if (dims.headerw) cpd.setAttribute('style',cpd.getAttribute('style').replace(/left\s*:\s*[0-9;px]*/,'left:'+(dims.headerw-15)+'px;')); else cpd.setAttribute('style',cpd.getAttribute('style').replace(/left\s*:\s*[0-9;px]*/,'left:'+(w-15)+'px;')); var texts = document.getElementsByClassName('chatcp_text'); for (var i=0;i<texts.length;i++) { texts[i].setAttribute('style',texts[i].getAttribute('style').replace(/width\s*:\s*[0-9;px]*/,'width:'+(w-56)+'px;')); } } } function tHandler(e) { var ci = this.getAttribute('cmdidx'); ccmds[ci] = this.value; saveTable(ccmds); if (e.keyCode==13) insertCmd(ccmds[ci]); } function insertCmd(c) { if (c) unsafeWindow.submitchat(c); } function bHandler() { insertCmd(ccmds[this.getAttribute('cmdidx')]); } function addPanel() { height = restoreHeight(); ccmds = restoreTable(); var f = document.getElementById('ChatWindow'); var cp = document.getElementById('chatcp'); if (f && !cp) { placeDockIcon(f); cp = document.createElement('div'); var w = (dims.headerw) ? dims.headerw : dims.width;//document.body.clientWidth-19; var p = restorePos(); cp.setAttribute('style','height:'+height+'px;width:'+w+'px;'+((p>0)?'border-top:1px solid black;':'')+'background-image:-moz-linear-gradient(center top , white 50%, transparent 100%);z-index:7;font-size:12px;position:absolute;font-family:arial;left:2px;top:'+p+'px;'); cp.setAttribute('id','chatcp'); var t = document.createElement('table'); t.setAttribute('cellspacing','0'); for(var i=0;unitHeight(i)<height;i++) { newEntry(i,w-40,t); } var tt = document.createElement('table'); tt.setAttribute('style','vertical-align:top;'); var tr = document.createElement('tr'); var td = document.createElement('td'); tt.setAttribute('cellspacing','0'); tt.setAttribute('cellpadding','0'); td.setAttribute('style','vertical-align:top;'); td.appendChild(t); tr.appendChild(td); td = document.createElement('td'); var span = document.createElement('div'); span.setAttribute('style','background:lightgray;height:'+(height-4)+'px;width:15px;position:relative;top:2px;'); span.setAttribute('title','Click and drag to position the chat control panel.'); span.setAttribute('class','chatcpbar'); td.appendChild(span); tr.appendChild(td); tt.appendChild(tr); cp.appendChild(tt); var handle = document.createElement('div'); handle.setAttribute('style','height:7px;width:'+(w+1)+'px;text-align:center;vertical-align:middle;border-bottom:1px solid black;background-color:transparent;z-index:8;font-size:12px;position:absolute;font-family:arial;left:2px;top:'+(p+height-3)+'px;'); handle.setAttribute('id','chatcp_handle'); handle.setAttribute('title','Click and drag to resize the chat control panel.'); var a = document.createElement('img'); a.setAttribute('src',"data:image/png,%89PNG%0D%0A%1A%0A%00%00%00%0DIHDR%00%00%00%1E%00%00%00%05%08%02%00%00%00%DDC%CB%AD%00%00%00%01sRGB%00%AE%CE%1C%E9%00%00%00%09pHYs%00%00%0B%13%00%00%0B%13%01%00%9A%9C%18%00%00%00%07tIME%07%DA%0C%17%002%18%89S%DB%E9%00%00%00%19tEXtComment%00Created%20with%20GIMPW%81%0E%17%00%00%00%16IDAT%18%D3c%60%A0%19%60%FC%FF%FF%3F%C3%90%03C%D3%D5%00W%E9%05%FD%13%F9%A0%92%00%00%00%00IEND%AEB%60%82"); handle.appendChild(a); //handle.addEventListener('click',rollHandler,false); handle.addEventListener('mousedown',dragStartSize,false); cp.addEventListener('mousedown',dragStart,true); f.parentNode.insertBefore(cp,f); f.parentNode.insertBefore(handle,f); //cp.appendChild(handle); window.addEventListener('resize',setWidths,false); if (restoreDock()) rollHandler(); setWidths(); } } function unitHeight(u) { return u*27+5; } function heightUnit(h) { return Math.floor((h-5)/27); } function saveTable(t) { var pn = getPlayerNameFromCharpane(); if (pn) { GM_setValue(pn+'_cmds',t.join('#####')); } } function saveHeight(h) { height = h; var pn = getPlayerNameFromCharpane(); if (pn) { GM_setValue(pn+'_cpheight',h); } } function restoreHeight() { var pn = getPlayerNameFromCharpane(); if (pn) { return Math.ceil(Number(GM_getValue(pn+'_cpheight',unitHeight(5)))); } return Math.ceil(unitHeight(5)); } function saveDock(b) { var pn = getPlayerNameFromCharpane(); if (pn) { GM_setValue(pn+'_docked',b); } } function restoreDock() { var pn = getPlayerNameFromCharpane(); if (pn) { return Boolean(GM_getValue(pn+'_docked',false)); } } function restoreTable() { var pn = getPlayerNameFromCharpane(); if (pn) { var t = GM_getValue(pn+'_cmds',''); if (t) { t = t.split('#####'); return t; } } return ['Good morning clan-mates!', '/unequip all', '', '', '']; } function savePos(y) { var pn = getPlayerNameFromCharpane(); if (pn) { GM_setValue(pn+'_pos',y); } } function restorePos() { var pn = getPlayerNameFromCharpane(); if (pn) { var t = Number(GM_getValue(pn+'_pos',2)); return t; } return 2; } // utility to get player name; hacked/stolen from Antimarty's fortune cookie script function getPlayerNameFromCharpane() { var somef=window.parent.frames; var goo; for(var j=0;j<somef.length;j++) { if (somef[j].name=="charpane") { goo=somef[j]; var username = goo.document.getElementsByTagName("b"); if (!username || username.length < 1) return playername; username = username[0]; if (!username) return playername; username = username.firstChild; if (!username) return playername; // in full mode the link is <a><b>Name</b></a> // in compact mode it's <b><a>Name</a></b> // so have to handle this, and also can use it to tell // whether it's in compact mode or not. var fullmode = true; while (username && username.nodeType == 1) { username = username.firstChild; fullmode = false; } if (!username) return playername; username = username.nodeValue; if (!username) return playername; username = username.toLowerCase(); playername = username; return username; } } } // code to drag the panel around var d; function dragStart(event, id) { var cp = document.getElementById('chatcp'); var cph = document.getElementById('chatcp_handle'); if (cp && cph) { var v = getStyleAttr(cp.getAttribute('style'),'width'); if (v>=0) { if (event.clientX<v-50) return; } d = new Object(); d.cp = cp; d.cph = cph; var x = event.clientX + window.scrollX; var y = event.clientY + window.scrollY; // Save starting positions of cursor and element. d.cursorStartX = x; d.cursorStartY = y; d.elStartLeft = parseInt(cp.style.left, 10); d.elStartTop = parseInt(cp.style.top, 10); d.baseH = getStyleAttr(cp.getAttribute('style'),'height'); if (isNaN(d.elStartLeft)) d.elStartLeft = 2; if (isNaN(d.elStartTop)) d.elStartTop = 2; document.addEventListener("mousemove", dragGo, true); document.addEventListener("mouseup", dragStop, true); event.preventDefault(); } } // drag handler for positioning the panel function dragGo(event) { var x, y; // Get cursor position with respect to the page. y = event.clientY + window.scrollY; //d.elNode.style.left = (d.elStartLeft + x - d.cursorStartX) + "px"; if ((d.elStartTop + y - d.cursorStartY)>=(dims.headerw? (dims.headert+16) : (dims.top+16)) && (d.elStartTop + y - d.cursorStartY)<(dims.height+(dims.headerw? (dims.headert+16) : (dims.top+16)))-height) { if ((d.elStartTop + y - d.cursorStartY)<=3) y = d.cursorStartY - d.elStartTop; d.cp.style.top = (d.elStartTop + y - d.cursorStartY) + "px"; if ((d.elStartTop + y - d.cursorStartY)>0) d.cp.setAttribute('style',setTopBorder(d.cp.getAttribute('style'))); else d.cp.setAttribute('style',removeTopBorder(d.cp.getAttribute('style'))); d.cph.style.top = (d.elStartTop + y - d.cursorStartY + d.baseH - 3) + "px"; savePos(d.elStartTop + y - d.cursorStartY); } event.preventDefault(); } // terminate dragging to position the panel function dragStop(event) { // Stop capturing mousemove and mouseup events. document.removeEventListener("mousemove", dragGo, true); document.removeEventListener("mouseup", dragStop, true); d = null; } // code to resize the panel function dragStartSize(event, id) { var cp = document.getElementById('chatcp'); var cph = document.getElementById('chatcp_handle'); if (cp && cph) { d = new Object(); d.cp = cp; d.cph = cph; var y = event.clientY + window.scrollY; d.baseH = getStyleAttr(cp.getAttribute('style'),'height'); d.baseO = getStyleAttr(cph.getAttribute('style'),'top'); // Save starting positions of cursor and element. d.cursorStartY = y; d.elStartLeft = parseInt(cp.style.left, 10); d.elStartTop = parseInt(cp.style.top, 10); if (isNaN(d.elStartLeft)) d.elStartLeft = 2; if (isNaN(d.elStartTop)) d.elStartTop = 2; document.addEventListener("mousemove", dragGoSize, true); document.addEventListener("mouseup", dragStopSize, true); event.preventDefault(); } } // create cp index i in table t with width w function newEntry(i,w,t) { var tr = document.createElement('tr'); tr.setAttribute('id','chatcp_index'+i); var td = document.createElement('td'); var i1 = document.createElement('input'); i1.setAttribute('type','button'); //i1.setAttribute('value','>'); //var arrow = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABEAAAAMCAYAAACEJVa/AAAAmklEQVQokaXSPQ5BURCG4YcNiGhUGpah0CpFQyOswUpElCLR24VFiJ8FqCQ6Ea7CkdwILseXvN3Mm5nJkJ0mFih8UftRcsIO9XdFuQyghBUSDJB/lky+YIwZrkE0RTEt2fzAOqyVYItyjCTNMcga/0guWKIm2GKYpW/SyaCLNkbhsAf0RaSFM/aoxAiG7uPPY5ofqaLnxYM9cgOSr1GycHbzaQAAAABJRU5ErkJggg=='; //i1.setAttribute('style','font-size:9px;width:22px;'); i1.setAttribute('style','background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABEAAAAMCAYAAACEJVa/AAAAmklEQVQokaXSPQ5BURCG4YcNiGhUGpah0CpFQyOswUpElCLR24VFiJ8FqCQ6Ea7CkdwILseXvN3Mm5nJkJ0mFih8UftRcsIO9XdFuQyghBUSDJB/lky+YIwZrkE0RTEt2fzAOqyVYItyjCTNMcga/0guWKIm2GKYpW/SyaCLNkbhsAf0RaSFM/aoxAiG7uPPY5ofqaLnxYM9cgOSr1GycHbzaQAAAABJRU5ErkJggg==");background-repeat: no-repeat;background-position: center;'); i1.setAttribute('cmdidx',i); i1.addEventListener('mouseup',bHandler,false); var i2 = document.createElement('input'); i2.setAttribute('type','text'); i2.setAttribute('width','128'); i2.setAttribute('value',((i>=ccmds.length)?'':ccmds[i])); i2.setAttribute('class','chatcp_text'); i2.setAttribute('style','font-size:9px;width:'+(w-22)+'px;height:13px;'); i2.setAttribute('cmdidx',i); i2.addEventListener('keyup',tHandler,true); i2.addEventListener('change',tHandler,true); td.appendChild(i1); td.appendChild(i2); tr.appendChild(td); t.appendChild(tr); } // update the interior of the panel during resizing function updateCPSize(h) { var bars = document.getElementsByClassName('chatcpbar'); for (var i=0;i<bars.length;i++) { var s = bars[i].getAttribute('style'); bars[i].setAttribute('style',replaceOrAddStyle(s,'height',(h-4)+'px')); } var last = heightUnit(h); var ins = document.getElementById('chatcp_index'+last); if (!ins) { // we must have an entry 0 var w = document.getElementById('chatcp_index0'); if (w) { var t = w.parentNode; w = getStyleAttr(w.firstChild.firstChild.nextSibling.getAttribute('style'),'width'); for (var i=1;i<last;i++) { ins = document.getElementById('chatcp_index'+i); if (!ins) { newEntry(i,(w+16),t); } } } } else { var del = document.getElementById('chatcp_index'+last); while (del) { del.parentNode.removeChild(del); last++; del = document.getElementById('chatcp_index'+last); } } saveHeight(h); } // drag handler for resizing the panel function dragGoSize(event) { var y; // Get cursor position with respect to the page. y = event.clientY + window.scrollY; var delta = y - d.cursorStartY; if (delta!=0) { var newh = d.baseH + delta; if (newh>unitHeight(1) && newh<(dims.height+(dims.headerw? (dims.headert+16) : (dims.top+16)))) { newh = unitHeight(heightUnit(newh)); delta = newh - d.baseH; d.cp.setAttribute('style',replaceOrAddStyle(d.cp.getAttribute('style'),'height',newh+'px')); d.cph.setAttribute('style',replaceOrAddStyle(d.cph.getAttribute('style'),'top',(d.baseO+delta)+'px')); updateCPSize(newh); } } event.preventDefault(); } // terminate dragging to resize the panel function dragStopSize(event) { // Stop capturing mousemove and mouseup events. document.removeEventListener("mousemove", dragGoSize, true); document.removeEventListener("mouseup", dragStopSize, true); d = null; } function getMaxDimensions() { var chats = document.getElementsByClassName('chatdisplay'); for (var i=0;i<chats.length;i++) { if (chats[i].style.display!='none') { var header = document.evaluate('.//div[@class="header"]',chats[i],null,XPathResult.FIRST_ORDERED_NODE_TYPE,null); dims = {top:Number(chats[i].style.top.replace(/[^0-9]+/,'')),width:Number(chats[i].clientWidth),height:Number(chats[i].style.height.replace(/[^0-9]+/,''))}; if (header.singleNodeValue) { dims.headert = Number(header.singleNodeValue.style.top.replace(/[^0-9]+/,'')); dims.headerw = Number(header.singleNodeValue.style.width.replace(/[^0-9]+/,'')); } //console.log('dimensions: top='+dims.top+', width='+dims.width+', height='+dims.height+', offw='+chats[i].offsetWidth+', cw='+chats[i].clientWidth); chats[i].addEventListener('scroll',setWidths,false); return; } } } function placeDockIcon(f) { var img=document.createElement('img'); img.setAttribute('src',"data:image/png,%89PNG%0D%0A%1A%0A%00%00%00%0DIHDR%00%00%00%0E%00%00%00%0C%08%06%00%00%00R%80%8C%DA%00%00%00%01sRGB%00%AE%CE%1C%E9%00%00%00%06bKGD%00%00%00%00%00%00%F9C%BB%7F%00%00%00%09pHYs%00%00%0B%13%00%00%0B%13%01%00%9A%9C%18%00%00%00%07tIME%07%DC%03%1E%14)%06%E8D%1D%FA%00%00%00%19tEXtComment%00Created%20with%20GIMPW%81%0E%17%00%00%00%5BIDAT(%CF%ED%8F%A1%11%C0%20%10%04%97L%8Ay%85%A0%8F%EF%80b%9E%8EPt%81%A7%10%FC%23%A228TD%D6%9C%DA%99%DB%E0%EE%CE%017%40%CE%99Z%2BsNJ)%00%98%19%00)%A5M%EA%BD%3Fb%8C%91%D6%1A%00%AA%FA%DA1%06%22%B2%C9%E1%F4%EA%C5!%7F%E3%A7%1A%17%CC%8BJ%7F%13%D8%1D%F7%00%00%00%00IEND%AEB%60%82"); if (dims.headerw) img.setAttribute('style','position:absolute;top:'+(dims.headert+1)+'px;left:'+(dims.headerw-15)+'px;z-index:7;'); else img.setAttribute('style','position:absolute;top:'+(dims.top+2)+'px;left:'+(dims.width-15)+'px;z-index:7;'); img.setAttribute('title','Click to toggle display of chat control panel.'); img.setAttribute('id','chatcp_dock'); img.addEventListener('click',rollHandler,false); f.parentNode.insertBefore(img,f); } function initialize() { getMaxDimensions(); if (dims) { addPanel(); } } setTimeout(initialize,50);