Skip to content

Instantly share code, notes, and snippets.

@Pmmlabs
Last active October 24, 2019 03:55
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Pmmlabs/fe2b34d6a877719bdfca to your computer and use it in GitHub Desktop.
Save Pmmlabs/fe2b34d6a877719bdfca to your computer and use it in GitHub Desktop.
Плагин для VkOpt, добавляющий возможность форматирования текста в диалогах (жирный,курсив,зачеркнутый)
// ==UserScript==
// @id font@vkopt
// @name Font for VkOpt
// @version 1.0
// @namespace https://greasyfork.org/users/23
// @author Pmmlabs@github
// @description Плагин для VkOpt, добавляющий возможность форматирования текста в диалогах (жирный,курсив,зачеркнутый)
// @include *vk.com*
// @run-at document-end
// @noframes
// @grant none
// ==/UserScript==
if (!window.vkopt_plugins) vkopt_plugins = {};
(function () {
var PLUGIN_ID = 'TextFormat';
vkopt_plugins[PLUGIN_ID] = {
Name: 'Text Formatting',
css:'d:after {content: "́";}',
el_id: 'vk_format_panel', // id элемента с кнопками. Нужен только для предотвращения повторной вставки.
masks: {
U: 1,
B: 2,
I: 4,
D: 8,
S: 16
},
// ФУНКЦИИ
onLocation: function (nav_obj, cur_module_name) { // событие "при переходе в Диалоги"
if (cur_module_name == 'im' && !nav_obj.w && !ge(this.el_id))
this.UI();
},
UI: function(){ // Добавление кнопок форматирования
var parent = ge('im_texts'); // контейнер, содержащий текстовое поле и кнопки; сюда будем вставлять (в начало)
var main=vkCe('div',{id:this.el_id}); // панелька с кнопками форматирования
var B = vkCe('input',{type:"button", value:'𝗕','class':'im_rc_emojibtn'}); // тег input обязателен, с другим получаем не то выделение
B.onclick = function(){vkopt_plugins[PLUGIN_ID].onclick('b');};
var U = vkCe('input',{type:"button", value:'U̲','class':'im_rc_emojibtn'});
U.onclick = function(){vkopt_plugins[PLUGIN_ID].onclick('u');};
var I = vkCe('input',{type:"button", value:'𝘐','class':'im_rc_emojibtn'});
I.onclick = function(){vkopt_plugins[PLUGIN_ID].onclick('i');};
var D = vkCe('input',{type:"button", value:'у́','class':'im_rc_emojibtn'}); // ударение
D.onclick = function(){vkopt_plugins[PLUGIN_ID].onclick('d');};
var S = vkCe('input',{type:"button", value:'S̶','class':'im_rc_emojibtn'});
S.onclick = function(){vkopt_plugins[PLUGIN_ID].onclick('s');};
main.appendChild(B);
main.appendChild(U);
main.appendChild(I);
main.appendChild(D);
main.appendChild(S);
parent.insertBefore(main, parent.firstChild);
},
onclick: function(tag){ // обработчик нажатия на кнопку форматирования. tag - строка, тег, которым будем оборачивать выделенный текст
var selection = window.getSelection().getRangeAt(0);
selection.insertNode(vkCe(tag,{},selection.extractContents().textContent));
},
onLibFiles: function (file_name) { // событие "при подгрузке im.js"
if (file_name == 'im.js')
Inj.Before('IM.send', 'if (progressNode', "vkopt_plugins['" + PLUGIN_ID + "'].process(txt);");
},
process: function (content,parents) { // Замена HTML-разметки в контейнере content на соответствующие Unicode-последовательности
var russianBold = { // не хватает: Б,Ж,И,Ц,Ч,Ш,Щ,Ы,Ъ,Э,Ю,Я,г,д,ж,з,и,л,м,н,ц,ч,щ,ш,ь,ы,ъ,э,ю,я
'А': '𝚨',
'В': '𝚩',
'Г': '𝚪',
'Д': '𝚫',
'Е': '𝚬',
'Ё': '𝚬',
'З': '𝟯',
'К': '𝚱',
'Л': '𝚲',
'М': '𝚳',
'Н': '𝚮',
'О': '𝚶',
'П': '𝚷',
'Р': '𝚸',
'С': '𝗖',
'Т': '𝚻',
'У': 'Ꭹ',
'Ф': '𝚽',
'Х': '𝚾',
'Ь': 'Ꮟ', ////
'а': '𝗮',
'б': '𝛅',
'в': '𝛃',
'е': '𝗲',
'ё': '𝗲',
'к': '𝛋',
'о': '𝗼',
'п': '𝛑',
'р': '𝗽',
'с': '𝗰',
'т': '𝛕',
'у': '𝛄',
'ф': '𝛟',
'х': '𝘅'
};
var russianItalic = {// не хватает: Б,Ж,И,Ц,Ч,Ш,Щ,Ы,Ъ,Э,Ю,Я,г,ж,з,л,м,н,ц,ч,щ,ь,ы,ъ,э,ю,я
'А': '𝛢',
'В': '𝛣',
'Г': '𝛤',
'Д': '𝛥',
'Е': '𝛦',
'Ё': '𝛦',
'К': '𝛫',
'Л': '𝛬',
'М': '𝛭',
'Н': '𝛨',
'О': '𝛰',
'П': '𝛱',
'Р': '𝛲',
'С': '𝘊',
'Т': '𝛵',
'У': 'Ꭹ',
'Ф': '𝛷',
'Х': '𝛸',
'а': '𝘢',
'б': '𝛿',
'в': '𝛽',
'д': '𝜕',
'е': '𝘦',
'ё': '𝘦',
'и': 'ⴎ',
'к': '𝜅',
'о': '𝘰',
'п': 'ⴖ',
'р': '𝘱',
'с': '𝘤',
'т': '𝜏',
'у': 'ⴘ',
'ф': '𝜙',
'х': '𝘹',
'ш': 'ⴍ'
};
var accum = '';
var el = content.firstChild;
while (el) { // цикл по всем дочерним элементам
switch (el.nodeType) {
case 3: // Text Node
var text = el.innerText;
if (parents & this.masks.U) // Подчеркнутый
text = text.replace(/(.)/g, '͟$1');
if (parents & this.masks.S) // Зачеркнутый
text = text.replace(/(.)/g, '⃪$1̵');
if (parents & this.masks.D) // Ударение. Ставим только на последний символ.
text = text.replace(/(.)$/, '$1́');
// замена английских букв на буквы из блока Mathematical Alphanumeric Symbols
if (parents & this.masks.B && parents & this.masks.I) // жирный курсив
text = text.replace(/(.)/g, function (char) {
if (char >= 'A' && char <= 'Z')
return String.fromCodePoint(char.codePointAt(0) + 120315);
if (char >= 'a' && char <= 'z')
return String.fromCodePoint(char.codePointAt(0) + 120309);
if (char >= '0' && char <= '9')
return String.fromCodePoint(char.codePointAt(0) + 120734); // просто жирный с засечками
return char;
});
else if (parents & this.masks.B) // просто жирный
text = text.replace(/(.)/g, function (char) {
if (char >= 'A' && char <= 'Z')
return String.fromCodePoint(char.codePointAt(0) + 120211);
if (char >= 'a' && char <= 'z')
return String.fromCodePoint(char.codePointAt(0) + 120205);
if (char >= '0' && char <= '9')
return String.fromCodePoint(char.codePointAt(0) + 120764);
if (char >= 'А' && char <= 'я' || char=='Ё' || char=='ё')
return russianBold[char] || char;
return char;
});
else if (parents & this.masks.I) // просто курсив
text = text.replace(/(.)/g, function (char) {
if (char >= 'A' && char <= 'Z')
return String.fromCodePoint(char.codePointAt(0) + 120263);
if (char >= 'a' && char <= 'z')
return String.fromCodePoint(char.codePointAt(0) + 120257);
if (char >= '0' && char <= '9')
return String.fromCodePoint(char.codePointAt(0) + 65248); // моноширинный
if (char >= 'А' && char <= 'я' || char=='Ё' || char=='ё')
return russianItalic[char] || char;
return char;
});
accum += text;
case 1: // Element Node
accum += this.process(el,(parents || 0) + this.masks[el.tagName]); // рекурсивная обработка вложенных тегов
break;
}
el = el.nextSibling;
}
if (content.tagName == 'DIV') // случай первого уровня рекурсии, когда content - поле ввода сообщения.
content.innerHTML = accum; // подменяем в нём текст на наш сгенерированный
else
return accum; // случай обработки внутри какого-то тега
}
};
if (window.vkopt_ready) vkopt_plugin_run(PLUGIN_ID);
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment