Show xanaflight in xanaviewer
This commit is contained in:
parent
9eecd4f490
commit
155c15741d
|
@ -42,7 +42,7 @@ def parse_edl(edl_text):
|
|||
|
||||
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)
|
||||
spans = edl['spans']
|
||||
|
||||
|
@ -83,7 +83,7 @@ def fulfil_edl_with_sources(edl_text):
|
|||
|
||||
doc_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]
|
||||
new_text = ''
|
||||
pos = start
|
||||
|
|
|
@ -68,6 +68,12 @@ def parse_sourcedoc_facet(facet):
|
|||
assert leg.startswith(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):
|
||||
link_type = None
|
||||
expect = 'link_type'
|
||||
|
|
353
sourcing/static/js/xanaflight.js
Normal file
353
sourcing/static/js/xanaflight.js
Normal 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);
|
||||
}
|
62
sourcing/templates/view/xanaflight.html
Normal file
62
sourcing/templates/view/xanaflight.html
Normal 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>
|
|
@ -6,6 +6,7 @@ from .forms import (LoginForm, SignupForm, AccountSettingsForm,
|
|||
UploadSourceDocForm, SourceDocForm, ItemForm,
|
||||
ForgotPasswordForm, PasswordForm)
|
||||
from .model import User, SourceDoc, Item, XanaDoc, XanaLink, Reference
|
||||
from .parse import parse_xanapage_facet
|
||||
from .url import get_url
|
||||
from .mail import send_mail
|
||||
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):
|
||||
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')
|
||||
def fulfil(username, hashid):
|
||||
item = get_xanadoc(username, hashid)
|
||||
item = get_item(username, hashid)
|
||||
|
||||
return render_template('view/xanadoc.html',
|
||||
item=item,
|
||||
doc=fulfil_edl_with_sources(item.text))
|
||||
if item.type == 'xanadoc':
|
||||
return render_template('view/xanadoc.html',
|
||||
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'])
|
||||
def set_title(username, hashid):
|
||||
|
|
Loading…
Reference in a new issue