Show xanaflight in xanaviewer

This commit is contained in:
Edward Betts 2018-12-05 14:39:01 +00:00
parent 9eecd4f490
commit 155c15741d
5 changed files with 446 additions and 6 deletions

View file

@ -42,7 +42,7 @@ def parse_edl(edl_text):
return edl return edl
def fulfil_edl_with_sources(edl_text): def fulfil_edl_with_sources(edl_text, hide_all_transclusions=False):
edl = parse_edl(edl_text) edl = parse_edl(edl_text)
spans = edl['spans'] spans = edl['spans']
@ -83,7 +83,7 @@ def fulfil_edl_with_sources(edl_text):
doc_spans = [] doc_spans = []
for num, (url, start, length) in spans: for num, (url, start, length) in spans:
highlight = url not in hide_transclusions highlight = not hide_all_transclusions and url not in hide_transclusions
span_text = source_text[url] # [start:start + length] span_text = source_text[url] # [start:start + length]
new_text = '' new_text = ''
pos = start pos = start

View file

@ -68,6 +68,12 @@ def parse_sourcedoc_facet(facet):
assert leg.startswith(prefix) assert leg.startswith(prefix)
return leg[len(prefix):] return leg[len(prefix):]
def parse_xanapage_facet(facet):
leg = facet[0]
prefix = 'xanapage: '
assert leg.startswith(prefix)
return leg[len(prefix):]
def parse_link(link_text): def parse_link(link_text):
link_type = None link_type = None
expect = 'link_type' expect = 'link_type'

View file

@ -0,0 +1,353 @@
'use strict';
var doc1 = document.getElementById('doc1');
var edlform = document.getElementById('edlform');
var max_zindex = 0;
var bridge_count = 0;
var link_bridge_count = 0;
var payment_params = {};
var payment_content;
var xnb_per_char = 150000;
function listener (event) {
console.log(event.type, event.pageX, event.pageY);
}
function hl_location(hl) {
var rects = hl.getClientRects();
var top = rects[0].top;
var right = rects[0].right;
var bottom = rects[rects.length-1].bottom
var left = rects[rects.length-1].left;
console.log(top, right, bottom, left);
}
function dragMoveListener (event) {
var target = event.target,
// keep the dragged position in the data-x/data-y attributes
x = (parseFloat(target.getAttribute('data-x')) || 0) + event.dx,
y = (parseFloat(target.getAttribute('data-y')) || 0) + event.dy;
update_location(target, x, y);
update();
}
function update() {
for(var i = 0; i < bridge_count; i++) {
update_bridge('bridge' + i, 'span' + i, 'transclusion' + i);
}
for(var i = 0; i < link_bridge_count; i++) {
update_bridge('linkbridge' + i, 'xanalink' + i, 'link' + i);
}
}
function update_bridge(bridge, name_h1, name_h2) {
var points = []
var h1 = document.getElementById(name_h1);
var h2 = document.getElementById(name_h2);
if (!h1) {
return;
}
if (!h2) {
return; // because we skipped the large document
}
var rect1 = h1.getBoundingClientRect();
var rect2 = h2.getBoundingClientRect();
var h1_x_center = rect1.right - rect1.width / 2;
var h2_x_center = rect2.right - rect2.width / 2;
var bridge_element = document.getElementById(bridge);
var h_l, h_r, rect_l, rect_r;
if (h1_x_center < h2_x_center) {
h_l = h1;
h_r = h2;
rect_l = rect1;
rect_r = rect2;
} else {
h_l = h2;
h_r = h1;
rect_l = rect2;
rect_r = rect1;
}
var body_l = $(h_l).closest(".body").get(0).getBoundingClientRect();
var body_r = $(h_r).closest(".body").get(0).getBoundingClientRect();
var left_bottom = rect_l.bottom;
if(left_bottom < body_l.top) {
left_bottom = body_l.top;
} else if (left_bottom > body_l.bottom) {
left_bottom = body_l.bottom;
}
var left_top = rect_l.top;
if(left_top < body_l.top) {
left_top = body_l.top;
} else if (left_top > body_l.bottom) {
left_top = body_l.bottom;
}
var right_bottom = rect_r.bottom;
if(right_bottom < body_r.top) {
right_bottom = body_r.top;
} else if (right_bottom > body_r.bottom) {
right_bottom = body_r.bottom;
}
var right_top = rect_r.top;
if(right_top < body_r.top) {
right_top = body_r.top;
} else if (right_top > body_r.bottom) {
right_top = body_r.bottom;
}
points.push(rect_l.right + ',' + left_top);
points.push(rect_l.right + ',' + left_bottom);
points.push(rect_r.left + ',' + right_bottom);
points.push(rect_r.left + ',' + right_top);
var poly = document.getElementById(bridge);
poly.setAttribute('points', points.join(' '));
}
function update_location(target, x, y) {
// target.style.transform = 'scale(0.75) translate(' + x + 'px, ' + y + 'px)';
target.style.transform = 'translate(' + x + 'px, ' + y + 'px)';
target.setAttribute('data-x', x);
target.setAttribute('data-y', y);
max_zindex += 1;
target.style.zIndex = max_zindex;
}
function resizemove(event) {
var target = event.target,
x = (parseFloat(target.getAttribute('data-x')) || 0),
y = (parseFloat(target.getAttribute('data-y')) || 0);
// update the element's style
target.style.width = event.rect.width + 'px';
target.style.height = event.rect.height + 'px';
// translate when resizing from top or left edges
x += event.deltaRect.left;
y += event.deltaRect.top;
update_location(target, x, y);
update();
}
interact('.document')
.draggable({
onmove: dragMoveListener,
})
.resizable({
// preserveAspectRatio: false,
edges: { left: true, right: true, bottom: true, top: true },
})
.on('resizemove', resizemove)
.actionChecker(function (pointer, event, action, interactable, element, interaction) {
if (!interact.matchesSelector(event.target, '.heading') && action.name == 'drag') {
return;
}
return action;
});
interact('#edlform')
.draggable({
onmove: dragMoveListener,
})
.on('resizemove', resizemove)
.actionChecker(function (pointer, event, action, interactable, element, interaction) {
if (!interact.matchesSelector(event.target, '.heading') && action.name == 'drag') {
return;
}
return action;
});
// doc1.style.height = '400px';
// update_location(doc1, 200, 50);
var docid = 0;
function new_document(doc) {
var source = $("#document-template").html();
var template = Handlebars.compile(source);
docid++;
var context = {
docid: docid,
heading: doc.heading,
doctype: doc.doctype,
text: doc.text
};
var element = $(template(context));
var w = document.documentElement.clientWidth;
var h = document.documentElement.clientHeight;
var x = Math.random() * (w - 400);
var y = Math.random() * (h - 400);
update_location(element.get(0), x, y);
$("#top").append(element);
}
function reset() {
$(".document").remove();
var svg = document.getElementById('svg');
while (svg.firstChild) {
svg.removeChild(svg.firstChild);
}
bridge_count = 0;
link_bridge_count = 0;
}
$("button#clear").click(function(event) {
$("#edl").val("");
reset();
});
function get_end_number(str) {
var len = str.length;
var num;
for(var i = 0; i < len; i++) {
if(!isNaN(num = parseInt(str.substr(i))))
return num;
}
throw "no number found";
}
function hover_bridge(element, hover) {
var num = get_end_number(element.id);
var bridge = document.getElementById('bridge' + num);
bridge.setAttribute("class", hover ? 'hoverbridge' : 'bridge');
var cls = 'hovertransclusion';
if (hover) {
$('#transclusion' + num).addClass(cls);
$('#span' + num).addClass(cls);
} else {
$('#transclusion' + num).removeClass(cls);
$('#span' + num).removeClass(cls);
}
}
function hover_link_bridge(element, hover) {
var num = get_end_number(element.id);
var bridge = document.getElementById('linkbridge' + num);
bridge.setAttribute("class", hover ? 'hoverlinkbridge' : 'linkbridge');
var cls = 'hoverlink';
if (hover) {
$('#xanalink' + num).addClass(cls);
$('#link' + num).addClass(cls);
} else {
$('#xanalink' + num).removeClass(cls);
$('#link' + num).removeClass(cls);
}
}
function fulfil(doc) {
bridge_count = doc.span_count;
link_bridge_count = doc.link_count;
var svg_element = document.getElementById('svg');
for(var i = 0; i < doc.link_count; i++) {
var p = document.createElementNS('http://www.w3.org/2000/svg', 'polygon');
p.setAttribute('id', 'linkbridge' + i);
p.setAttribute('class', 'linkbridge');
p.setAttribute('visibility', 'hidden');
p.addEventListener('mouseover', function(e) {
hover_link_bridge(this, true);
});
p.addEventListener('mouseout', function(e) {
hover_link_bridge(this, false);
});
svg_element.appendChild(p);
}
new_document({'heading': 'xanadoc',
'text': doc.doc,
'doctype': 'xanadoc'});
update();
$('.link').bind('mouseover', function(e) {
hover_link_bridge(this, true);
});
$('.link').bind('mouseout', function(e) {
hover_link_bridge(this, false);
});
$('.xanadoclink').click(function(e) {
var num = get_end_number(this.id);
var source = $('#link' + num).closest( ".sourcedoc" );
var bridge1 = document.getElementById('linkbridge' + num);
var cur_state = bridge1.getAttribute('visibility');
var new_state = cur_state == 'hidden' ? 'visible' : 'hidden';
source.find('.sourcedoclink').each(function(index, value) {
var bridge_num = get_end_number(value.id);
var bridge = document.getElementById('linkbridge' + bridge_num);
bridge.setAttribute('visibility', new_state);
});
source.toggle();
update();
});
$('.xanadoctransclusion').click(function(e) {
var num = get_end_number(this.id);
var source = $('#transclusion' + num).closest( ".sourcedoc" );
var bridge1 = document.getElementById('bridge' + num);
var cur_state = bridge1.getAttribute('visibility');
var new_state = cur_state == 'hidden' ? 'visible' : 'hidden';
source.find('.sourcedoctransclusion').each(function(index, value) {
var bridge_num = get_end_number(value.id);
var bridge = document.getElementById('bridge' + bridge_num);
bridge.setAttribute('visibility', new_state);
});
source.toggle();
update();
});
$('.body').bind('scroll', function(event) {
update();
});
$('.sourcedoc').hide();
}
function size_svg() {
var w = document.documentElement.clientWidth - 10;
var h = document.documentElement.clientHeight - 10;
$('svg').width(w);
$('svg').height(h);
}

View file

@ -0,0 +1,62 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{{ title | default("Xanadu") }}</title>
<link rel="stylesheet" href="{{ url_for('static', filename='bootstrap4/css/bootstrap.css') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='css/xanadoc.css') }}">
</head>
<body>
{% include "navbar.html" %}
<div class="container-fluid">
{% include "flash_msg.html" %}
{% raw %}
<script id="document-template" type="text/x-handlebars-template">
<div class="document {{ doctype }}" id="doc{{ docid }}">
<div class="heading" id="head{{ docid }}">{{ heading }}</div>
<div class="wrapper">
<div class="body" id="body{{ docid }}">
{{{ text }}}
</div>
</div>
</div>
</script>
{% endraw %}
<svg id="svg" version="1.2" xmlns="http://www.w3.org/2000/svg">
</svg>
<div id="top">
</div>
<script src="{{ url_for('static', filename='jquery/jquery.js') }}"></script>
<script src="{{ url_for('static', filename='bootstrap/js/bootstrap.js') }}"></script>
<script>
</script>
<script src="{{ url_for('static', filename='js/interact.js') }}"></script>
<script src="{{ url_for('static', filename='js/xanaflight.js') }}"></script>
<script src="{{ url_for('static', filename='handlebars/handlebars.js') }}"></script>
<script>
var get_span_path = "{{ url_for('.get_span') }}";
var docs = {{ docs | tojson }};
$(function() {
size_svg();
$(window).resize(size_svg);
reset(); // clear all documents and bridges
docs.forEach(fulfil);
});
</script>
</body>
</html>

View file

@ -6,6 +6,7 @@ from .forms import (LoginForm, SignupForm, AccountSettingsForm,
UploadSourceDocForm, SourceDocForm, ItemForm, UploadSourceDocForm, SourceDocForm, ItemForm,
ForgotPasswordForm, PasswordForm) ForgotPasswordForm, PasswordForm)
from .model import User, SourceDoc, Item, XanaDoc, XanaLink, Reference from .model import User, SourceDoc, Item, XanaDoc, XanaLink, Reference
from .parse import parse_xanapage_facet
from .url import get_url from .url import get_url
from .mail import send_mail from .mail import send_mail
from .edl import fulfil_edl_with_sources, fulfil_edl, parse_edl from .edl import fulfil_edl_with_sources, fulfil_edl, parse_edl
@ -234,13 +235,31 @@ def realize_edl(username, hashid):
def view_item_raw(username, hashid): def view_item_raw(username, hashid):
return view_item(username, hashid, raw=True) return view_item(username, hashid, raw=True)
def fulfil_xanaflight(item):
link = item.parse()
assert link['type'] == 'flight'
facets = link['facets']
docs = []
for facet in facets:
xanapage = Item.from_external(parse_xanapage_facet(facet))
assert xanapage.type == 'xanadoc'
doc = fulfil_edl_with_sources(xanapage.text, hide_all_transclusions=True)
doc['hashid'] = xanapage.hashid
print(doc)
print()
docs.append(doc)
return render_template('view/xanaflight.html', item=item, docs=docs)
@bp.route('/<username>/<hashid>/fulfil') @bp.route('/<username>/<hashid>/fulfil')
def fulfil(username, hashid): def fulfil(username, hashid):
item = get_xanadoc(username, hashid) item = get_item(username, hashid)
return render_template('view/xanadoc.html', if item.type == 'xanadoc':
item=item, return render_template('view/xanadoc.html',
doc=fulfil_edl_with_sources(item.text)) item=item,
doc=fulfil_edl_with_sources(item.text))
if item.type == 'xanalink' and item.text.startswith('type=flight'):
return fulfil_xanaflight(item)
@bp.route('/<username>/<hashid>/set_title', methods=['POST']) @bp.route('/<username>/<hashid>/set_title', methods=['POST'])
def set_title(username, hashid): def set_title(username, hashid):