diff --git a/Plugins/MessageUtilities/MessageUtilities.plugin.js b/Plugins/MessageUtilities/MessageUtilities.plugin.js index 296410cb8a..1108f9c18b 100644 --- a/Plugins/MessageUtilities/MessageUtilities.plugin.js +++ b/Plugins/MessageUtilities/MessageUtilities.plugin.js @@ -3,7 +3,7 @@ class MessageUtilities { getName () {return "MessageUtilities";} - getVersion () {return "1.5.6";} + getVersion () {return "1.5.7";} getAuthor () {return "DevilBro";} @@ -11,9 +11,12 @@ class MessageUtilities { constructor () { this.changelog = { - "fixed":[["Double Click Delay","Delay on couble click was fixed"]], - "added":[["New Options","Copy raw message content & Copy message link"],["Toasts","You can enable/disable toasts for native actions"]], - "improved":[["Priorities","Hotkey+Click combos now got priorities, a double click has a higher priority than a single click & an action with two keys set has a high priority than an action with one key, this allows actions to be set for example to (1. Ctrl + Click and 2. Ctrl + D + Click) without executing both when Ctrl + D + Click is pressed, same goes for double clicks"]] + "improved":[["Delays","A delay is need to cancel the single click event in case a double click follows, the plugin now checks if an action with a double click might overwrite a single click (happens if they share the same keys), if this is not the case the plugin will trigger the single click action without delay now"]], + "added":[["Context Hints", "Added hints to native contextmenu items, hints can now be disabled in the settings"],["Toasts","You can enable/disable toasts for native actions"]] + }; + + this.patchModules = { + "MessageContextMenu":["componentDidMount","componentDidUpdate"] }; } @@ -28,10 +31,10 @@ class MessageUtilities { "NONE" /*[0]*/, "" /*[1]*/, "" /*[2]*/, "CANCEL" /*[3]*/, "" /*[4]*/, "" /*[5]*/, "HELP" /*[6]*/, "" /*[7]*/, "BACK_SPACE" /*[8]*/, "TAB" /*[9]*/, "" /*[10]*/, "" /*[11]*/, "CLEAR" /*[12]*/, "ENTER" /*[13]*/, "ENTER_SPECIAL" /*[14]*/, "" /*[15]*/, "SHIFT" /*[16]*/, "CONTROL" /*[17]*/, "ALT" /*[18]*/, "PAUSE" /*[19]*/, "CAPS_LOCK" /*[20]*/, "KANA" /*[21]*/, "EISU" /*[22]*/, "JUNJA" /*[23]*/, "FINAL" /*[24]*/, "HANJA" /*[25]*/, "" /*[26]*/, "ESCAPE" /*[27]*/, "CONVERT" /*[28]*/, "NONCONVERT" /*[29]*/, "ACCEPT" /*[30]*/, "MODECHANGE" /*[31]*/, "SPACE" /*[32]*/, "PAGE_UP" /*[33]*/, "PAGE_DOWN" /*[34]*/, "END" /*[35]*/, "HOME" /*[36]*/, "LEFT" /*[37]*/, "UP" /*[38]*/, "RIGHT" /*[39]*/, "DOWN" /*[40]*/, "SELECT" /*[41]*/, "PRINT" /*[42]*/, "EXECUTE" /*[43]*/, "PRINTSCREEN" /*[44]*/, "INSERT" /*[45]*/, "DELETE" /*[46]*/, "" /*[47]*/,"0" /*[48]*/, "1" /*[49]*/, "2" /*[50]*/, "3" /*[51]*/, "4" /*[52]*/, "5" /*[53]*/, "6" /*[54]*/, "7" /*[55]*/, "8" /*[56]*/, "9" /*[57]*/, "COLON" /*[58]*/, "SEMICOLON" /*[59]*/, "LESS_THAN" /*[60]*/, "EQUALS" /*[61]*/, "GREATER_THAN" /*[62]*/, "QUESTION_MARK" /*[63]*/, "AT" /*[64]*/, "A" /*[65]*/, "B" /*[66]*/, "C" /*[67]*/, "D" /*[68]*/, "E" /*[69]*/, "F" /*[70]*/, "G" /*[71]*/, "H" /*[72]*/, "I" /*[73]*/, "J" /*[74]*/, "K" /*[75]*/, "L" /*[76]*/, "M" /*[77]*/, "N" /*[78]*/, "O" /*[79]*/, "P" /*[80]*/, "Q" /*[81]*/, "R" /*[82]*/, "S" /*[83]*/, "T" /*[84]*/, "U" /*[85]*/, "V" /*[86]*/, "W" /*[87]*/, "X" /*[88]*/, "Y" /*[89]*/, "Z" /*[90]*/, "OS_KEY" /*[91]*/, "" /*[92]*/, "CONTEXT_MENU" /*[93]*/, "" /*[94]*/, "SLEEP" /*[95]*/, "NUMPAD0" /*[96]*/, "NUMPAD1" /*[97]*/, "NUMPAD2" /*[98]*/, "NUMPAD3" /*[99]*/, "NUMPAD4" /*[100]*/, "NUMPAD5" /*[101]*/, "NUMPAD6" /*[102]*/, "NUMPAD7" /*[103]*/, "NUMPAD8" /*[104]*/, "NUMPAD9" /*[105]*/, "MULTIPLY" /*[106]*/, "ADD" /*[107]*/, "SEPARATOR" /*[108]*/, "SUBTRACT" /*[109]*/, "DECIMAL" /*[110]*/, "DIVIDE" /*[111]*/, "F1" /*[112]*/, "F2" /*[113]*/, "F3" /*[114]*/, "F4" /*[115]*/, "F5" /*[116]*/, "F6" /*[117]*/, "F7" /*[118]*/, "F8" /*[119]*/, "F9" /*[120]*/, "F10" /*[121]*/, "F11" /*[122]*/, "F12" /*[123]*/, "F13" /*[124]*/, "F14" /*[125]*/, "F15" /*[126]*/, "F16" /*[127]*/, "F17" /*[128]*/, "F18" /*[129]*/, "F19" /*[130]*/, "F20" /*[131]*/, "F21" /*[132]*/, "F22" /*[133]*/, "F23" /*[134]*/, "F24" /*[135]*/, "" /*[136]*/, "" /*[137]*/, "" /*[138]*/, "" /*[139]*/, "" /*[140]*/, "" /*[141]*/, "" /*[142]*/, "" /*[143]*/, "NUM_LOCK" /*[144]*/, "SCROLL_LOCK" /*[145]*/, "WIN_OEM_FJ_JISHO" /*[146]*/, "WIN_OEM_FJ_MASSHOU" /*[147]*/, "WIN_OEM_FJ_TOUROKU" /*[148]*/, "WIN_OEM_FJ_LOYA" /*[149]*/, "WIN_OEM_FJ_ROYA" /*[150]*/, "" /*[151]*/, "" /*[152]*/, "" /*[153]*/, "" /*[154]*/, "" /*[155]*/, "" /*[156]*/, "" /*[157]*/, "" /*[158]*/, "" /*[159]*/, "CIRCUMFLEX" /*[160]*/, "EXCLAMATION" /*[161]*/, "DOUBLE_QUOTE" /*[162]*/, "HASH" /*[163]*/, "DOLLAR" /*[164]*/, "PERCENT" /*[165]*/, "AMPERSAND" /*[166]*/, "UNDERSCORE" /*[167]*/, "OPEN_PAREN" /*[168]*/, "CLOSE_PAREN" /*[169]*/, "ASTERISK" /*[170]*/, "PLUS" /*[171]*/, "PIPE" /*[172]*/, "HYPHEN_MINUS" /*[173]*/, "OPEN_CURLY_BRACKET" /*[174]*/, "CLOSE_CURLY_BRACKET" /*[175]*/, "TILDE" /*[176]*/, "" /*[177]*/, "" /*[178]*/, "" /*[179]*/, "" /*[180]*/, "VOLUME_MUTE" /*[181]*/, "VOLUME_DOWN" /*[182]*/, "VOLUME_UP" /*[183]*/, "" /*[184]*/, "" /*[185]*/, "SEMICOLON" /*[186]*/, "EQUALS" /*[187]*/, "COMMA" /*[188]*/, "MINUS" /*[189]*/, "PERIOD" /*[190]*/, "SLASH" /*[191]*/, "BACK_QUOTE" /*[192]*/, "" /*[193]*/, "" /*[194]*/, "" /*[195]*/, "" /*[196]*/, "" /*[197]*/, "" /*[198]*/, "" /*[199]*/, "" /*[200]*/, "" /*[201]*/, "" /*[202]*/, "" /*[203]*/, "" /*[204]*/, "" /*[205]*/, "" /*[206]*/, "" /*[207]*/, "" /*[208]*/, "" /*[209]*/, "" /*[210]*/, "" /*[211]*/, "" /*[212]*/, "" /*[213]*/, "" /*[214]*/, "" /*[215]*/, "" /*[216]*/, "" /*[217]*/, "" /*[218]*/, "OPEN_BRACKET" /*[219]*/, "BACK_SLASH" /*[220]*/, "CLOSE_BRACKET" /*[221]*/, "QUOTE" /*[222]*/, "" /*[223]*/, "META" /*[224]*/, "ALTGR" /*[225]*/, "" /*[226]*/, "WIN_ICO_HELP" /*[227]*/, "WIN_ICO_00" /*[228]*/, "" /*[229]*/, "WIN_ICO_CLEAR" /*[230]*/, "" /*[231]*/,"" /*[232]*/, "WIN_OEM_RESET" /*[233]*/, "WIN_OEM_JUMP" /*[234]*/, "WIN_OEM_PA1" /*[235]*/, "WIN_OEM_PA2" /*[236]*/, "WIN_OEM_PA3" /*[237]*/, "WIN_OEM_WSCTRL" /*[238]*/,"WIN_OEM_CUSEL" /*[239]*/, "WIN_OEM_ATTN" /*[240]*/, "WIN_OEM_FINISH" /*[241]*/, "WIN_OEM_COPY" /*[242]*/, "WIN_OEM_AUTO" /*[243]*/, "WIN_OEM_ENLW" /*[244]*/, "WIN_OEM_BACKTAB" /*[245]*/, "ATTN" /*[246]*/, "CRSEL" /*[247]*/, "EXSEL" /*[248]*/, "EREOF" /*[249]*/, "PLAY" /*[250]*/, "ZOOM" /*[251]*/, "" /*[252]*/, "PA1" /*[253]*/, "WIN_OEM_CLEAR" /*[254]*/, "" /*[255]*/ ]; - this.clicks = ["click"]; this.keys = ["key1","key2"]; this.defaults = { settings: { + "addHints": {value:true, description:"Add keycombo hints to contextmenus:"}, "clearOnEscape": {value:true, description:"Clear chat input when Escape is pressed:"} }, toasts: {}, @@ -69,9 +72,7 @@ class MessageUtilities { if (!this.defaults.bindings[action].plugin || BDFDB.isPluginEnabled(this.defaults.bindings[action].plugin)) { settingshtml += `
`; settingshtml += `

${this.defaults.bindings[action].name}:

${toasts[action] != undefined ? `
Toast:
` : ''}
Enabled:
`; - for (let click of this.clicks) { - settingshtml += `
${click}:
${BDFDB.createSelectMenu(this.createSelectChoice(bindings[action][click]), bindings[action][click], action + " " + click)}
`; - } + settingshtml += `
Click:
${BDFDB.createSelectMenu(this.createSelectChoice(bindings[action].click), bindings[action].click, action + " click")}
`; for (let key of this.keys) { settingshtml += `
${key}:
`; } @@ -135,20 +136,14 @@ class MessageUtilities { if (this.started) return; BDFDB.loadMessage(this); - let clickTimeout; BDFDB.addEventListener(this, document, "click", BDFDB.dotCN.messagegroup + "> [aria-disabled]," + BDFDB.dotCN.messagegroup + "> * > [aria-disabled]," + BDFDB.dotCN.messagesystem, e => { - clearTimeout(clickTimeout); - let keys = [].concat(BDFDB.pressedKeys); - clickTimeout = setTimeout(() => { - this.onClick(e, 0, keys, "onSglClick"); - }, 500); + this.onClick(e, 0, "onSglClick"); }) BDFDB.addEventListener(this, document, "dblclick", BDFDB.dotCN.messagegroup + "> [aria-disabled]," + BDFDB.dotCN.messagegroup + "> * > [aria-disabled]," + BDFDB.dotCN.messagesystem, e => { - clearTimeout(clickTimeout); - this.onClick(e, 1, BDFDB.pressedKeys, "onDblClick"); + this.onClick(e, 1, "onDblClick"); }); BDFDB.addEventListener(this, document, "keydown", BDFDB.dotCN.textareawrapchat, e => { - this.onKeyDown(e, e.which, BDFDB.pressedKeys, "onKeyDown"); + this.onKeyDown(e, e.which, "onKeyDown"); }); } else { @@ -164,6 +159,39 @@ class MessageUtilities { //begin of own functions + + processMessageContextMenu (instance, menu, returnvalue) { + if (instance.props && instance.props.message && instance.props.channel && instance.props.target) { + let changed = false; + for (let itemlabel of menu.querySelectorAll(BDFDB.dotCN.contextmenulabel)) { + let action = null; + switch (itemlabel.innerText) { + case BDFDB.LanguageStrings.COPY_MESSAGE_LINK: + action = "Copy_Link"; + break; + case BDFDB.LanguageStrings.EDIT_MESSAGE: + action = "Edit_Message"; + break; + case BDFDB.LanguageStrings.PIN_MESSAGE: + case BDFDB.LanguageStrings.UNPIN_MESSAGE: + action = "Pin/Unpin_Message"; + break; + case BDFDB.LanguageStrings.DELETE_MESSAGE: + action = "Delete_Message"; + break; + } + if (action) { + let hintlabel = this.getActiveShortcutString(action); + if (hintlabel) { + changed = true; + BDFDB.addClass(itemlabel.nextElementSibling, "BDFDB-contextMenuItemHint"); + BDFDB.setInnerText(itemlabel.nextElementSibling, hintlabel); + } + } + } + if (changed) BDFDB.initElements(menu); + } + } resetAll (settingspanel) { BDFDB.openConfirmModal(this, "Are you sure you want to delete all key bindings?", () => { @@ -246,7 +274,7 @@ class MessageUtilities { BDFDB.saveData(action, binding, this, "bindings"); } - onClick (e, click, keys, name) { + onClick (e, click, name) { if (!this.isEventFired(name)) { this.fireEvent(name); let settings = BDFDB.getAllData(this, "settings"); @@ -255,26 +283,44 @@ class MessageUtilities { for (let action in bindings) { let binding = bindings[action]; let prioritybinding = bindings[priorityaction]; - if (this.checkIfBindingIsValid(binding, click, keys) && (!bindings[priorityaction] || binding.click > prioritybinding.click || binding.key2 != 0 && prioritybinding.key2 == 0)) priorityaction = action; + if (this.checkIfBindingIsValid(binding, click) && (!bindings[priorityaction] || binding.click > prioritybinding.click || binding.key2 != 0 && prioritybinding.key2 == 0)) priorityaction = action; } if (priorityaction) { let {messagediv, pos, message} = this.getMessageData(e.currentTarget); if (messagediv && pos > -1 && message) { BDFDB.stopEvent(e); - this.defaults.bindings[priorityaction].func.bind(this)({messagediv, pos, message}, priorityaction); + clearTimeout(this.clickTimeout); + if (!this.hasDoubleClickOverwrite(bindings, bindings[priorityaction])) { + this.defaults.bindings[priorityaction].func.bind(this)({messagediv, pos, message}, priorityaction); + } + else this.clickTimeout = setTimeout(() => { + this.defaults.bindings[priorityaction].func.bind(this)({messagediv, pos, message}, priorityaction); + }, 500); } } this.cancelEvent(name); } } - checkIfBindingIsValid (binding, doneclick, keys) { + checkIfBindingIsValid (binding, doneclick) { let valid = true; - for (let click of this.clicks) if (binding[click] != doneclick) valid = false; - for (let key of this.keys) if (!keys.includes(binding[key]) && binding[key] != 0) valid = false; + if (binding.click != doneclick) valid = false; + for (let key of this.keys) if (!BDFDB.pressedKeys.includes(binding[key]) && binding[key] != 0) valid = false; return valid; } + hasDoubleClickOverwrite (bindings, binding) { + if (binding.click == 1) return false; + let dblbindings = BDFDB.filterObject(bindings, bndg => {return bndg.click == 1}); + for (let dblaction in dblbindings) { + let dblbndg = dblbindings[dblaction]; + let overwrite = true; + for (let key of this.keys) if (binding[key] != dblbndg[key]) overwrite = false; + if (overwrite) return true; + } + return false; + } + doDelete ({messagediv, pos, message}, action) { let deletelink = messagediv.parentElement.querySelector(BDFDB.dotCNS.messagelocalbotmessage + BDFDB.dotCN.anchor); if (deletelink) deletelink.click(); @@ -356,7 +402,6 @@ class MessageUtilities { doCitate ({messagediv, pos, message}, action) { if (BDFDB.isPluginEnabled(this.defaults.bindings.__Citate_Message.plugin)) { - console.log(messagediv.parentElement); let citarButton = messagediv.parentElement.querySelector(".citar-btn"); if (citarButton) citarButton.click(); } @@ -380,11 +425,12 @@ class MessageUtilities { } getActiveShortcutString (action) { - let str = ""; - if (BDFDB.getData(action, this, "settings")) { + if (!action) return null; + let str = "", settings = BDFDB.getAllData(this, "settings"); + if (settings.addHints && settings[action]) { let binding = BDFDB.getData(action, this, "bindings"); if (binding) for (let type in binding) { - let typename = type.indexOf("click") == 0 ? this.clickMap[binding[type]] : this.keyboardMap[binding[type]]; + let typename = type == "click" ? this.clickMap[binding[type]] : this.keyboardMap[binding[type]]; if (typename && typename != "NONE") str += typename + "+"; } } @@ -408,6 +454,6 @@ class MessageUtilities { } cancelEvent (name) { - setTimeout(() => {BDFDB.removeFromArray(this.firedEvents, name)}, 1000); + setImmediate(() => {BDFDB.removeFromArray(this.firedEvents, name)}); } }