gf2bbs-sticker

more emoji sticker

// ==UserScript==
// @name         gf2bbs-sticker
// @name:zh-cn   《少女前线2:追放》官方社区-表情包贴图
// @namespace    https://gf2-bbs.sunborngame.com/
// @version      1.0.0
// @description  more emoji sticker
// @description:zh-cn 更多表情包
// @author       hk416
// @license      MIT
// @match        https://gf2-bbs.sunborngame.com/*
// @icon         https://gf2-cn.cdn.sunborngame.com/website/official/web_head.jpg
// @grant        none
// ==/UserScript==

(function () {
    'use strict';

    const imgs = [
        // offical vol.1 
        // https://store.line.me/stickershop/product/4857276
        // https://shouji.sogou.com/interface/expr.php?pkg_id=23929
        { title: "摸摸", who: "FAL", src: "https://community.cdn.sunborngame.com/prod/1727848031902.png", },
        { title: "Hi", who: "汤姆森", src: "https://community.cdn.sunborngame.com/prod/1727848167062.png" },
        { title: "喜欢", who: "Kar98k", src: "https://community.cdn.sunborngame.com/prod/1727848988102.png" },
        { title: "喝茶", who: "春田", src: "https://community.cdn.sunborngame.com/prod/1727836351968.png" },

        { title: "Yes", who: "柯尔特左轮", src: "https://community.cdn.sunborngame.com/prod/1727850010461.png" },
        { title: "No", who: "IDW", src: "https://community.cdn.sunborngame.com/prod/1727850175869.png" },
        { title: "答错啦喵", who: "IDW", src: "https://community.cdn.sunborngame.com/prod/1727850242980.png" },
        { title: "哭哭", who: "RO635", src: "https://community.cdn.sunborngame.com/prod/1727448421782.png" },

        { title: "给我打钱", who: "格林娜", src: "https://community.cdn.sunborngame.com/prod/1727850338729.png" },
        { title: "请给我钱", who: "格林娜", src: "https://community.cdn.sunborngame.com/prod/1727850488638.png" },
        { title: "Bye", who: "AR15", src: "https://community.cdn.sunborngame.com/prod/1727850509007.png" },
        { title: "扶额", who: "M16A1", src: "https://community.cdn.sunborngame.com/prod/1727850591057.png" },

        { title: "吃零食", who: "FNC", src: "https://community.cdn.sunborngame.com/prod/1727850634826.png" },
        { title: "盯", who: "维尔德", src: "https://community.cdn.sunborngame.com/prod/1727787797318.png" },
        { title: "喷雾", who: "M4A1", src: "https://community.cdn.sunborngame.com/prod/1727848572022.png" },
        { title: "超开心", who: "M4 SOPMODⅡ", src: "https://community.cdn.sunborngame.com/prod/1727850835476.png" },

        { title: "小钱钱", who: "格林娜", src: "https://community.cdn.sunborngame.com/prod/1727850925489.png" },
        { title: "你的快递", who: "AR15", src: "https://community.cdn.sunborngame.com/prod/1727850981830.png" },
        { title: "hkm4",  who: "HK416", src: "https://community.cdn.sunborngame.com/prod/1727614818417.png" },
        { title: "围观", who: "M4A1", src: "https://community.cdn.sunborngame.com/prod/1727851568599.png" },

        { title: "困", who: "G11", src: "https://community.cdn.sunborngame.com/prod/1727851649842.png" },
        { title: "生气", who: "WA2000", src: "https://community.cdn.sunborngame.com/prod/1727851706760.png" },
        { title: "疑惑", who: "索米", src: "https://community.cdn.sunborngame.com/prod/1727509528781.png" },
        { title: "点点点", who: "S.A.T.8", src: "https://community.cdn.sunborngame.com/prod/1727851798839.png" },

        { title: "害羞", who: "M950A,雷电", src: "https://community.cdn.sunborngame.com/prod/1727852482643.png" },
        { title: "加油", who: "重装小队", src: "https://community.cdn.sunborngame.com/prod/1727852568852.png" },
        { title: "休息一下", who: "M4 SOPMODⅡ", src: "https://community.cdn.sunborngame.com/prod/1727852745854.png" },
        { title: "", who: "建筑师", src: "https://community.cdn.sunborngame.com/prod/1727852782880.png" },

        { title: "警觉", who: "IDW", src: "https://community.cdn.sunborngame.com/prod/1727852834449.png" },
        { title: "好孩子", who: "G36", src: "https://community.cdn.sunborngame.com/prod/1727852839107.png" },
        { title: "吐舌头", who: "UMP9,UMP45", src: "https://community.cdn.sunborngame.com/prod/1727852846379.png" },
        { title: "不要过来啊", who: "G36C", src: "https://community.cdn.sunborngame.com/prod/1727693870956.png" },

        { title: "红茶可以吗", who: "MK48", src: "https://community.cdn.sunborngame.com/prod/1727852967535.png" },
        { title: "怒", who: "内格夫", src: "https://community.cdn.sunborngame.com/prod/1727852975009.png" },
        { title: "来啦", who: "AK12,AN94", src: "https://community.cdn.sunborngame.com/prod/1727852979133.png" },
        { title: "欸", who: "SPAS-12", src: "https://community.cdn.sunborngame.com/prod/1727852983900.png" },

        { title: "欸嘿", who: "P7", src: "https://community.cdn.sunborngame.com/prod/1727853392241.png" },
        { title: "我懂的", who: "6P62", src: "https://community.cdn.sunborngame.com/prod/1727618480779.png" },
        { title: "干杯", who: "M16A1", src: "https://community.cdn.sunborngame.com/prod/1727853395971.png" },
        { title: "让我看看", who: "59式", src: "https://community.cdn.sunborngame.com/prod/1727853400617.png" },

    ]

    const itemTemplate = (src, title="") => `<div class="emoji_item">
        <img src="${src}" alt="" loading="lazy">
        <span>${title || ''}</span>
    </div>`


    const pluginTemplate = () => `<div>
        <div class="sticker-button" style="position: fixed;right: 5px;top: 50%;font-size: 24px;cursor:pointer;z-index: 2062;user-select: none;">
            <img style="width: 24px;" src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='rgba(102,102,102,1)'%3E%3Cpath d='M10.5199 19.8634C10.5955 18.6615 10.8833 17.5172 11.3463 16.4676C9.81124 16.3252 8.41864 15.6867 7.33309 14.7151L8.66691 13.2248C9.55217 14.0172 10.7188 14.4978 12 14.4978C12.1763 14.4978 12.3501 14.4887 12.5211 14.471C14.227 12.2169 16.8661 10.7083 19.8634 10.5199C19.1692 6.80877 15.9126 4 12 4C7.58172 4 4 7.58172 4 12C4 15.9126 6.80877 19.1692 10.5199 19.8634ZM19.0233 12.636C15.7891 13.2396 13.2396 15.7891 12.636 19.0233L19.0233 12.636ZM22 12C22 12.1677 21.9959 12.3344 21.9877 12.5L12.5 21.9877C12.3344 21.9959 12.1677 22 12 22C6.47715 22 2 17.5228 2 12C2 6.47715 6.47715 2 12 2C17.5228 2 22 6.47715 22 12ZM10 10C10 10.8284 9.32843 11.5 8.5 11.5C7.67157 11.5 7 10.8284 7 10C7 9.17157 7.67157 8.5 8.5 8.5C9.32843 8.5 10 9.17157 10 10ZM17 10C17 10.8284 16.3284 11.5 15.5 11.5C14.6716 11.5 14 10.8284 14 10C14 9.17157 14.6716 8.5 15.5 8.5C16.3284 8.5 17 9.17157 17 10Z'%3E%3C/path%3E%3C/svg%3E">
        </div>
        <div class="sticker-panel" style="display: none;">
            <div class="van-overlay" style="z-index: 2064;"></div>
            <div class="van-popup van-popup--bottom" title="表情" style="z-index: 2065;">
                <div class="emoji_box">
                    ${imgs.map(i => itemTemplate(i.src, i.title)).join("")}
                </div>
                <button type="button" class="van-action-sheet__cancel"> 取消 </button>
            </div>
        </div>
    </div>`

    /**
     * @param {string} html 
     */
    function createFragment(html) {
        const container = document.createElement('template')
        container.innerHTML = html
        return container.content
    }

    /**
     * 插入图片至选中区域
     * @param {Element} src 
     * @param {Range} range 
     */
    function insertImgTo(src, range) {
        const img = createFragment(`<img class="showImg" src="${src}" alt="" data-href="">`)
        range.insertNode(img)
    }

    /**
     * 判断选中区域光标是否处于编辑框中
     * @param {Range} range 
     */
    function isInEditor(range){
        for (let editor of document.querySelectorAll('[contenteditable="true"]')) {
            if(range.intersectsNode(editor)){
                return true
            }
        }
        return false
    }

    function main() {
        const root = createFragment(pluginTemplate())
        const overlay = root.querySelector('.van-overlay')
        const emojiBox = root.querySelector('.emoji_box')
        const cancelButton = root.querySelector('button')
        const stickerPanel = root.querySelector('.sticker-panel')
        const stickerButton = root.querySelector('.sticker-button')

        document.body.appendChild(root)

        let range = null
        const show = () => {
            const sel = document.getSelection()
            if (sel && sel.rangeCount > 0) {
                range = sel?.getRangeAt(0).cloneRange()
            }
            stickerPanel.style.display = null
        }
        const hidden = () => {
            range = null
            stickerPanel.style.display = 'none'
        }

        const onImgClick = (e) => {
            const src = e.target.src
            if (src) {
                if (range && isInEditor(range)) {
                    insertImgTo(src, range)
                } else {
                    alert("插入位置(光标)未处于编辑框中")
                }
                hidden()
            }
        }
        stickerButton.addEventListener('click', show)
        emojiBox.addEventListener('click', onImgClick)
        overlay.addEventListener('click', hidden)
        cancelButton.addEventListener('click', hidden)
    }

    main()
})();