From 994fccf764d90da68745cf8f24bc8350808e951e Mon Sep 17 00:00:00 2001
From: Edward Betts <edward@4angle.com>
Date: Fri, 26 Apr 2019 12:56:53 +0100
Subject: [PATCH] Working implementation of editing.

---
 sourcing/edit.py                 |  4 +++
 sourcing/span.py                 |  3 +++
 sourcing/static/js/xanaedit.js   | 10 +++----
 sourcing/templates/xanaedit.html | 12 ++++++---
 sourcing/view.py                 | 46 +++++++++++++++++++++++---------
 5 files changed, 53 insertions(+), 22 deletions(-)

diff --git a/sourcing/edit.py b/sourcing/edit.py
index 653c458..5f6cf1d 100644
--- a/sourcing/edit.py
+++ b/sourcing/edit.py
@@ -83,6 +83,10 @@ def apply_edits(spans, edits):
         if edit['op'] == 'insert':
             spans = apply_insert(spans, edit)
             continue
+        if edit['op'] == 'replace':
+            spans = apply_delete(spans, edit)
+            spans = apply_insert(spans, edit)
+            continue
 
     return spans
 
diff --git a/sourcing/span.py b/sourcing/span.py
index 08f9cd8..5d0a6e4 100644
--- a/sourcing/span.py
+++ b/sourcing/span.py
@@ -16,3 +16,6 @@ class Span:
 
     def end(self) -> int:
         return self.start + self.length
+
+    def for_edl(self) -> str:
+        return f'{self.url},start={self.start},length={self.length}'
diff --git a/sourcing/static/js/xanaedit.js b/sourcing/static/js/xanaedit.js
index 3e117fe..1172f95 100644
--- a/sourcing/static/js/xanaedit.js
+++ b/sourcing/static/js/xanaedit.js
@@ -21,7 +21,7 @@ var changes = document.getElementById("changes");
 
 var edits = [];
 
-editor.value = text;;
+editor.value = text;
 
 function update_list_of_edits() {
     changes.innerHTML = null;
@@ -29,11 +29,11 @@ function update_list_of_edits() {
       var update;
       var start = edit.start + 1;
       if (edit.op == 'insert') {
-        update = start + ' insert: [' + edit.new + ']';
+        update = start + ' insert: [' + JSON.stringify(edit.new) + ']';
       } else if (edit.op == 'delete') {
-        update = start + ' delete: [' + edit.old + ']';
+        update = start + ' delete: [' + JSON.stringify(edit.old) + ']';
       } else if (edit.op == 'replace') {
-        update = start + ' replace: [' + edit.old + '] with [' + edit.new + ']';
+        update = start + ' replace: [' + JSON.stringify(edit.old) + '] with [' + JSON.stringify(edit.new) + ']';
       }
       var div = document.createElement("div");
       div.innerHTML = update;
@@ -52,7 +52,7 @@ function update_buttons () {
 }
 
 function update(e) {
-    var current = editor.value;
+    var current = editor.value.replace(/\n/g, '\r\n');
     if (current == text)  // no change
       return
 
diff --git a/sourcing/templates/xanaedit.html b/sourcing/templates/xanaedit.html
index 01bce88..a798903 100644
--- a/sourcing/templates/xanaedit.html
+++ b/sourcing/templates/xanaedit.html
@@ -16,14 +16,18 @@
   <div class="col-8">
 
     <p>
+    {#
     <button class="btn btn-primary save-btn" id="save-btn" disabled>save, continue editing</button>
-    <button type="submit" class="btn btn-primary save-btn" id="finish-btn" disabled>save and finish</button>
-    <a href="{{ doc.url }}" class="btn btn-secondary" id="cancel-btn">back to view page</a>
+    #}
+    <button type="submit" class="btn btn-primary save-btn" id="finish-btn" disabled>save changes</button>
+    <a href="{{ doc.url }}" class="btn btn-secondary" id="cancel-btn">forget changes</a>
     </p>
 
     <textarea id="editor" rows="16" class="w-100" autofocus></textarea>
   </div>
-  <div class="col-4" id="changes">
+  <div class="col-4">
+    <h4>changes</h4>
+    <div id="changes"></div>
   </div>
 </div>
 
@@ -33,7 +37,7 @@
 
 {% block scripts %}
 <script>
-var text = {{ doc_text.replace('\r\n', '\n')|tojson }};
+var text = {{ doc_text|tojson }};
 </script>
 <script src="{{ url_for('static', filename='js/xanaedit.js') }}"></script>
 {% endblock %}
diff --git a/sourcing/view.py b/sourcing/view.py
index 28fa72a..ab465de 100644
--- a/sourcing/view.py
+++ b/sourcing/view.py
@@ -20,7 +20,6 @@ from functools import wraps
 from .utils import nbsp_at_start
 from itsdangerous import URLSafeTimedSerializer
 # from sqlalchemy_continuum import version_class
-from pprint import pformat
 
 import json
 import re
@@ -413,8 +412,13 @@ def create_xanapage_from_sourcedoc(username, hashid):
     flash('New xanapage created.')
     return redirect(page.url)
 
-@bp.route('/<username>/<hashid>/xanaedit')
+@bp.route('/<username>/<hashid>/xanaedit', methods=['GET', 'POST'])
 def xanaedit_item(username, hashid):
+    if request.method == 'POST':
+        save_xanaedit(username, hashid)
+
+        return redirect(url_for('xanaedit_item', username=username, hashid=hashid))
+
     doc = get_xanapage(username, hashid)
 
     spans = list(fulfil_edl(doc.text))
@@ -422,29 +426,45 @@ def xanaedit_item(username, hashid):
 
     return render_template('xanaedit.html', doc=doc, doc_text=doc_text)
 
-@bp.route('/<username>/<hashid>/xanaedit', methods=['POST'])
 def save_xanaedit(username, hashid):
-    # doc = get_xanapage(username, hashid)
-    edits = json.loads(request.form['edits'])
-    return jsonify(edits=edits)
-
-@bp.route('/<username>/<hashid>/finish', methods=['POST'])
-def finish_xanaedit(username, hashid):
-    doc = get_xanapage(username, hashid)
-    current_edl = parse_edl(doc.text)
+    page = get_xanapage(username, hashid)
+    current_edl = parse_edl(page.text)
 
     spans = [Span(*span) for span in current_edl['spans']]
     edits = json.loads(request.form['edits'])
     new_text = ''
     new_text_pos = 0
     for edit in edits:
-        if edit['op'] != 'insert':
+        if edit['op'] not in ('insert', 'replace'):
             continue
         new_text += edit['new']
         edit['span'] = Span('placeholder', new_text_pos, len(edit['new']))
         new_text_pos += len(edit['new'])
     spans = apply_edits(spans, edits)
-    return Response(pformat(spans), mimetype='text/plain')
+
+    new_src_doc = SourceDoc(user=current_user, text=new_text)
+    session.add(new_src_doc)
+    session.commit()
+
+    for span in spans:
+        if span.url == 'placeholder':
+            span.url = new_src_doc.external_url
+
+    new_edl = ''.join(f'span: {span.for_edl()}\n' for span in spans)
+
+    page.text = new_edl
+    session.commit()
+
+    flash('Edits saved.')
+
+    return page
+
+@bp.route('/<username>/<hashid>/finish', methods=['POST'])
+def finish_xanaedit(username, hashid):
+
+    page = save_xanaedit(username, hashid)
+
+    return redirect(page.url)
 
 @bp.route('/<username>/<hashid>/edit', methods=['GET', 'POST'])
 def edit_item(username, hashid):