Kanka Marketplace Plugin HTML Inserter for Summernote

Adds a button to Summernote that inserts HTML snippets required by Marketplace themes.

目前为 2021-07-27 提交的版本。查看 最新版本

// ==UserScript==
// @name         Kanka Marketplace Plugin HTML Inserter for Summernote
// @namespace    http://tampermonkey.net/
// @version      3
// @description  Adds a button to Summernote that inserts HTML snippets required by Marketplace themes.
// @author       Salvatos
// @match        https://kanka.io/*
// @icon         https://www.google.com/s2/favicons?domain=kanka.io
// @grant        none
// @run-at       document-end
// ==/UserScript==

/* This one works for a single button
async function fixCodeEditor() {
    // Wait for Summernote to finish initializing
    while(!document.querySelector(".note-codable")) {
        console.log("Waiting for Summernote.");
        await new Promise(r => setTimeout(r, 100));
    }
    console.log("Ready.");

    const toolbar = document.getElementsByClassName('note-toolbar')[0];
    var customButton = `
    <div class="note-btn-group btn-group note-extensions custom-summernote-button">
    <button type="button" class="note-btn btn btn-default btn-sm note-codeview-keep" tabindex="-1" title="Custom button">
    <i class="fas fa-file-import" aria-hidden="true"></i>
    </button>
    </div>`;
    toolbar.insertAdjacentHTML("beforeend", customButton);

    const htmlSnippet = "<p>test input</p>";

    // Add input event to code editor
    customButton = document.getElementsByClassName('custom-summernote-button')[0];
    customButton.addEventListener('click', ()=>{
        // Copy code editor’s value to Summernote’s hidden textarea in case of immediate saving
        document.getElementById('entry').value += htmlSnippet;
        // Insert HTML in editors
        document.getElementsByClassName('note-editable')[0].insertAdjacentHTML("beforeend", htmlSnippet);
        document.getElementsByClassName('note-codable')[0].value += htmlSnippet;
    });
}*/

// Let’s try a dropdown
async function insertCustomTool() {
    // Wait for Summernote to finish initializing
    while(!document.querySelector(".note-codable")) {
        console.log("Waiting for Summernote.");
        await new Promise(r => setTimeout(r, 100));
    }
    console.log("Ready.");

    // Prepare to check for supported themes in the campaign
    var rootFlags = getComputedStyle(document.documentElement);

    // Define our supported code snippets
    let snippets = [];
    // Build list items for our supported code snippets
    let themes = [];

    // Figure Box and Floats by Ornstein
    if (rootFlags.getPropertyValue('--summernote-insert-figure-box') || 1 === 1) { // Temporary bypass for initial release
        snippets.push('<div class="figure">Insert image and caption here</div>');
        snippets.push('<div class="figure r clear">Insert image and caption here</div>');
        themes.push('<li aria-label="Figure Box and Floats (no float)"><a href="#">Figure Box (no float)</a></li>');
        themes.push('<li aria-label="Figure Box and Floats (float right + clear)"><a href="#">Figure Box (float right + clear)</a></li>');
    }

    // Responsive Image Gallery by Salvatos
    if (rootFlags.getPropertyValue('--summernote-insert-autogallery') || 1 === 1) { // Temporary bypass for initial release
        snippets.push('<div class="autogallery">Insert gallery images here</div>');
        themes.push('<li aria-label="Responsive Image Gallery"><a href="#">Responsive Image Gallery</a></li>');
    }

    // Simple Tooltips by KeepOnScrollin
    if (rootFlags.getPropertyValue('--summernote-insert-simple-tooltip') || 1 === 1) { // Temporary bypass for initial release
        snippets.push('<span class="simple-tooltip">Tooltip trigger<span class="simple-tooltip-text top">Tooltip content</span></span>');
        themes.push('<li aria-label="Simple Tooltip (top)"><a href="#">Simple Tooltip (top)</a></li>');
    }
    // Tip Box by Critter
    if (rootFlags.getPropertyValue('--summernote-insert-tip-box') || 1 === 1) { // Temporary bypass for initial release
        snippets.push('<div class="tipbox-small">Small Tip Box text.</div>');
        snippets.push('<div class="tipbox-big">Big Tip Box text.</div>');
        themes.push('<li aria-label="Tip Box (small)"><a href="#">Tip Box (small)</a></li>');
		themes.push('<li aria-label="Tip Box (big)"><a href="#">Tip Box (big)</a></li>');
    }

    var themeList = themes.join("");

    // Locate toolbar and insert our dropdown button
    const toolbar = document.getElementsByClassName('note-toolbar')[0];
    var customButton = `
<div class="note-btn-group btn-group note-style">
	<div class="note-btn-group btn-group">
		<button type="button" class="note-btn btn btn-default btn-sm dropdown-toggle note-codeview-keep" tabindex="-1" data-toggle="dropdown" title="Marketplace theme HTML snippets" aria-expanded="false">
			<i class="fas fa-puzzle-piece"></i> <span class="note-icon-caret"></span>
		</button>
		<ul class="note-dropdown-menu dropdown-menu dropdown-snippets" aria-label="Marketplace theme HTML snippets">
			` + themeList + `
		</ul>
	</div>
</div>`;
    toolbar.insertAdjacentHTML("beforeend", customButton);

    // Grab our completed dropdown
    const dropdown = document.getElementsByClassName('dropdown-snippets')[0];

    // Make sure we have at least one supported theme enabled
    if (dropdown.children[0]) {
        // Add click events to editor
        for (let i = 0; i < dropdown.children.length; i++) {
            var currentButton = dropdown.children[i];

            currentButton.addEventListener('click', ()=>{
                // Add HTML to Summernote’s hidden textarea in case of immediate saving
                document.getElementById('entry').value += snippets[i];
                // Insert HTML in editors
                document.getElementsByClassName('note-editable')[0].insertAdjacentHTML("beforeend", snippets[i]);
                document.getElementsByClassName('note-codable')[0].value += '\n' + snippets[i]; // TODO: Would be nice to scroll the editor to the end after inserting
            });
        }
    }
    else {
        dropdown.insertAdjacentHTML("beforeend", "<li><a href='#'><em>No supported theme found</em></a></li>");
    }
}

// Run it
if (document.getElementById('entity-form')) { // TODO: this ID is currently missing from the campaign edit form and specific entry block editor; asking Jay for a fix
    insertCustomTool();
}

/*
* TODO: A different script (or button + function) should be used for themes that only need to add classes to any element, such as Redacted Text, Context-Aware Classes and .boxquote.
* Those would only work in the visual editor since there I can target those elements as objects and manipulate their classes.
* The question is how we would identify the element that corresponds to the cursor position.
*/

/*
* TODO: We could try to insert at current position but that requires a decent chunk of additional code and jQuery
* Plus we’d have to figure out which editor is open

$('input[type=button]').on('click', function() {
    var cursorPos = $('#text').prop('selectionStart');
    var v = $('#text').val();
    var textBefore = v.substring(0,  cursorPos);
    var textAfter  = v.substring(cursorPos, v.length);

    $('#text').val(textBefore + $(this).val() + textAfter);
});
*/

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址