UNPKG

scratch-sb1-converter

Version:

Scratch 1 (.sb) to Scratch 2 (.sb2) conversion library for Scratch 3.0

172 lines (142 loc) 5.06 kB
const log = require('../util/log'); const _expanded = {}; const _registry = []; class DefaultRenderer { static check () { return true; } render (data, view) { if (data instanceof HTMLElement) { view.content.appendChild(data); } else { view.renderTitle(`Unknown Structure(${data ? data.classId || data.constructor.name : ''})`); } } } class SB1View { constructor (data, prefix = '', path = prefix) { this._elements = {}; this.element = document.createElement('div'); this.element.style.position = 'relative'; this.element.style.top = '0'; this.element.style.left = '0'; // this.element.style.overflow = 'hidden'; this.content = this.element; this.data = data; this.prefix = prefix; this.path = path; this.expanded = !!_expanded[this.path]; this.canExpand = false; this.toggle = this.toggle.bind(this); this.element.addEventListener('click', this.toggle); this.renderer = SB1View.createRenderer(this.data, this); this.render(); } toggle (event) { if (!this.canExpand) return; if (event.target !== this._elements.arrow && event.target !== this._elements.title) return; _expanded[this.path] = this.expanded = !this.expanded; this.render(); event.preventDefault(); event.stopPropagation(); return false; } createElement (type, name) { if (!this._elements[name]) { this._elements[name] = document.createElement(type); } this._elements[name].innerHTML = ''; return this._elements[name]; } child (value, key, path) { return new SB1View(value, key, `${this.path}${path}`); } renderClear () { this.canExpand = false; while (this.element.children.length) { this.element.removeChild(this.element.children[0]); } this.content = this.element; } renderArrow () { this.canExpand = true; const arrowDiv = this.createElement('div', 'arrow'); arrowDiv.innerHTML = '&#x25b6;'; arrowDiv.style.position = 'absolute'; arrowDiv.style.left = '0'; arrowDiv.style.width = '1em'; arrowDiv.style.transform = this.expanded ? 'rotateZ(90deg)' : ''; arrowDiv.style.transition = 'transform 3s'; this.element.appendChild(arrowDiv); const contentDiv = this.createElement('div', 'arrowContent'); contentDiv.style.position = 'relative'; contentDiv.style.left = '1em'; contentDiv.style.right = '0'; this.element.appendChild(contentDiv); this.content = contentDiv; } renderTitle (title) { const titleDiv = this.createElement('div', 'title'); const fullTitle = (this.prefix ? `${this.prefix}: ` : '') + title; if (['\n', '\r', '<br>'].some(str => fullTitle.indexOf(str) !== -1) || fullTitle.length > 80) { this.renderArrow(); if (this.expanded) { titleDiv.innerText = fullTitle; } else { const maxLength = Math.min( fullTitle.lastIndexOf(' ', 80), ['\n', '\r', '<br>'].reduce((value, str) => { if (fullTitle.indexOf(str) !== -1) { return Math.min(value, fullTitle.indexOf(str)); } return value; }, Infinity) ); titleDiv.innerText = `${fullTitle.substring(0, maxLength)} ...`; } } else { titleDiv.innerText = fullTitle; } this.content.appendChild(titleDiv); return titleDiv; } expand (fn, elsefn) { if (this.expanded) { elsefn(); } else { fn(); } } renderExpand (fn) { if (this.expanded) { try { const div = this.createElement('div', 'expanded'); fn.call(this, div) .forEach(view => this.content.appendChild(view.element)); } catch (error) { log.error(error); const divError = this.createElement('div', 'expanded-error'); divError.innerText = 'Error rendering expanded area ...'; this.content.appendChild(divError); } } } render () { this.renderClear(); this.renderer.render(this.data, this); } static register (Class) { _registry.push([Class.check, Class]); } static findRenderer (data, view) { return _registry.reduce((carry, [check, Class]) => { if (check(data, view)) return Class; return carry; }, DefaultRenderer); } static createRenderer (data, view) { const Renderer = SB1View.findRenderer(data, view); return new Renderer(view); } } export {SB1View};