UNPKG

text-mode

Version:

Character based display for the DOM

301 lines (218 loc) 7.78 kB
(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){ window.TextMode = require( './text-mode' ); },{"./text-mode":4}],2:[function(require,module,exports){ function charSize( font, c ){ var span = document.createElement( 'span' ); document.body.appendChild( span ); span.style.cssText = 'font: ' + font; span.appendChild( document.createTextNode( c || '╬' ) ); var charSize = { width: span.offsetWidth, height: span.offsetHeight }; document.body.removeChild( span ); return charSize; } module.exports = charSize; },{}],3:[function(require,module,exports){ module.exports = function( template ){ return eval( "(function(o){return '" + template.replace( /'/g, "\\'" ) .replace( /<%=\s*/g, "'+o." ) .replace( /\s*%>/g, "+'" ) + "'})" ); } },{}],4:[function(require,module,exports){ 'use strict'; var template = require( './string-inject' ); var charSize = require( './char-size' ); function TextMode( target, options ){ if( !( this instanceof TextMode )){ return new TextMode( target, options ); } var tm = this; var parent; if( typeof target === 'string' ){ parent = document.querySelector( target ); } else if( target instanceof HTMLElement ){ parent = target; } else { parent = document.body; if( !options && target && Object.keys( target ).some( function( key ){ return key in TextMode.defaults; })){ options = target; }; }; tm.viewport = document.createElement( 'div' ); parent.appendChild( tm.viewport ); options = options || TextMode.defaults; Object.keys( TextMode.defaults ).forEach( function( key ){ tm[ key ] = key in options ? options[ key ] : TextMode.defaults[ key ]; }); tm.id = randomId(); tm.viewport.id = 'tm-' + tm.id; tm.sheet = newSheet(); tm.charSize = charSize( tm.font ); tm.size = { width: tm.columns * tm.charSize.width, height: tm.rows * tm.charSize.height }; cache[ tm.id ] = { tiles: [], textNodes: [], fore: [], back: [], className: [], classMap: {}, nextIndex: 0 }; var viewportStyle = templates.viewport( tm ); var tilesStyle = templates.tiles( tm.charSize ); newRule( tm.sheet, '#' + tm.viewport.id, viewportStyle ); newRule( tm.sheet, '#' + tm.viewport.id + ' span', tilesStyle ); initTiles( tm ); } TextMode.prototype.set = function( column, row, text, fore, back, className ){ var tm = this; if( Array.isArray( column ) ){ var buffer = column; tm.each( function( x, y, i ){ tm.set( x, y, buffer[ i ].text, buffer[ i ].fore, buffer[ i ].back, buffer[ i ].className ); }); return; } var i = row * tm.columns + column; cache[ tm.id ].textNodes[ i ].nodeValue = text; if( fore || back ){ tm.setColor( column, row, fore, back ); } if( className ){ tm.setClassName( column, row, className ); } }; TextMode.prototype.setColor = function( column, row, fore, back ){ var tm = this; var i = row * tm.columns + column; if( fore === cache[ tm.id ].fore[ i ] && back === cache[ tm.id ].back[ i ] ) return; fore = fore || cache[ tm.id ].fore[ i ] || tm.fore; back = back || cache[ tm.id ].back[ i ] || tm.back; tm.fore = cache[ tm.id ].fore[ i ] = fore; tm.back = cache[ tm.id ].back[ i ] = back; var key = fore + ',' + back; if( !( key in cache[ tm.id ].classMap ) ){ tm.addColor( fore, back ); } var colorClass = cache[ tm.id ].classMap[ key ]; cache[ tm.id ].tiles[ i ].className = colorClass + ' ' + cache[ tm.id ].className[ i ]; }; TextMode.prototype.setClassName = function( column, row, className ){ var tm = this; var i = row * tm.columns + column; if( cache[ tm.id ].className[ i ] === className ) return; cache[ tm.id ].className[ i ] = className; var colorClass = getColorClass( tm, i ); cache[ tm.id ].tiles[ i ].className = colorClass + ' ' + className; }; TextMode.prototype.get = function( column, row ){ var tm = this; if( typeof column !== 'number' ){ var buffer = []; tm.each( function( x, y, i ){ buffer[ i ] = tm.get( x, y ); }); return buffer; } var i = row * tm.columns + column; return { fore: cache[ tm.id ].fore[ i ], back: cache[ tm.id ].back[ i ], text: cache[ tm.id ].textNodes[ i ].nodeValue, className: cache[ tm.id ].className[ i ] }; }; TextMode.prototype.addColor = function( fore, back ){ var tm = this; var key = fore + ',' + back; if( key in cache[ tm.id ].classMap ) return; var className = 'color-' + tm.id + '-' + nextIndex( tm.id ); cache[ tm.id ].classMap[ key ] = className; newRule( tm.sheet, '.' + className, templates.color({ fore: fore, back: back })); }; TextMode.prototype.each = function( callback ){ var tm = this; for( var i = 0; i < tm.columns * tm.rows; i++ ){ var x = i % tm.columns; var y = Math.floor( i / tm.columns ); callback( x, y, i ); } }; TextMode.defaults = { columns: 80, rows: 25, fore: '#ddd', back: '#222', font: '16px monospace' }; var cache = {}; var templates = { style: template( '<%=selector%> { <%=rule%> }' ), color: template( 'background: <%=back%>; color: <%=fore%>;' ), viewport: template( 'position: relative; width: <%=size.width%>px; height: <%=size.height%>px; font: <%=font%>' ), tiles: template( 'position: absolute; line-height: <%=height%>px; width: <%=width%>px; height: <%=height%>px;' ), tile: template( 'top: <%=top%>px; left: <%=left%>px;' ) }; function newSheet(){ var style = document.createElement( 'style' ); document.head.appendChild( style ); return style.sheet; } function newRule( sheet, selector, rule ){ var style = templates.style({ selector: selector, rule: rule }); sheet.insertRule( style, sheet.cssRules.length ); } function randomId( prefix ){ var h = prefix || ''; for( var i = 0; i < 8; i++ ){ h += Math.floor( Math.random() * 16 ).toString( 16 ); } return h; } function nextIndex( id ){ return cache[ id ].nextIndex++; } function initTiles( tm ){ tm.each( function( x, y, i ){ var span = document.createElement( 'span' ); var content = document.createTextNode( '' ); span.appendChild( content ); tm.viewport.appendChild( span ); cache[ tm.id ].tiles[ i ] = span; cache[ tm.id ].textNodes[ i ] = content; cache[ tm.id ].className[ i ] = ''; updatePosition( tm, x, y, i ); tm.setColor( x, y, tm.fore, tm.back ); }); } function updatePosition( tm, x, y, i ){ var span = cache[ tm.id ].tiles[ i ]; var position = { left: x * tm.charSize.width, top: y * tm.charSize.height }; span.style.cssText = templates.tile( position ); } function getColorClass( tm, i ){ var fore = cache[ tm.id ].fore[ i ]; var back = cache[ tm.id ].back[ i ]; var key = fore + ',' + back; return cache[ tm.id ].classMap[ key ]; } module.exports = TextMode; },{"./char-size":2,"./string-inject":3}]},{},[1]);