| 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) -> | |
| rowspan = Math.max 1, d.triples.length | |
| triples = '' | |
| d.triples.forEach (t,i) -> | |
| if i > 0 | |
| triples += '</tr><tr>' | |
| object = if t.object_type is 'uri' then "<a href='#{t.object}'>#{t.object}</a>" else t.object | |
| triples += "<td class='predicate'>#{t.predicate}</td><td class='object #{t.object_type}'>#{object}</td>" | |
| # hide automatic IDs | |
| id = if d.id[0] is '_' then '' else d.id | |
| return "<tr><td class='id' rowspan='#{rowspan}'>#{id}</td><td rowspan='#{rowspan}' class='#{d.type}'>#{d.text.replace(/\n/g,'↵')}</td>#{triples}</tr>" | |
| annotations.exit() | |
| .remove() |
| .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; | |
| } | |
| .AnnotationView .annotation .id { | |
| color: #555; | |
| min-width: 14px; | |
| } | |
| .AnnotationView .annotation .span { | |
| background: #B9DBF3; | |
| } | |
| .AnnotationView .annotation .predicate { | |
| color: #444; | |
| } | |
| .AnnotationView .annotation .object.literal { | |
| background: #DDD; | |
| } | |
| .AnnotationView .annotation .object.uri { | |
| background: #DED; | |
| } | |
| .AnnotationView .annotation .object a { | |
| color: black; | |
| text-decoration: none; | |
| } | |
| .AnnotationView .annotation .object a:hover { | |
| text-decoration: underline; | |
| } |
| // 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 id, rowspan, triples; | |
| rowspan = Math.max(1, d.triples.length); | |
| triples = ''; | |
| d.triples.forEach(function(t, i) { | |
| var object; | |
| if (i > 0) { | |
| triples += '</tr><tr>'; | |
| } | |
| object = t.object_type === 'uri' ? "<a href='" + t.object + "'>" + t.object + "</a>" : t.object; | |
| return triples += "<td class='predicate'>" + t.predicate + "</td><td class='object " + t.object_type + "'>" + object + "</td>"; | |
| }); | |
| id = d.id[0] === '_' ? '' : d.id; | |
| return "<tr><td class='id' rowspan='" + rowspan + "'>" + id + "</td><td rowspan='" + rowspan + "' class='" + d.type + "'>" + (d.text.replace(/\n/g, '↵')) + "</td>" + triples + "</tr>"; | |
| }); | |
| return annotations.exit().remove(); | |
| } | |
| }); | |
| }).call(this); |
| 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() |
| body { | |
| display: flex; | |
| flex-direction: row; | |
| } | |
| body > * { | |
| width: 0; | |
| flex-grow: 1; | |
| } | |
| .Editor { | |
| border-right: 1px solid gray; | |
| } |
| // 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); |
| // 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; | |
| })); |
| { | |
| var plain_text_offset = 0; | |
| var unidentified_span_next_id = 0; | |
| var unidentified_spans_stack = []; | |
| var open_spans = {}; | |
| var result = { | |
| spans: [], | |
| plain_text: "" | |
| }; | |
| var triples_index = {}; | |
| } | |
| start = (TripleSection / Body) (Newlines (TripleSection / Body))* { | |
| // check if there are some spans left open at the end of the code | |
| if(unidentified_spans_stack.length > 0 || Object.keys(open_spans).length > 0 ) { | |
| error('Span not closed at end of input.'); // FIXME better error handling: show the line of the first unclosed span | |
| } | |
| // resolve triple IDs in spans | |
| result.spans.forEach(function(span) { | |
| span.triples = []; | |
| if(span.id in triples_index) { | |
| triples_index[span.id].forEach(function(triple) { | |
| span.triples.push(triple); | |
| }) | |
| } | |
| }); | |
| return result; | |
| } | |
| Body 'text body' | |
| = (Text / Operator)* | |
| TripleSection 'triple section' | |
| = '+++' (Newlines Triples)? Newlines '+++' | |
| Triples | |
| = Triple (Newlines Triple)* | |
| Triple | |
| = s:Subject Spaces p:Predicate Spaces o:Object { | |
| // add the triple to the index (subject is used as key) | |
| if(!(s in triples_index)) { | |
| triples_index[s] = []; | |
| } | |
| triples_index[s].push({subject: s, predicate: p, object: o.text, object_type: o.type }); | |
| } | |
| Subject = Id { return text(); } | |
| Predicate = (!(Spaces) .)+ { return text(); } | |
| Object | |
| = '"' [^"]* '"' { return {type: "literal", text: text()}; } | |
| / !(Newlines / '"') (!(Newlines) .)* { return {type: 'uri', text: text()}; } | |
| Operator | |
| = SpanOpen / SpanClose | |
| SpanOpen | |
| = id:SpanOpenCode { | |
| if(id === "") { | |
| // store unidentified spans in stack | |
| unidentified_spans_stack.push({ | |
| type: 'span', | |
| start: plain_text_offset, | |
| start_code_location: location() | |
| }); | |
| } | |
| else { | |
| // store identified spans in an index | |
| open_spans[id] = { | |
| type: 'span', | |
| id: id, | |
| start: plain_text_offset, | |
| start_code_location: location() | |
| }; | |
| } | |
| } | |
| SpanClose | |
| = id:SpanCloseCode { | |
| var span; | |
| if(id in open_spans) { | |
| // span found in index: move it to results | |
| 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 | |
| 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; | |
| } | |
| span.id = id; | |
| } | |
| } | |
| span.end = plain_text_offset; | |
| span.end_code_location = location(); | |
| span.text = result.plain_text.slice(span.start, span.end); | |
| result.spans.push(span); | |
| } | |
| NoText | |
| = SpanOpenCode / SpanCloseCode / '\n+++' / '+++\n' / '+++' | |
| SpanOpenCode = '<' id:NullableId '<' { return id; } | |
| SpanCloseCode = '>' id:NullableId '>' { return id; } | |
| Newlines = [ \t\r\n]+ | |
| Spaces = [ \t]+ | |
| NullableId 'nullable identifier' | |
| = $(Id / '') { return text(); } | |
| Id 'identifier' | |
| = [a-zA-Z0-9][_a-zA-Z0-9]* { return text(); } | |
| Text 'text node' | |
| = (!NoText .)+ { | |
| result.plain_text += text(); | |
| plain_text_offset += text().length; | |
| } |
| window.Data = Backbone.Model.extend | |
| defaults: | |
| rows: [] | |
| 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 | |
| # create the CodeMirror editor | |
| CodeMirror.defineSimpleMode('hl', { | |
| start: [ | |
| {regex: new RegExp('<[a-zA-Z0-9][_a-zA-Z0-9]*<'), token: 'span_open'}, | |
| {regex: new RegExp('<<'), token: 'span_open'}, | |
| {regex: new RegExp('>[a-zA-Z0-9][_a-zA-Z0-9]*>'), token: 'span_close'}, | |
| {regex: new RegExp('>>'), token: 'span_close'}, | |
| {regex: new RegExp('^\\+\\+\\+$'), token: 'triple_section_open', next: 'triple_section'} | |
| ], | |
| triple_section: [ | |
| {regex: new RegExp('^\\+\\+\\+$'), token: 'triple_section_close', next: 'start'}, | |
| {regex: new RegExp('(^[^ \t]*)([ \t]+)([^ \t]*)([ \t]+)(".*"$)'), token: ['subject', '', 'predicate', '', 'literal']}, | |
| {regex: new RegExp('(^[^ \t]*)([ \t]+)([^ \t]*)([ \t]+)([^" \t]*$)'), token: ['subject', '', 'predicate', '', 'object']} | |
| ] | |
| }) | |
| @editor = CodeMirror wrapper.node(), { | |
| #lineNumbers: true, | |
| lineWrapping: true, | |
| value: ''' | |
| This is <<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> <3<supports <4<a syntax>3> for overlapping spans>4>. | |
| Actual <<annotations>A> are based on RDF triples, and are included in one or more sections like the following one: | |
| +++ | |
| A foaf:page https://en.wikipedia.org/wiki/Annotation | |
| +++ | |
| ''' | |
| } | |
| @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() | |
| @triple_section_highlight() | |
| 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.start.line-1, ch: s.start_code_location.start.column-1}, {line: s.end_code_location.end.line-1, ch: s.end_code_location.end.column-1}, {className: 'span'} | |
| triple_section_highlight: () -> | |
| in_section = false | |
| line_number = 0 | |
| @editor.eachLine (l) => | |
| @editor.removeLineClass line_number, 'background' | |
| @editor.removeLineClass line_number, 'text' | |
| if in_section | |
| @editor.addLineClass line_number, 'background', 'triple_section' | |
| @editor.addLineClass line_number, 'text', 'triple_section_text' | |
| # triple section open | |
| if l.text is '+++' and in_section | |
| in_section = not in_section | |
| @editor.addLineClass line_number, 'background', 'triple_section_close' | |
| # triple section close | |
| else if l.text is '+++' | |
| in_section = not in_section | |
| @editor.addLineClass line_number, 'background', 'triple_section_open' | |
| line_number++ | |
| return false |
| .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(31,118,180,0.085); | |
| } | |
| .Editor .angle_bracket { | |
| font-weight: bold; | |
| color: rgba(31,118,180,1); | |
| } | |
| .Editor .about_resource { | |
| color: #ff7f0e; | |
| font-weight: bold; | |
| } | |
| .Editor .directive { | |
| background: rgba(255, 177, 0, 0.05); | |
| color: #444; | |
| } | |
| .Editor .directive_block_opener { | |
| border-top: 1px solid #DDD; | |
| background: rgba(255, 177, 0, 0.05); | |
| } | |
| .Editor .directive_block_closer { | |
| background: rgba(255, 177, 0, 0.05); | |
| } | |
| .Editor :not(:last-child) > .directive_block_closer { | |
| border-bottom: 1px solid #DDD; | |
| } | |
| .Editor .directive_block_code { | |
| color: #555; | |
| } | |
| .Editor .error { | |
| background: rgba(255,0,0,0.2); | |
| border-bottom: 2px solid red; | |
| } | |
| .Editor .code { | |
| font-family: monospace; | |
| font-size: 11px; | |
| } | |
| /* Codemirror highlighting | |
| */ | |
| .Editor .cm-span_open, .Editor .cm-span_close, .Editor .cm-subject { | |
| color: rgba(31,118,180,1); | |
| font-weight: bold; | |
| } | |
| .Editor .cm-triple_section_open, .Editor .cm-triple_section_close { | |
| color: #444; | |
| } | |
| .Editor .triple_section, .Editor .triple_section_open, .Editor .triple_section_close { | |
| background: rgba(255, 177, 0, 0.05); | |
| } | |
| .Editor .triple_section_text { | |
| font-family: monospace; | |
| } | |
| .Editor .triple_section_open { | |
| border-top: 1px solid #DDD; | |
| } | |
| .Editor :not(:last-child) > .triple_section_close { | |
| border-bottom: 1px solid #DDD; | |
| } | |
| .Editor .cm-predicate, .Editor .cm-object { | |
| color: #444; | |
| } | |
| .Editor .cm-literal { | |
| font-family: sans-serif; | |
| } |
| // 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); | |
| CodeMirror.defineSimpleMode('hl', { | |
| start: [ | |
| { | |
| regex: new RegExp('<[a-zA-Z0-9][_a-zA-Z0-9]*<'), | |
| token: 'span_open' | |
| }, { | |
| regex: new RegExp('<<'), | |
| token: 'span_open' | |
| }, { | |
| regex: new RegExp('>[a-zA-Z0-9][_a-zA-Z0-9]*>'), | |
| token: 'span_close' | |
| }, { | |
| regex: new RegExp('>>'), | |
| token: 'span_close' | |
| }, { | |
| regex: new RegExp('^\\+\\+\\+$'), | |
| token: 'triple_section_open', | |
| next: 'triple_section' | |
| } | |
| ], | |
| triple_section: [ | |
| { | |
| regex: new RegExp('^\\+\\+\\+$'), | |
| token: 'triple_section_close', | |
| next: 'start' | |
| }, { | |
| regex: new RegExp('(^[^ \t]*)([ \t]+)([^ \t]*)([ \t]+)(".*"$)'), | |
| token: ['subject', '', 'predicate', '', 'literal'] | |
| }, { | |
| regex: new RegExp('(^[^ \t]*)([ \t]+)([^ \t]*)([ \t]+)([^" \t]*$)'), | |
| token: ['subject', '', 'predicate', '', 'object'] | |
| } | |
| ] | |
| }); | |
| this.editor = CodeMirror(wrapper.node(), { | |
| lineWrapping: true, | |
| value: 'This is <<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> <3<supports <4<a syntax>3> for overlapping spans>4>.\n\nActual <<annotations>A> are based on RDF triples, and are included in one or more sections like the following one:\n+++\nA foaf:page https://en.wikipedia.org/wiki/Annotation\n+++' | |
| }); | |
| 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(); | |
| }); | |
| this.triple_section_highlight(); | |
| 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) { | |
| return _this.editor.markText({ | |
| line: s.start_code_location.start.line - 1, | |
| ch: s.start_code_location.start.column - 1 | |
| }, { | |
| line: s.end_code_location.end.line - 1, | |
| ch: s.end_code_location.end.column - 1 | |
| }, { | |
| className: 'span' | |
| }); | |
| }; | |
| })(this)); | |
| }, | |
| triple_section_highlight: function() { | |
| var in_section, line_number; | |
| in_section = false; | |
| line_number = 0; | |
| return this.editor.eachLine((function(_this) { | |
| return function(l) { | |
| _this.editor.removeLineClass(line_number, 'background'); | |
| _this.editor.removeLineClass(line_number, 'text'); | |
| if (in_section) { | |
| _this.editor.addLineClass(line_number, 'background', 'triple_section'); | |
| _this.editor.addLineClass(line_number, 'text', 'triple_section_text'); | |
| } | |
| if (l.text === '+++' && in_section) { | |
| in_section = !in_section; | |
| _this.editor.addLineClass(line_number, 'background', 'triple_section_close'); | |
| } else if (l.text === '+++') { | |
| in_section = !in_section; | |
| _this.editor.addLineClass(line_number, 'background', 'triple_section_open'); | |
| } | |
| line_number++; | |
| return false; | |
| }; | |
| })(this)); | |
| } | |
| }); | |
| }).call(this); |
| app = new AppView | |
| el: 'body' | |
| model: new Data |
| <!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> |
| // Generated by CoffeeScript 1.10.0 | |
| (function() { | |
| window.Table = Backbone.D3View.extend({ | |
| namespace: null, | |
| tagName: 'table', | |
| initialize: function() { | |
| return this.listenTo(this.model, 'change:rows', this.render); | |
| }, | |
| render: function() { | |
| var data_cells, header, header_cells, rows, rows_data; | |
| rows_data = this.model.get('rows'); | |
| header = rows_data.length > 0 ? Object.keys(rows_data[0]) : []; | |
| this.d3el.selectAll('*').remove(); | |
| header_cells = this.d3el.append('tr').selectAll('th').data(header); | |
| header_cells.enter().append('th').text(function(d) { | |
| return d; | |
| }); | |
| rows = this.d3el.append('tbody').selectAll('tr').data(rows_data); | |
| rows.enter().append('tr'); | |
| data_cells = rows.selectAll('td').data(function(d) { | |
| return Object.keys(d).map(function(k) { | |
| return d[k]; | |
| }); | |
| }); | |
| return data_cells.enter().append('td').text(function(d) { | |
| return d; | |
| }); | |
| } | |
| }); | |
| }).call(this); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment