绯月表情增强插件

KF论坛专用的回复表情, 插图扩展插件, 在发帖时快速输入自定义表情和论坛BBCODE

当前为 2017-01-26 提交的版本,查看 最新版本

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name       绯月表情增强插件
// @namespace   https://greasyfork.org/users/5415
// @version     4.2.0
// @author      eddie32
// @description KF论坛专用的回复表情, 插图扩展插件, 在发帖时快速输入自定义表情和论坛BBCODE
// @icon        https://blog.nekohand.moe/favicon.ico
// @homepage    https://github.com/liu599/KF-Emotion-UserScript
// @include     https://*miaola.info/*
// @include     http://*2dkf.com/*
// @include     http://*9moe.com/*
// @include     http://*kfgal.com/*
// @copyright   2014-2017, eddie32
// @grant       none
// @license     MIT
// @run-at      document-end
// ==/UserScript==

/* *
 * *  KF Emotion UserScript
 * *  Author: eddie32
 * *  Version: 4.2.0
 * *  Change Log: Rewrite the code based on ES6 recommodation
 * *  Add hover:enlarge feature
 * *  User option storage locally
 * *  License: M.I.T
 * *  Publish Date: 2017.01.28
 * */

'use strict';
const versionNo = '4.2.0';


/*Address function
 * startNumber: number, indicating the start number;
 * lengthArray: number, indicating the addrArray length;
 * strPrefix: string, address Prefix;
 * strSuffix: string, address Suffix;
 * leadingZero: boolen, true for leading zero in number;
 * addrArray: array, address array, default for empty;
*/

// 创建表情包数组的函数
function emAddrArrayHandler(startNumber, lengthArray, strPrefix, strSuffix,  addrArray = [], leadingZero = false){
   let addrTemp = '', addrNumber = 0;
   for(let j=startNumber;j<lengthArray;j++){
     addrNumber = j;
     if(leadingZero){
        addrNumber = (j>9)?(j):(`0${j}`);
     }
     addrTemp = `${strPrefix}${addrNumber}${strSuffix}`;
     addrArray.push(addrTemp);
   }
   return addrArray;
}
/* 表情包地址数据 */
// B站
let biliEM = emAddrArrayHandler(1, 17,'http://smile.nekohand.moe/blogAcc/LoveliveEmotion01/EmCol/BiliBili/2233 (',
                ').gif');
emAddrArrayHandler(0, 14,'http://smile.nekohand.moe/blogAcc/LoveliveEmotion01/EmCol/BiliBili/bilibiliTV (',
                                ').png',biliEM);
// tora酱
emAddrArrayHandler(1, 14,'http://smile.nekohand.moe/blogAcc/LoveliveEmotion01/EmCol/tora/0',
                            '.jpg',biliEM,true);
//阿卡林 from 摇曳百合
let AkariSmile = emAddrArrayHandler(1,21,'http://smile.nekohand.moe/blogAcc/LoveliveEmotion01/EmCol/Dynamic/akari','.gif');
emAddrArrayHandler(1,72,'http://smile.nekohand.moe/blogAcc/LoveliveEmotion01/EmCol/akari/akari','.png',AkariSmile);
// New Game kf扩展
let NewGame = emAddrArrayHandler(2,64,'http://nekohand.moe/spsmile/01Sora/0xx','.png');
emAddrArrayHandler(1,20,'http://ss.nekohand.moe/Asource/EmotionPic/KFEM (',').gif', NewGame);
// ACFUN
let ACSmile4 = emAddrArrayHandler(1,51,'http://smile.nekohand.moe/blogAcc/LoveliveEmotion01/EmCol/ACFUN/New/','.png');
emAddrArrayHandler(1,40,'http://smile.nekohand.moe/blogAcc/LoveliveEmotion01/EmCol/ACFUN/Niming/','.gif',ACSmile4,true);
// KF 内置
let KFSmileURL = emAddrArrayHandler(1,49,`${typeof imgpath != 'undefined' ? imgpath : ''}/post/smile/em/em`,
                                     '.gif',[],true);
let KFSmileCode = emAddrArrayHandler(10,58,`[s:`,
                                    ']');
// lovelive专用小
let LoveliveSmalltargetURL = emAddrArrayHandler(1,41,'http://smile.nekohand.moe/blogAcc/LoveliveEmotion02/Small/Lovelive2nd',
                                      '.png');
    emAddrArrayHandler(1,41,'http://smile.nekohand.moe/blogAcc/LoveliveEmotion01/Small/Lovelive',
                                                                            '.png',LoveliveSmalltargetURL);
// kf快捷代码(需要改写解构赋值)
let functionDescription = ['出售贴sell=售价','引用', '隐藏hide=神秘等级','插入代码','删除线','跑马灯','文字颜色','粗体',
                                '下划线','斜体','水平线','背景色','插入图片'];
let defaultFunction = ['[sell=100][/sell]','[quote][/quote]','[hide=100][/hide]','[code][/code]',
                        '[strike][/strike]','[fly][/fly]','[color=#00FF00][/color]','[b][/b]','[u][/u]','[i][/i]',
                        '[hr]', '[backcolor=][/backcolor]','[img][/img]'];
// 颜文字
let emoji = ['(●・ 8 ・●)',
'╰(๑◕ ▽ ◕๑)╯','(ゝω・)','〜♪♪','(゚Д゚≡゚Д゚)', '(^o^)ノ' , '(|||゚Д゚)', '(`ε´ )',  '(╬゚д゚)', '(|||゚д゚)' , '( ̄∇ ̄)', '( ̄3 ̄)', '( ̄ー ̄)', '( ̄ .  ̄)', '( ̄︿ ̄)', '( ̄︶ ̄)', '(*´ω`*)', '(・ω・)','(⌒▽⌒)','( ̄▽ ̄)','(=・ω・=)','(`・ω・´)','(〜 ̄△ ̄)〜','(・∀・)',
  '(°∀°)ノ','( ̄3 ̄)','╮( ̄▽ ̄)╭','( ´_ゝ`)','のヮの','(ノ؂< ๑)诶嘿☆~','(&lt;_&lt;)','(&gt;_&gt;)','(;¬_¬)','(▔□▔)/','(゚Д゚≡゚д゚)!?','Σ(゚д゚;)','Σ(  ̄□ ̄||)',
  '(´;ω;`)','(/TДT)/','(^・ω・^ )','(。・ω・。)','(● ̄(エ) ̄●)','ε=ε=(ノ≧∇≦)ノ','(´・_・`)','(-_-#)','( ̄へ ̄)','( ̄ε(# ̄) Σ','ヽ(`Д´)ノ','(╯°口°)╯(┴—┴','(#-_-)┯━┯','_(:3」∠)_','(笑)','(汗)','(泣)','(苦笑)', '(´・ω・`)', '(╯°□°)╯︵ ┻━┻','(╯‵□′)╯︵┻━┻', '( ´ρ`)', '( ゚ω゚)', '(o゚ω゚o)', '( ^ω^)', '(。◕∀◕。)', '/( ◕‿‿◕ )\\','ε٩( º∀º )۶з','( ̄ε(# ̄)☆╰╮( ̄▽ ̄///)',
                     '(●´3`)~♪', '_(:з」∠)_','хорошо!','\(^o^)/','(•̅灬•̅ )', '(゚Д゚)','まったく、小学生は最高だぜ!!','ε=ε=ε=┏(゜ロ゜;)┛',
                    '(;°ほ°)','	⎝≧⏝⏝≦⎠','ヽ(✿゚▽゚)ノ','焔に舞い上がるスパークよ、邪悪な異性交際に、天罰を与え!','|•ω•`)'];


let MenuList = {
    item4:{datatype:'imageLink', title:'固有',addr:KFSmileURL, ref:KFSmileCode},
    item1:{datatype:'plain',title:'快捷',addr:defaultFunction, ref:functionDescription},
    item2:{datatype:'plain',title:'颜文字', addr:emoji},
    item5:{datatype:'image',title:'ACFUN',addr:ACSmile4},
    item6:{datatype:'image',title:'常用',addr:NewGame},  //
    item7:{datatype:'image',title:'Akari',addr:AkariSmile}, //Akari
    item8:{datatype:'image',title:'BiliBili',addr:biliEM}, //B站
    item3:{datatype:'image',title:'LoveLive',addr:LoveliveSmalltargetURL}
};

/* Event 函数 */
const EventUtil = {
    getEvent: function(event){
        return event ? event : window.event;
    },
    getTarget: function(event){
        return event.target || event.srcElement;
    },
    preventDefault: function(event){
        if (event.preventDefault){
            event.preventDefault();
        } else {
            event.returnValue = false;
        }
    },
    stopPropagation: function(event){
        if (event.stopPropagation){
            event.stopPropagation();
        } else {
            event.cancelBubble = true;
        }
    },
    addHandler: function(element, type, handler){
        if (element.addEventListener){
            element.addEventListener(type, handler, false);  //DOM2
        } else if (element.attachEvent){
            element.attachEvent('on' + type, handler);  //IE
        } else {
            element['on' + type] = handler;  //DOM 0
        }
    },
    removeHandler: function(element, type, handler){
        if (element.removeEventListener){
            element.removeEventListener(type, handler, false); //DOM2
        } else if (element.detachEvent){
            element.detachEvent('on' + type, handler); //IE
        } else {
            element['on' + type] = null; //DOM 0
        }
    }
};
/*Element 函数*/
const EleUtil = {
    create: function(ele){
        return document.createElement(ele);
    },
    selectID: function(ele){
        return document.getElementById(ele);
    },
    select: function(selector){
        return document.querySelector(selector);
    }
};

/*Cookie处理*/
const CookieUtil = {
    getCookies: function(){
        CookieObj = {};
        let thisCookie = document.cookie;
        if(thisCookie === '') return CookieObj;
        let listObj = thisCookie.split(';');
        for(let i=0, len=listObj.length;i<len;i++){
            let w = listObj[i].split('=');
            let name = decodeURIComponent(w[0].replace(/^\s+|\s+$/g,''));
            let value = decodeURIComponent(w[1]);
    		    CookieObj[name] = value;
        }
        return CookieObj;
        //console.log(thisCookie);
    },
    setCookies: function(name,value,path,iDay,domain,secure){
        let oDate=new Date();
        oDate.setDate(oDate.getDate()+iDay);
        let cookie = encodeURIComponent(name) + '=' + encodeURIComponent(value);
	      if (iDay) {
		       cookie+=';expires=' + oDate;
        }
      	if (path) {
      		cookie+=';path=' + path;
      	}
      	if (domain) {
      		cookie+=';domain' + domain;
      	}
      	if (secure) {
      		cookie+=';secure' + secure;
      	}
    	  document.cookie = cookie;
    }
};
/*模块*/
const createItems = {
    createContainer: function(key){
        let ItemContainer = EleUtil.create('div');
        ItemContainer.id = 'eddie32' + key;
        EleUtil.selectID('toggleWindow').style.height='100px';
        EleUtil.selectID('toggleWindow').appendChild(ItemContainer);
        return ItemContainer;
    },
    createImages:function(key){
        let outerContainer = createItems.createContainer(key);
        //console.log(MenuList[key]);
        let imgList = MenuList[key].addr;
        let imgLength = imgList.length;
        for(let k=0;k<imgLength;k++){
            let divElement = EleUtil.create('div');
            divElement.className = 'clickItem';
            let imgItem = EleUtil.create('img');
            imgItem.src = imgList[k];
            imgItem.className = 'Ems';
            imgItem.onclick = expandMenu.attachEmotion;
            imgItem.onmouseover = mouseOverAction.showImg;
            imgItem.onmouseout =mouseOverAction.clearImg;
            //imgItem.style.cssText = 'cursor:pointer;padding: 10px 10px:width: 75px;height: 75px;';
            divElement.appendChild(imgItem);
            outerContainer.appendChild(divElement);
        }
    },
    createPlainText: function(key){
        let outerContainer = createItems.createContainer(key);
        let txtList = MenuList[key].addr;
        let txtLength = txtList.length;
        for(let k=0;k<txtLength;k++){
            let txtItem = EleUtil.create('span');
            txtItem.style.cssText = 'cursor:pointer; margin: 10px 10px;';
            txtItem.innerHTML = `<a data-sign=${encodeURI(txtList[k])} class='txtBtnEmotion'>${txtList[k]}</a>`;
            if(MenuList[key].ref){
              txtItem.innerHTML = `<a data-sign=${encodeURI(txtList[k])} class='txtBtnEmotion'>${MenuList[key].ref[k]}</a>`;
              EleUtil.selectID('toggleWindow').style.height='50px';
            }
            txtItem.onclick = expandMenu.attachEmotion;
            txtItem.style.cssText = 'cursor:pointer;padding: 10px 10px:width: 50px;';
            outerContainer.appendChild(txtItem);
        }
    },
    createImageLink: function(key){
        let outerContainer = createItems.createContainer(key);
        let imgList = MenuList[key].addr;
        let refList = MenuList[key].ref;
        let imgLength = imgList.length;
        for(var k=0;k<imgLength;k++){
            let imgItem = EleUtil.create('img');
            imgItem.dataset.link =  refList[k];
            imgItem.src = imgList[k];
            imgItem.className = 'Ems';
            imgItem.onclick = expandMenu.attachEmotion;
            imgItem.style.cssText = 'width: 50px !important;height: 50px !important;';
            outerContainer.appendChild(imgItem);
        }
    }
};
const mouseOverAction = {
      showImg: function(event){
          let eventTarget = EventUtil.getTarget(event);
          if(!eventTarget.src){
              return null;
          }
          let largeViewContainer = EleUtil.selectID('largeView');
          //console.log([event.clientY,event.clientX]);
          //console.log([EleUtil.selectID('largeView').style.top,EleUtil.selectID('largeView').style.left]);
          largeViewContainer.innerHTML = `<img src=${eventTarget.src} />`
          largeViewContainer.style.display = 'block';
          largeViewContainer.style.top = `${event.clientY + 20}px`;
          largeViewContainer.style.left = `${event.clientX}px`;
      },
      clearImg: function(event){
          EleUtil.selectID('largeView').style.display = 'none';
      }
}
const expandMenu = {
    init: function(event){
        createMenu.clear();
        let eventTarget = EventUtil.getTarget(event);
        EleUtil.selectID('toggleWindow').style.display = 'block';
        EleUtil.selectID('toggleWindow').style.width= EleUtil.select('textarea').style.width;
        let dataType = eventTarget.attributes[2].nodeValue;
        let dataKey = eventTarget.attributes[1].nodeValue;
        if(EleUtil.select('#eddie32'+dataKey)){
            EleUtil.select('#eddie32'+dataKey).style.display = 'block';
            if(dataKey == 'item1') EleUtil.selectID('toggleWindow').style.height='50px';
            else EleUtil.selectID('toggleWindow').style.height='100px';
            return;
        }
        if(dataType =='plain'){
           createItems.createPlainText(dataKey);
        }else if(dataType =='image'){
           createItems.createImages(dataKey);
        }else if(dataType == 'imageLink'){
           createItems.createImageLink(dataKey);
        }
    },
    attachEmotion: function(event){
        const eventTarget = EventUtil.getTarget(event);
        //console.log(eventTarget);

        let addressTarget = '', emotionAddress='';
        if(eventTarget.attributes.length==2){
            if(eventTarget.src){
                addressTarget = eventTarget.src;
                emotionAddress=expandMenu.addressParse(addressTarget,'image');
            }else{
                //console.log(eventTarget.attributes);
                addressTarget = eventTarget.attributes[0].nodeValue;
                emotionAddress=expandMenu.addressParse(addressTarget,'plain');
            }
        }
        else{
           //console.log(eventTarget.attributes);
           addressTarget = eventTarget.attributes[0].nodeValue;
           emotionAddress=expandMenu.addressParse(addressTarget,'plain');
        }
        let selectTextArea = EleUtil.select('textarea');
        const ovalue = selectTextArea.value;
        const startPos = selectTextArea.selectionStart;
        const endPos = selectTextArea.selectionEnd;
        selectTextArea.value = `${ovalue.slice(0, startPos)}${emotionAddress}${ovalue.slice(startPos)}`;
       // console.log(eventTarget);
       // console.log(emotionAddress);
    },
    addressParse: function(addStr, pattern){
        let stringReturn='';
        if(pattern === 'image'){
            stringReturn = `[img]${addStr}[/img]`;
        }
        if(pattern === 'plain'){
            stringReturn =  decodeURI(addStr);
        }
        if(pattern === 'imageLink'){
            stringReturn =  addStr;
        }
        return stringReturn;
    }
};
const createMenu = {
    defaultID: 'emotion0000',
    main: function(){
        /*main menu*/
        let mainMenu = EleUtil.create('div');
        mainMenu.innerHTML = `<span id='largeView'></span><span class='subMenu' title='主菜单 version ${versionNo}'><b>⑨囧⑨</b></span>`;
        mainMenu.id = createMenu.defaultID;
        let MenuLength = Object.keys(MenuList).length;
        for(let i=0;i<MenuLength;i++){
            const MenuKey = Object.keys(MenuList)[i];
            const MenuTitle = MenuList[MenuKey].title;
            const MenuType = MenuList[MenuKey].datatype;
            if(!MenuType || !MenuTitle) console.log('dataerror  '+MenuKey);
            const testMenu = createMenu.subs(MenuTitle,expandMenu.init,MenuKey, MenuType);
            mainMenu.appendChild(testMenu);
        }
        /*close button*/
        let closeBtn = EleUtil.create('span');
        closeBtn.innerHTML = '[x]';
        closeBtn.className= 'subMenu';
        closeBtn.id = 'closeEM';
        closeBtn.onclick = createMenu.clear;
        closeBtn.style.cssText = 'cursor:pointer';
        mainMenu.appendChild(closeBtn);
        /*dropdown box*/
        let itemWindow = EleUtil.create('div');
        itemWindow.id = 'toggleWindow';
        mainMenu.appendChild(itemWindow);
        /*css style*/
        let styleItem = EleUtil.create('style');
        styleItem.innerHTML = `#emotion0000 {padding:5px 5px; vertical-align: middle;   \
                                 font: 12px/16px 'Hiragino Sans GB','Microsoft YaHei','Arial','sans-serif'} \
                               #largeView{position:absolute; background: #fff;z-index:5000; opacity: 0.8} \
                               #largeView img{width: 200px; height:200px;} \
                               #toggleWindow a{padding: 5px 5px;line-height:2} \
                               #toggleWindow {height: 100px; padding: 3px 3px; overflow-x: auto; margin-top:6px; \
                                 margin-bottom:6px; border:1px solid #ff4351; display:none;position:relative; z-index:200; }\
                               .clickItem{display:inline-block; z-index:300;}
                               a.subBut{text-decoration: none;color: #fff;} \
                               .Ems{cursor:pointer;width: 50px;height: 50px;display:inline-block;  z-index:400;} \
                               a.subBut:hover{color: #fff;} \
                               a.txtBtnEmotion{text-decoration:none;} \
                               a.txtBtnEmotion:hover{background:#ff7680; color:#fff; } \
                               .subMenu{display:inline-block;cursor:pointer; text-align:center; padding: 8px 8px; \
                                 font: 12px/16px 'Hiragino Sans GB','Microsoft YaHei','Arial','sans-serif';\
                                 background-color: #ff4351;border-color: #ff4351;color: #fff;} \
                               .subMenu:hover, .subMenu:focus, .subMenu:visited{background-color: #ff7680;border-color: #ff7680;color: #fff;}`;
        mainMenu.appendChild(styleItem);
        return mainMenu;
    },
    subs: function(title,func,subid,subtype){
        let subMenu = EleUtil.create('span');
        subMenu.id = subid;
        subMenu.className= 'subMenu';
        let subcontent = `<a class='subBut' data-kid=${subid} date-type=${subtype}>${title}</a>`;
        subMenu.onclick = func;
        subMenu.title = title;
        subMenu.innerHTML = subcontent;
        return subMenu;
    },
    clear: function(){
        const toggleWindow = EleUtil.selectID('toggleWindow');
        toggleWindow.style.display = 'none';
        const togWinChildren = toggleWindow.childNodes;
        for (let j=0, len = togWinChildren.length ;j<len;j++){
            //console.log(togWinChildren[j]);
            togWinChildren[j].style.display = 'none';
        }
    }
};


//let testareaEleSet = new WeakSet();
let elementSet = document.getElementsByTagName('textarea');
let elementSetLength = elementSet.length;
if(elementSetLength===0){
  console.log('There is no textarea');
}
//testareaEleSet.add(elementSet);
let userOption = {
   userWindowHeight: 120,
   userSelectTextArea: 'last',
};
let mainEmotionMenu = createMenu.main();
for (let elementSingle of elementSet) {
  //console.log(elementSingle);
  elementSingle.parentNode.insertBefore(mainEmotionMenu, elementSingle);
}