Last active
November 8, 2019 07:14
-
-
Save nitaku/4d2849e3eab28149b2540925d415df19 to your computer and use it in GitHub Desktop.
Inline BreakDown editor
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
window.AnnotationView = Backbone.D3View.extend | |
namespace: null | |
tagName: 'div' | |
initialize: () -> | |
@d3el | |
.attr | |
class: 'AnnotationView' | |
@listenTo @model, 'change:annotations', @render | |
render: () -> | |
annotations_data = @model.get 'annotations' | |
annotations = @d3el.selectAll '.annotation' | |
.data annotations_data | |
annotations.enter().append 'table' | |
.attr | |
class: 'annotation' | |
annotations | |
.html (d) -> | |
# hide automatic IDs | |
id = if d.id[0] is '_' then '' else d.id | |
# hide undefined body | |
body = if d.body? then d.body else '' | |
return "<tr><td class='id'>#{id}</td><td class='text'>#{d.text.replace(/\n/g,'↵')}</td><td class='body'>#{body}</td></tr>" | |
annotations.exit() | |
.remove() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
.AnnotationView { | |
overflow-y: auto; | |
} | |
.AnnotationView .annotation { | |
font-family: sans-serif; | |
font-size: 12px; | |
margin: 4px; | |
border: 1px solid #DFDFDF; | |
border-collapse: collapse; | |
} | |
.AnnotationView td { | |
padding: 4px; | |
min-width: 14px; | |
} | |
.AnnotationView .annotation .id { | |
color: #555; | |
} | |
.AnnotationView .annotation .text { | |
background: rgba(255, 165, 0, 0.15); | |
} | |
.AnnotationView .annotation .body { | |
color: #444; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Generated by CoffeeScript 1.10.0 | |
(function() { | |
window.AnnotationView = Backbone.D3View.extend({ | |
namespace: null, | |
tagName: 'div', | |
initialize: function() { | |
this.d3el.attr({ | |
"class": 'AnnotationView' | |
}); | |
return this.listenTo(this.model, 'change:annotations', this.render); | |
}, | |
render: function() { | |
var annotations, annotations_data; | |
annotations_data = this.model.get('annotations'); | |
annotations = this.d3el.selectAll('.annotation').data(annotations_data); | |
annotations.enter().append('table').attr({ | |
"class": 'annotation' | |
}); | |
annotations.html(function(d) { | |
var body, id; | |
id = d.id[0] === '_' ? '' : d.id; | |
body = d.body != null ? d.body : ''; | |
return "<tr><td class='id'>" + id + "</td><td class='text'>" + (d.text.replace(/\n/g, '↵')) + "</td><td class='body'>" + body + "</td></tr>"; | |
}); | |
return annotations.exit().remove(); | |
} | |
}); | |
}).call(this); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
window.AppView = Backbone.D3View.extend | |
initialize: () -> | |
# retrieve the grammar from an external file | |
d3.text 'breakdown.peg.js', (grammar) => | |
editor = new Editor | |
model: @model | |
grammar: grammar | |
@el.appendChild(editor.el) | |
editor.render() | |
aw = new AnnotationView | |
model: @model | |
@el.appendChild(aw.el) | |
aw.render() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
body { | |
display: flex; | |
flex-direction: row; | |
} | |
body > * { | |
width: 0; | |
flex-grow: 1; | |
} | |
.Editor { | |
border-right: 1px solid gray; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Generated by CoffeeScript 1.10.0 | |
(function() { | |
window.AppView = Backbone.D3View.extend({ | |
initialize: function() { | |
return d3.text('breakdown.peg.js', (function(_this) { | |
return function(grammar) { | |
var aw, editor; | |
editor = new Editor({ | |
model: _this.model, | |
grammar: grammar | |
}); | |
_this.el.appendChild(editor.el); | |
editor.render(); | |
aw = new AnnotationView({ | |
model: _this.model | |
}); | |
_this.el.appendChild(aw.el); | |
return aw.render(); | |
}; | |
})(this)); | |
} | |
}); | |
}).call(this); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Backbone.D3View.js 0.3.1 | |
// --------------- | |
// (c) 2015 Adam Krebs | |
// Backbone.D3View may be freely distributed under the MIT license. | |
// For all details and documentation: | |
// https://github.com/akre54/Backbone.D3View | |
(function (factory) { | |
if (typeof define === 'function' && define.amd) { define(['backbone', 'd3'], factory); | |
} else if (typeof exports === 'object') { module.exports = factory(require('backbone'), require('d3')); | |
} else { factory(Backbone, d3); } | |
}(function (Backbone, d3) { | |
// Cached regex to match an opening '<' of an HTML tag, possibly left-padded | |
// with whitespace. | |
var paddedLt = /^\s*</; | |
var ElementProto = (typeof Element !== 'undefined' && Element.prototype) || {}; | |
var matchesSelector = ElementProto.matches || | |
ElementProto.webkitMatchesSelector || | |
ElementProto.mozMatchesSelector || | |
ElementProto.msMatchesSelector || | |
ElementProto.oMatchesSelector; | |
Backbone.D3ViewMixin = { | |
// A reference to the d3 selection backing the view. | |
d3el: null, | |
namespace: d3.ns.prefix.svg, | |
$: function(selector) { | |
return this.el.querySelectorAll(selector); | |
}, | |
$$: function(selector) { | |
return this.d3el.selectAll(selector); | |
}, | |
_removeElement: function() { | |
this.undelegateEvents(); | |
this.d3el.remove(); | |
}, | |
_createElement: function(tagName) { | |
var ns = typeof this.namespace === 'function' ? this.namespace() : this.namespace; | |
return ns ? | |
document.createElementNS(ns, tagName) : | |
document.createElement(tagName); | |
}, | |
_setElement: function(element) { | |
if (typeof element == 'string') { | |
if (paddedLt.test(element)) { | |
var el = document.createElement('div'); | |
el.innerHTML = element; | |
this.el = el.firstChild; | |
} else { | |
this.el = document.querySelector(element); | |
} | |
} else { | |
this.el = element; | |
} | |
this.d3el = d3.select(this.el); | |
}, | |
_setAttributes: function(attributes) { | |
this.d3el.attr(attributes); | |
}, | |
// `delegate` supports two- and three-arg forms. The `selector` is optional. | |
delegate: function(eventName, selector, listener) { | |
if (listener === undefined) { | |
listener = selector; | |
selector = null; | |
} | |
var view = this; | |
var wrapped = function(event) { | |
var node = event.target, | |
idx = 0, | |
o = d3.event; | |
d3.event = event; | |
// The `event` object is stored in `d3.event` but Backbone expects it as | |
// the first argument to the listener. | |
if (!selector) { | |
listener.call(view, d3.event, node.__data__, idx++); | |
d3.event = o; | |
return; | |
} | |
while (node && node !== view.el) { | |
if (matchesSelector.call(node, selector)) { | |
listener.call(view, d3.event, node.__data__, idx++); | |
} | |
node = node.parentNode; | |
} | |
d3.event = o; | |
}; | |
var map = this._domEvents || (this._domEvents = {}); | |
var handlers = map[eventName] || (map[eventName] = []); | |
handlers.push({selector: selector, listener: listener, wrapped: wrapped}); | |
this.el.addEventListener(eventName, wrapped, false); | |
return this; | |
}, | |
undelegate: function(eventName, selector, listener) { | |
if (!this._domEvents || !this._domEvents[eventName]) return; | |
if (typeof selector !== 'string') { | |
listener = selector; | |
selector = null; | |
} | |
var handlers = this._domEvents[eventName].slice(); | |
var i = handlers.length; | |
while (i--) { | |
var handler = handlers[i]; | |
var match = (listener ? handler.listener === listener : true) && | |
(selector ? handler.selector === selector : true); | |
if (!match) continue; | |
this.el.removeEventListener(eventName, handler.wrapped, false); | |
this._domEvents[eventName].splice(i, 1); | |
} | |
}, | |
undelegateEvents: function() { | |
var map = this._domEvents, el = this.el; | |
if (!el || !map) return; | |
Object.keys(map).forEach(function(eventName) { | |
map[eventName].forEach(function(handler) { | |
el.removeEventListener(eventName, handler.wrapped, false); | |
}); | |
}); | |
this._domEvents = {}; | |
return this; | |
} | |
}; | |
Backbone.D3View = Backbone.View.extend(Backbone.D3ViewMixin); | |
return Backbone.D3View; | |
})); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Version 2.3 "inline" 28/07/2017 | |
{ | |
var plain_text_offset = 0; | |
var unidentified_span_next_id = 0; | |
var unidentified_spans_stack = []; | |
var open_spans = {}; | |
var result = { | |
spans: [], | |
plain_text: "" | |
}; | |
var last_span = undefined; | |
} | |
start = Doc { | |
return result; | |
} | |
Doc 'document' | |
= (Text / SpanOpen / SpanClose)* | |
SpanOpen = id:SpanOpenCode { | |
if(id === "") { | |
// store unidentified spans in stack | |
unidentified_spans_stack.push({ | |
start: plain_text_offset, | |
start_code_location: location() | |
}); | |
} | |
else { | |
// store identified spans in an index | |
open_spans[id] = { | |
id: id, | |
start: plain_text_offset, | |
start_code_location: location() | |
}; | |
} | |
} | |
SpanClose = d:SpanCloseCode { | |
var id = d.id; | |
if(id in open_spans) { | |
// span found in index: move it to results | |
last_span = open_spans[id]; | |
delete open_spans[id]; | |
} | |
else { | |
if(unidentified_spans_stack.length === 0) { | |
error('Trying to close a span without opening it.'); | |
} | |
else { | |
// span found in stack: move it to results | |
last_span = unidentified_spans_stack.pop(); | |
// give unidentified spans an ID (underscore as first character is not allowed by syntax) | |
if(id === '') { | |
id = '_'+unidentified_span_next_id; | |
unidentified_span_next_id += 1; | |
} | |
last_span.id = id; | |
} | |
} | |
last_span.end = plain_text_offset; | |
last_span.end_code_location = location(); | |
last_span.text = result.plain_text.slice(last_span.start, last_span.end); | |
if(d.body !== undefined) { | |
last_span.body = d.body; | |
} | |
result.spans.push(last_span); | |
} | |
Text = NoSpanCode { | |
result.plain_text += text(); | |
plain_text_offset += text().length; | |
} | |
NoSpanCode = (!SpanCode .)+ { return text(); } | |
SpanCode = SpanOpenCode / SpanCloseCode | |
SpanOpenCode = '<' id:NullableId '<' { return id; } | |
SpanCloseCode = | |
'>' id:NullableId '>' body:Body? | |
{ | |
return {id: id, body: body}; | |
} | |
Body = BodyOpenCode body:NoBodyCode BodyCloseCode { return body; } | |
NullableId 'nullable identifier' | |
= $(Id / '') { return text(); } | |
Id 'identifier' | |
= [a-zA-Z0-9][_a-zA-Z0-9]* { return text(); } | |
NoBodyCode = (!BodyCode .)+ { return text(); } | |
BodyCode = BodyOpenCode / BodyCloseCode | |
BodyOpenCode = '(' | |
BodyCloseCode = ')' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
window.Data = Backbone.Model.extend | |
defaults: | |
rows: [] | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Generated by CoffeeScript 1.10.0 | |
(function() { | |
window.Data = Backbone.Model.extend({ | |
defaults: { | |
rows: [] | |
} | |
}); | |
}).call(this); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
window.Editor = Backbone.D3View.extend | |
namespace: null | |
tagName: 'div' | |
events: | |
input: 'compile' | |
initialize: (conf) -> | |
@d3el.classed 'Editor', true | |
# Chrome bug workaround (https://github.com/codemirror/CodeMirror/issues/3679) | |
editor_div = @d3el.append 'div' | |
.attr | |
class: 'editor_div' | |
.style | |
position: 'relative' | |
wrapper = editor_div.append 'div' | |
.style | |
position: 'absolute' | |
height: '100%' | |
width: '100%' | |
@status_bar = @d3el.append 'div' | |
.attr | |
class: 'status_bar' | |
@parser = PEG.buildParser conf.grammar | |
@editor = CodeMirror wrapper.node(), { | |
#lineNumbers: true, | |
lineWrapping: true, | |
value: ''' | |
This is a new version of <<BreakDown>>(B), a language that can be used to select portions of text for <<annotation>>(A). | |
<<Nested <<spans>>(1) are allowed>>(2), as well as <<newlines | |
within spans>>(N). Moreover, <<BreakDown>>(B) <1<supports <2<a syntax>1>(ONE) for specifying overlapping spans>2>(TWO). You can also mark a portion of text as <<interesting>> without linking something to it. | |
The actual meaning of the <<annotation>>(A) is left open. <<BreakDown>>(B) merely links a body (the part between round brackets) with the section of the text surrounded by angle brackets. | |
''' | |
} | |
@editor.on 'change', () => | |
@compile() | |
@compile() | |
render: () -> | |
@editor.refresh() | |
compile: () -> | |
@status_bar.text 'All ok.' | |
@status_bar.classed 'error', false | |
# clear highlighting | |
@editor.getAllMarks().forEach (mark) -> | |
mark.clear() | |
try | |
data = @parser.parse @editor.getValue() | |
@spans_highlight(data.spans) | |
@model.set 'annotations', data.spans | |
catch e | |
@status_bar.text "Line #{e.location.start.line}: #{e.message}" | |
@status_bar.classed 'error', true | |
spans_highlight: (spans) -> | |
spans.forEach (s) => | |
@editor.markText {line: s.start_code_location.end.line-1, ch: s.start_code_location.end.column-1}, {line: s.end_code_location.start.line-1, ch: s.end_code_location.start.column-1}, {className: 'span'} | |
@editor.markText {line: s.start_code_location.start.line-1, ch: s.start_code_location.start.column-1}, {line: s.start_code_location.end.line-1, ch: s.start_code_location.end.column-1}, {className: 'code'} | |
@editor.markText {line: s.end_code_location.start.line-1, ch: s.end_code_location.start.column-1}, {line: s.end_code_location.end.line-1, ch: s.end_code_location.end.column-1}, {className: 'code'} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
.Editor .status_bar { | |
height: 22px; | |
background: #DDD; | |
border-top: 1px solid gray; | |
font-family: sans-serif; | |
font-size: 12px; | |
padding: 4px; | |
box-sizing: border-box; | |
} | |
.Editor .error { | |
background: #F77; | |
} | |
.Editor { | |
display: flex; | |
flex-direction: column; | |
} | |
.Editor .editor_div { | |
flex-grow: 1; | |
height: 0; | |
} | |
.Editor .CodeMirror { | |
height: 100%; | |
font-size: 12px; | |
font-family: sans-serif; | |
line-height: 1.3; | |
background: #F7F7F7; | |
margin-left: 4px; | |
margin-right: 4px; | |
} | |
.Editor .CodeMirror-gutters { | |
border-right: 0; | |
} | |
.Editor .CodeMirror-lines > * { | |
border: 1px solid #DDD; | |
background: white; | |
} | |
.Editor .span { | |
background: rgba(255, 165, 0, 0.15); | |
} | |
.Editor .code { | |
color: rgba(200, 76, 0, 0.8); | |
font-weight: bold; | |
} | |
.Editor .error { | |
background: rgba(255,0,0,0.2); | |
border-bottom: 2px solid red; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Generated by CoffeeScript 1.10.0 | |
(function() { | |
window.Editor = Backbone.D3View.extend({ | |
namespace: null, | |
tagName: 'div', | |
events: { | |
input: 'compile' | |
}, | |
initialize: function(conf) { | |
var editor_div, wrapper; | |
this.d3el.classed('Editor', true); | |
editor_div = this.d3el.append('div').attr({ | |
"class": 'editor_div' | |
}).style({ | |
position: 'relative' | |
}); | |
wrapper = editor_div.append('div').style({ | |
position: 'absolute', | |
height: '100%', | |
width: '100%' | |
}); | |
this.status_bar = this.d3el.append('div').attr({ | |
"class": 'status_bar' | |
}); | |
this.parser = PEG.buildParser(conf.grammar); | |
this.editor = CodeMirror(wrapper.node(), { | |
lineWrapping: true, | |
value: 'This is a new version of <<BreakDown>>(B), a language that can be used to select portions of text for <<annotation>>(A).\n\n<<Nested <<spans>>(1) are allowed>>(2), as well as <<newlines\nwithin spans>>(N). Moreover, <<BreakDown>>(B) <1<supports <2<a syntax>1>(ONE) for specifying overlapping spans>2>(TWO). You can also mark a portion of text as <<interesting>> without linking something to it.\n\nThe actual meaning of the <<annotation>>(A) is left open. <<BreakDown>>(B) merely links a body (the part between round brackets) with the section of the text surrounded by angle brackets.' | |
}); | |
this.editor.on('change', (function(_this) { | |
return function() { | |
return _this.compile(); | |
}; | |
})(this)); | |
return this.compile(); | |
}, | |
render: function() { | |
return this.editor.refresh(); | |
}, | |
compile: function() { | |
var data, e, error; | |
this.status_bar.text('All ok.'); | |
this.status_bar.classed('error', false); | |
this.editor.getAllMarks().forEach(function(mark) { | |
return mark.clear(); | |
}); | |
try { | |
data = this.parser.parse(this.editor.getValue()); | |
this.spans_highlight(data.spans); | |
return this.model.set('annotations', data.spans); | |
} catch (error) { | |
e = error; | |
this.status_bar.text("Line " + e.location.start.line + ": " + e.message); | |
return this.status_bar.classed('error', true); | |
} | |
}, | |
spans_highlight: function(spans) { | |
return spans.forEach((function(_this) { | |
return function(s) { | |
_this.editor.markText({ | |
line: s.start_code_location.end.line - 1, | |
ch: s.start_code_location.end.column - 1 | |
}, { | |
line: s.end_code_location.start.line - 1, | |
ch: s.end_code_location.start.column - 1 | |
}, { | |
className: 'span' | |
}); | |
_this.editor.markText({ | |
line: s.start_code_location.start.line - 1, | |
ch: s.start_code_location.start.column - 1 | |
}, { | |
line: s.start_code_location.end.line - 1, | |
ch: s.start_code_location.end.column - 1 | |
}, { | |
className: 'code' | |
}); | |
return _this.editor.markText({ | |
line: s.end_code_location.start.line - 1, | |
ch: s.end_code_location.start.column - 1 | |
}, { | |
line: s.end_code_location.end.line - 1, | |
ch: s.end_code_location.end.column - 1 | |
}, { | |
className: 'code' | |
}); | |
}; | |
})(this)); | |
} | |
}); | |
}).call(this); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
app = new AppView | |
el: 'body' | |
model: new Data |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
html, body { | |
margin: 0; | |
padding: 0; | |
width: 100%; | |
height: 100%; | |
overflow: hidden; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset="utf-8"> | |
<title>BreakDown editor</title> | |
<link rel="stylesheet" href="index.css"> | |
<link rel="stylesheet" href="AppView.css"> | |
<link rel="stylesheet" href="Editor.css"> | |
<link rel="stylesheet" href="AnnotationView.css"> | |
<link type="text/css" href="//cdnjs.cloudflare.com/ajax/libs/codemirror/4.6.0/codemirror.min.css" rel="stylesheet"/> | |
<link type="text/css" href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/8.3/styles/github.min.css" rel="stylesheet"/> | |
<script src="http://d3js.org/d3.v3.min.js"></script> | |
<script src="/webvis/tmp/peg-0.9.0.min.js"></script> | |
<script src="http://underscorejs.org/underscore-min.js"></script> | |
<script src="http://backbonejs.org/backbone-min.js"></script> | |
<script src="backbone.d3view.js"></script> | |
<script src="//cdnjs.cloudflare.com/ajax/libs/codemirror/4.6.0/codemirror.min.js"></script> | |
<script src="//wafi.iit.cnr.it/webvis/tmp/codemirror_mode_simple.js"></script> | |
<script src="//cdnjs.cloudflare.com/ajax/libs/codemirror/4.6.0/addon/search/searchcursor.min.js"></script> | |
<!-- your views go here --> | |
<script src="AppView.js"></script> | |
<script src="Editor.js"></script> | |
<script src="AnnotationView.js"></script> | |
<!-- your models go here --> | |
<script src="Data.js"></script> | |
</head> | |
<body> | |
<script src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/8.3/highlight.min.js"></script> | |
<script src="index.js"></script> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Generated by CoffeeScript 1.10.0 | |
(function() { | |
var app; | |
app = new AppView({ | |
el: 'body', | |
model: new Data | |
}); | |
}).call(this); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment