scratchblocks
Version:
Make pictures of Scratch blocks from text.
169 lines (142 loc) • 4.02 kB
JavaScript
/*
* scratchblocks
* http://scratchblocks.github.io/
*
* Copyright 2013-2016, Tim Radvan
* @license MIT
* http://opensource.org/licenses/MIT
*/
import {
parse,
allLanguages,
loadLanguages,
Label,
Icon,
Input,
Block,
Comment,
Script,
Document,
} from "./syntax/index.js"
import * as scratch2 from "./scratch2/index.js"
import * as scratch3 from "./scratch3/index.js"
export default function (window) {
const document = window.document
scratch2.init(window)
scratch3.init(window)
function appendStyles() {
document.head.appendChild(scratch2.makeStyle())
document.head.appendChild(scratch3.makeStyle())
}
function newView(doc, options) {
options = {
style: "scratch2",
...options,
}
options.scale = options.scale || 1
if (options.style === "scratch2") {
return scratch2.newView(doc, options)
} else if (/^scratch3($|-)/.test(options.style)) {
return scratch3.newView(doc, options)
}
throw new Error(`Unknown style: ${options.style}`)
}
function render(doc, options) {
if (typeof options === "function") {
throw new Error("render() no longer takes a callback")
}
const view = newView(doc, options)
const svg = view.render()
// Used in high contrast theme
svg.classList.add(`scratchblocks-style-${options.style}`)
return svg
}
/*****************************************************************************/
/*** Render ***/
// read code from a DOM element
function readCode(el, options) {
options = {
inline: false,
...options,
}
const html = el.innerHTML.replace(/<br>\s?|\n|\r\n|\r/gi, "\n")
const pre = document.createElement("pre")
pre.innerHTML = html
let code = pre.textContent
if (options.inline) {
code = code.replace("\n", "")
}
return code
}
// insert 'svg' into 'el', with appropriate wrapper elements
function replace(el, svg, doc, options) {
let container
if (options.inline) {
container = document.createElement("span")
let cls = "scratchblocks scratchblocks-inline"
if (doc.scripts[0] && !doc.scripts[0].isEmpty) {
cls += ` scratchblocks-inline-${doc.scripts[0].blocks[0].shape}`
}
container.className = cls
container.style.display = "inline-block"
container.style.verticalAlign = "middle"
} else {
container = document.createElement("div")
container.className = "scratchblocks"
}
container.appendChild(svg)
el.innerHTML = ""
el.appendChild(container)
}
/* Render all matching elements in page to shiny scratch blocks.
* Accepts a CSS selector as an argument.
*
* scratchblocks.renderMatching("pre.blocks");
*
* Like the old 'scratchblocks2.parse().
*/
const renderMatching = function (selector, options) {
selector = selector || "pre.blocks"
options = {
// Default values for the options
style: "scratch2",
inline: false,
languages: ["en"],
scale: 1,
read: readCode, // function(el, options) => code
parse: parse, // function(code, options) => doc
render: render, // function(doc) => svg
replace: replace, // function(el, svg, doc, options)
...options,
}
// find elements
const results = [].slice.apply(document.querySelectorAll(selector))
results.forEach(el => {
const code = options.read(el, options)
const doc = options.parse(code, options)
const svg = options.render(doc, options)
options.replace(el, svg, doc, options)
})
}
return {
allLanguages: allLanguages, // read-only
loadLanguages: loadLanguages,
stringify: function (doc) {
return doc.stringify()
},
Label,
Icon,
Input,
Block,
Comment,
Script,
Document,
newView: newView,
read: readCode,
parse: parse,
replace: replace,
render: render,
renderMatching: renderMatching,
appendStyles: appendStyles,
}
}