Adding initial UI JS

This still needs lots of tests to be written, and checks for missing
browser functionality (specifically around Blob URLs)
This commit is contained in:
Jeff Avallone 2014-12-04 18:37:35 -05:00
parent bd19966cab
commit 257fb19369
5 changed files with 130 additions and 28 deletions

View File

@ -28,6 +28,7 @@
"karma-notify-reporter": "^0.1.1",
"karma-phantomjs-launcher": "^0.1.4",
"lodash": "^2.4.1",
"q": "^1.1.2",
"snapsvg": "git://github.com/adobe-webplatform/Snap.svg#dev",
"through": "^2.3.6",
"vinyl-transform": "^1.0.0"

View File

@ -1,10 +1,10 @@
<div class="container">
<form id="regexp_form">
<form id="regexp-form">
<textarea id="regexp-input" autofocus="autofocus" placeholder="Enter JavaScript-style regular expression to display"></textarea>
<button type="submit">Display</button>
<ul class="inline-list">
<li><a href="#" class="oi with-text" data-glyph="data-transfer-download">Download</a></li>
<li><a href="#" class="oi with-text" data-glyph="data-transfer-download" download="image.svg" type="image/svg+xml">Download</a></li>
<li><a href="#" class="oi with-text" data-glyph="link-intact">Permalink</a></li>
</ul>
</form>

View File

@ -1,28 +1,10 @@
import parser from './parser/javascript.js';
import Snap from 'snapsvg';
import Regexper from './regexper.js';
// Testing code
(function() {
var result = parser.parse('^test?(foo)[a-z]asdf$'),
svg = Snap('#regexp-render svg');
if (svg) {
document.body.className = 'has-results';
result.container = svg.group().transform(Snap.matrix()
.translate(10, 10));
result.render();
var regexper = new Regexper(document.body);
regexper.bindListeners();
setTimeout(() => {
var box;
result.position();
box = result.container.getBBox();
svg.attr({
width: box.width + 20,
height: box.height + 20
window.dispatchEvent(new Event('hashchange'));
});
});
}
}());

117
src/js/regexper.js Normal file
View File

@ -0,0 +1,117 @@
import parser from './parser/javascript.js';
import Snap from 'snapsvg';
import Q from 'q';
export default class Regexper {
constructor(root) {
this.root = root;
this.form = root.querySelector('#regexp-form');
this.field = root.querySelector('#regexp-input');
this.error = root.querySelector('#error');
this.permalink = root.querySelector('a[data-glyph="link-intact"]');
this.download = root.querySelector('a[data-glyph="data-transfer-download"]');
this.svg = root.querySelector('#regexp-render svg');
this.padding = 10;
this.snap = Snap(this.svg);
}
keypressListener(event) {
if (event.shiftKey && event.keyCode === 13) {
event.preventDefault();
this.form.dispatchEvent(new Event('submit'));
}
}
submitListener(event) {
event.preventDefault();
location.hash = this.field.value;
}
hashchangeListener() {
var expression = decodeURIComponent(location.hash.slice(1)).replace(/[\r\n]/g, '');
if (expression !== '') {
this.field.value = expression;
this.setState('is-loading');
this.renderRegexp(expression)
.then((() => {
this.setState('has-results');
this.updateLinks();
}).bind(this), this.showError.bind(this));
}
}
bindListeners() {
this.field.addEventListener('keypress', this.keypressListener.bind(this));
this.form.addEventListener('submit', this.submitListener.bind(this));
window.addEventListener('hashchange', this.hashchangeListener.bind(this));
}
setState(state) {
var classList = this.root.classList;
classList.remove('is-loading', 'has-results', 'has-error');
classList.add(state);
}
showError(message) {
this.setState('has-error');
this.error.innerHTML = '';
this.error.appendChild(document.createTextNode(message));
}
updateLinks() {
var blob, url;
blob = new Blob([svg.outerHTML], { type: 'image/svg+xml' });
url = URL.createObjectURL(blob);
this.download.setAttribute('href', url);
this.permalink.setAttribute('href', location);
}
renderSvg(snap, expression) {
var result;
snap.selectAll('g').remove();
result = parser.parse(expression);
result.container = snap.group().transform(Snap.matrix()
.translate(this.padding, this.padding));
result.render();
return result;
}
positionSvg(snap, parsed) {
var box;
parsed.position();
box = parsed.container.getBBox();
snap.attr({
width: box.width + this.padding * 2,
height: box.height + this.padding * 2
});
}
renderRegexp(expression) {
var padding = this.padding,
snap = Snap(this.svg),
promise;
promise = Q.promise(((resolve, reject, notify) => {
resolve(this.renderSvg(snap, expression));
}).bind(this));
promise.then(this.positionSvg.bind(this, snap));
return promise;
}
}

View File

@ -175,7 +175,9 @@ header {
#error {
background: $red;
color: $white;
text-indent: 0.5em;
padding: 0 0.5em;
white-space: pre;
font-family: monospace;
font-weight: bold;
display: none;
@ -192,7 +194,7 @@ header {
body.is-loading &, body.has-error & {
position: absolute;
top: -100px;
top: -10000px;
}
}