summaryrefslogtreecommitdiffstats
path: root/python/fatcat_web
diff options
context:
space:
mode:
Diffstat (limited to 'python/fatcat_web')
-rw-r--r--python/fatcat_web/forms.py37
-rw-r--r--python/fatcat_web/routes.py50
-rw-r--r--python/fatcat_web/templates/edit_macros.html36
-rw-r--r--python/fatcat_web/templates/release_create.html254
-rw-r--r--python/fatcat_web/templates/release_edit.html231
5 files changed, 345 insertions, 263 deletions
diff --git a/python/fatcat_web/forms.py b/python/fatcat_web/forms.py
index baff62d7..632e36c6 100644
--- a/python/fatcat_web/forms.py
+++ b/python/fatcat_web/forms.py
@@ -6,7 +6,7 @@ but can't find one that is actually maintained.
from flask_wtf import FlaskForm
from wtforms import SelectField, DateField, StringField, IntegerField, \
- FormField, FieldList, validators
+ HiddenField, FormField, FieldList, validators
from fatcat_client import ContainerEntity, CreatorEntity, FileEntity, \
ReleaseEntity, ReleaseContrib
@@ -51,6 +51,7 @@ class ReleaseContribForm(FlaskForm):
#given_name
#creator_id (?)
#orcid (for match?)
+ prev_index = HiddenField('prev_revision index', default=None)
raw_name = StringField('Display Name',
[validators.DataRequired()])
role = SelectField(
@@ -108,7 +109,14 @@ class ReleaseEntityForm(EntityEditForm):
"""
ref = ReleaseEntityForm()
for simple_attr in RELEASE_SIMPLE_ATTRS:
- setattr(ref, simple_attr, getattr(re, simple_attr))
+ a = getattr(ref, simple_attr)
+ a.data = getattr(re, simple_attr)
+ for i, c in enumerate(re.contribs):
+ rcf = ReleaseContribForm()
+ rcf.prev_index = i
+ rcf.role = c.role
+ rcf.raw_name = c.raw_name
+ ref.contribs.append_entry(rcf)
return ref
def to_entity(self):
@@ -130,13 +138,26 @@ class ReleaseEntityForm(EntityEditForm):
if a == '':
a = None
setattr(re, simple_attr, a)
- # TODO: don't update authors unless necessary!
- re.contribs = []
+ # bunch of complexity here to preserve old contrib metadata (eg,
+ # affiliation and extra) not included in current forms
+ # TODO: this may be broken; either way needs tests
+ if re.contribs:
+ old_contribs = re.contribs.copy()
+ re.contribs = []
+ else:
+ old_contribs = []
+ re.contribs = []
for c in self.contribs:
- re.contribs.append(ReleaseContrib(
- role=c.role.data or None,
- raw_name=c.raw_name.data or None,
- ))
+ if c.prev_index.data not in ('', None):
+ rc = old_contribs[int(c.prev_index.data)]
+ rc.role = c.role.data or None
+ rc.raw_name = c.raw_name.data or None
+ else:
+ rc = ReleaseContrib(
+ role=c.role.data or None,
+ raw_name=c.raw_name.data or None,
+ )
+ re.contribs.append(rc)
if self.edit_description.data:
re.edit_extra = dict(description=self.edit_description.data)
diff --git a/python/fatcat_web/routes.py b/python/fatcat_web/routes.py
index eb62d338..118f402b 100644
--- a/python/fatcat_web/routes.py
+++ b/python/fatcat_web/routes.py
@@ -325,7 +325,7 @@ def release_create():
user_api = auth_api(session['api_token'])
if form.editgroup_id.data:
# TODO: error handling
- eg = api.get_editgroup(form.editgroup_id.data)
+ eg = user_api.get_editgroup(form.editgroup_id.data)
else:
# if no editgroup, create one from description
eg = user_api.create_editgroup(
@@ -345,8 +345,9 @@ def release_create():
print("didn't validate...")
elif len(form.contribs) == 0:
form.contribs.append_entry()
- # TODO: check for editgroup in session
- editgroup_id = session.get('active_editgroup_id', None)
+ if not form.is_submitted():
+ editgroup_id = session.get('active_editgroup_id', None)
+ form.editgroup_id.data = editgroup_id
return render_template('release_create.html',
form=form, editgroup_id=editgroup_id)
@@ -363,13 +364,50 @@ def release_history(ident):
entity=entity,
history=history)
-@app.route('/release/<ident>/edit', methods=['GET'])
-def release_edit_view(ident):
+# XXX: figure out CSRF stuff for local dev
+@login_required
+@app.csrf.exempt
+@app.route('/release/<ident>/edit', methods=['GET', 'POST'])
+def release_edit(ident):
+ # TODO: prev_rev interlock
+ # TODO: factor out editgroup active/creation stuff
try:
entity = api.get_release(ident)
except ApiException as ae:
abort(ae.status)
- return render_template('entity_edit.html')
+ form = ReleaseEntityForm(csrf_enabled=False) # XXX:
+ if form.is_submitted():
+ if form.validate_on_submit():
+ # API on behalf of user
+ user_api = auth_api(session['api_token'])
+ if form.editgroup_id.data:
+ # TODO: error handling
+ eg = user_api.get_editgroup(form.editgroup_id.data)
+ else:
+ # if no editgroup, create one from description
+ eg = user_api.create_editgroup(
+ Editgroup(description=form.editgroup_description.data or None))
+ # set this session editgroup_id
+ session['active_editgroup_id'] = eg.editgroup_id
+ print(eg.editgroup_id) # XXX: debug
+ flash('Started new editgroup <a href="/editgroup/{}">{}</a>' \
+ .format(eg.editgroup_id, eg.editgroup_id))
+ # all the tricky logic is in the update method
+ form.update_entity(entity)
+ edit = user_api.update_release(entity.ident, entity,
+ editgroup_id=eg.editgroup_id)
+ # redirect to release revision
+ # TODO: release_rev_view
+ return redirect('/release/{}'.format(edit.ident))
+ elif form.errors:
+ print("user form errors (didn't validate): {}".format(form.errors))
+ else:
+ form = ReleaseEntityForm.from_entity(entity)
+ if not form.is_submitted():
+ editgroup_id = session.get('active_editgroup_id', None)
+ form.editgroup_id.data = editgroup_id
+ return render_template('release_edit.html',
+ form=form, editgroup_id=editgroup_id, entity=entity)
@app.route('/release/<ident>', methods=['GET'])
def release_view(ident):
diff --git a/python/fatcat_web/templates/edit_macros.html b/python/fatcat_web/templates/edit_macros.html
new file mode 100644
index 00000000..ad563066
--- /dev/null
+++ b/python/fatcat_web/templates/edit_macros.html
@@ -0,0 +1,36 @@
+
+{% macro form_field_errors(field) -%}
+ {% if field.errors %}
+ <div class="ui pointing red label">
+ {% for err in field.errors %}
+ {{ err }}
+ {% endfor %}
+ </div>
+ {% endif %}
+{%- endmacro %}
+
+{% macro form_field_basic(field, div_classes="") -%}
+<div class="field {{ div_classes }} {% if field.errors %}error{% endif %}">
+ {{ field.label }}
+ {{ field() }}
+ {{ form_field_errors(field) }}
+</div>
+{%- endmacro %}
+
+{% macro form_field_inline(field, div_classes="") -%}
+<div class="ui grid">
+ <div class="three wide column middle aligned right aligned" {# style="padding-right: 0.5rem;" #}>
+ <div class="field inline {{ div_classes }} {% if field.errors %}error{% endif %}">
+ {{ field.label }}
+ </div>
+ </div>
+ <div class="twelve wide column" {# style="padding-left: 0.5rem;" #}>
+ <div class="field {{ div_classes }} {% if field.errors %}error{% endif %}">
+ {{ field() }}
+ {{ form_field_errors(field) }}
+ </div>
+ </div>
+ <div class="one wide column">
+ </div>
+</div>
+{%- endmacro %}
diff --git a/python/fatcat_web/templates/release_create.html b/python/fatcat_web/templates/release_create.html
index 7ede5dfd..5ea3470d 100644
--- a/python/fatcat_web/templates/release_create.html
+++ b/python/fatcat_web/templates/release_create.html
@@ -1,260 +1,16 @@
-{% extends "base.html" %}
+{% extends "release_edit.html" %}
-{% macro form_field_errors(field) -%}
- {% if field.errors %}
- <div class="ui pointing red label">
- {% for err in field.errors %}
- {{ err }}
- {% endfor %}
- </div>
- {% endif %}
-{%- endmacro %}
-
-{% macro form_field_basic(field, div_classes="") -%}
-<div class="field {{ div_classes }} {% if field.errors %}error{% endif %}">
- {{ field.label }}
- {{ field() }}
- {{ form_field_errors(field) }}
-</div>
-{%- endmacro %}
-
-{% macro form_field_inline(field, div_classes="") -%}
-<div class="ui grid">
- <div class="three wide column middle aligned right aligned" {# style="padding-right: 0.5rem;" #}>
- <div class="field inline {{ div_classes }} {% if field.errors %}error{% endif %}">
- {{ field.label }}
- </div>
- </div>
- <div class="twelve wide column" {# style="padding-left: 0.5rem;" #}>
- <div class="field {{ div_classes }} {% if field.errors %}error{% endif %}">
- {{ field() }}
- {{ form_field_errors(field) }}
- </div>
- </div>
- <div class="one wide column">
- </div>
-</div>
-{%- endmacro %}
-
-{% block body %}
+{% block edit_form_prefix %}
<div class="ui segment">
<h1 class="ui header">Create New Release Entity</h1>
+<form class="ui form" id="create_release_form" method="POST" action="/release/create">
+{% endblock %}
-<form class="ui form" id="add_work_form" method="POST" action="/release/create">
- {{ form.hidden_tag() }}
-
- <br>
- <div class="ui accordion">
- <div class="{% if not editgroup_id %}active{% endif %} title">
- <h3><i class="dropdown icon"></i>Editgroup Meta</h3>
- </div>
- <div class="{% if not editgroup_id %}active{% endif %} content">
- {% if editgroup_id %}
- <p>You have an editgroup in progress, and this edit will be included by
- default. You can override this below.
- {% else %}
- <p>No existing editgroup is in progress (or at least, not is selected).
- An existing ID can be pasted in, or if you leave that blank but give a
- description, a new editgroup will be created for this edit.
- {% endif %}
- {{ form_field_inline(form.editgroup_id) }}
- {{ form_field_inline(form.editgroup_description) }}
- </div>
- </div>
-
- <br>
- <h3 class="ui dividing header">The Basics</h3>
- <div class="ui grid">
- <div class="three wide column" style="padding-bottom: 0px;"></div>
- <div class="twelve wide column" style="padding-bottom: 0px;">
- <div class="ui equal width fields">
- {{ form_field_basic(form.release_type, "required") }}
- {{ form_field_basic(form.release_status) }}
- </div>
- </div>
- <div class="one wide column" style="padding-bottom: 0px;"></div>
- </div>
-
- {{ form_field_inline(form.title, "required") }}
- {{ form_field_inline(form.original_title) }}
- {{ form_field_inline(form.work_id) }}
- {{ form_field_inline(form.release_date) }}
- <div class="ui grid">
- <div class="three wide column" style="padding-bottom: 0px;"></div>
- <div class="twelve wide column" style="padding-bottom: 0px;">
- <div class="ui equal width fields">
- {{ form_field_basic(form.language) }}
- {{ form_field_basic(form.license_slug) }}
- </div>
- </div>
- <div class="one wide column" style="padding-bottom: 0px;"></div>
- </div>
-
- <br>
- <h3 class="ui dividing header">Contributors</h3>
- <div class="list-group" id="contrib_list" name="contrib_list">
- {% for cform in form.contribs %}
- <div class="list-group-item ui grid" style="padding-right: 1em;">
- <div class="one wide column middle aligned center aligned sortable-handle" style="padding-bottom: 0px; padding-right: 0px; padding-left: 0px;">
- <i class="arrows alternate vertical icon"></i>
- </div>
- <div class="three wide column" style="padding-bottom: 0px; padding-left: 0px;">
- <div class="field {% if cform.role.errors %}error{% endif %}">
- {{ cform.role }}
- </div>
- </div>
- <div class="eleven wide column" style="padding-bottom: 0px;">
- <div class="field {% if cform.raw_name.errors %}error{% endif %}">
- {{ cform.raw_name}}
- </div>
- </div>
- <div class="one wide column right aligned" style="padding-bottom: 0px; padding-left: 0rem;">
- <button type="button" class="ui icon red button delete-contrib-button"><i class="trash icon"></i></button>
- </div>
- </div>
- {% endfor %}
- </div>
- <br>
- <button type="button" id="add-contrib-button" class="ui right floated icon green button" style="margin-right: 0.3rem;">
- <i class="plus icon"></i>
- </button>
- <br>
-
- <br>
- <h3 class="ui dividing header">Identifers</h3>
- <br>
- {{ form_field_inline(form.doi) }}
- {{ form_field_inline(form.wikidata_qid) }}
- {{ form_field_inline(form.isbn13) }}
- <div class="ui grid">
- <div class="three wide column" style="padding-bottom: 0px;"></div>
- <div class="twelve wide column" style="padding-bottom: 0px;">
- <div class="ui equal width fields">
- {{ form_field_basic(form.pmid) }}
- {{ form_field_basic(form.pmcid) }}
- </div>
- </div>
- <div class="one wide column" style="padding-bottom: 0px;"></div>
- </div>
-
- <br>
- <h3 class="ui dividing header">Container</h3>
- <br>
- {{ form_field_inline(form.container_id) }}
- {{ form_field_inline(form.publisher) }}
- <br>
- <div class="ui grid">
- <div class="three wide column" style="padding-bottom: 0px;"></div>
- <div class="twelve wide column" style="padding-bottom: 0px;">
- <div class="ui equal width fields">
- {{ form_field_basic(form.pages) }}
- {{ form_field_basic(form.volume) }}
- {{ form_field_basic(form.issue) }}
- </div>
- </div>
- <div class="one wide column" style="padding-bottom: 0px;"></div>
- </div>
-
- <br><br>
- <h3 class="ui dividing header">Submit</h3>
- {{ form_field_basic(form.edit_description) }}
- This description will be attached to this specific action, not to the
- editgroup as a whole.
+{% block edit_form_suffix %}
<br><br>
<input class="ui primary submit button" type="submit" value="Create Release!">
-
</form>
-
</div>
{% endblock %}
-{% block postscript %}
-<script src="https://cdn.jsdelivr.net/npm/sortablejs@latest/Sortable.min.js"></script>
-<script>
-<!-- Form code -->
-$(document).ready(function() {
-
- // these javascript dropdowns hide the original <input>, which breaks browser
- // form focusing (eg, for required fields) :(
- //$('#release_type').dropdown();
- //$('#release_status').dropdown();
- $('.ui.accordion').accordion();
-
- var fixup_contrib_numbering = function(group_item) {
- items = Array.from(group_item.querySelectorAll(".list-group-item"))
- for (var i = 0; i < items.length; i++) {
- var item_el = items[i];
- input_el = item_el.querySelectorAll("input")[0];
- select_el = item_el.querySelectorAll("select")[0];
- //console.log(input_el.id);
- //console.log(select_el.id);
- input_el.id = "contribs-" + i + "-raw_name";
- input_el.name = input_el.id;
- select_el.id = "contribs-" + i + "-role";
- select_el.name = select_el.id;
- //console.log(input_el.id);
- //console.log(select_el.id);
- };
- console.log("re-named contrib rows up to i=" + i);
- };
-
- var contrib_list = document.getElementById('contrib_list');
- var contrib_sortable = Sortable.create(contrib_list, {
- handle: '.sortable-handle',
- animation: 150,
- onSort: function(evt) {
- fixup_contrib_numbering(contrib_list);
- },
- });
- fixup_contrib_numbering(contrib_list);
-
- var contrib_delete_handler = function(ev) {
- row = ev.target.parentNode.parentNode;
- // I don't understand why this hack is needed; maybe because of the sortable stuff?
- if(!row.classList.contains("list-group-item")) {
- row = row.parentNode;
- }
- // console.log(row);
- console.assert(row.classList.contains("list-group-item"));
- row.parentNode.removeChild(row);
- fixup_contrib_numbering(contrib_list);
- };
-
- var attach_contrib_delete_handler = function(topthing) {
- Array.from(topthing.querySelectorAll(".delete-contrib-button")).forEach((el) => {
- el.addEventListener("click", contrib_delete_handler);
- });
- };
- attach_contrib_delete_handler(document);
-
- // XXX: really need some way to not duplicate this code from above...
- var contrib_template = `
- <div class="list-group-item ui grid" style="padding-right: 1em;">
- <div class="one wide column middle aligned center aligned sortable-handle" style="padding-bottom: 0px; padding-right: 0px; padding-left: 0px;">
- <i class="arrows alternate vertical icon"></i>
- </div>
- <div class="three wide column" style="padding-bottom: 0px; padding-left: 0px;">
- <select id="contribs-X-role" name="contribs-X-role"><option value="author">Author</option><option value="editor">Editor</option><option value="translator">Translator</option></select>
- </div>
- <div class="eleven wide column" style="padding-bottom: 0px;">
- <input id="contribs-X-raw_name" name="contribs-X-raw_name" type="text" value="">
- </div>
- <div class="one wide column right aligned" style="padding-bottom: 0px; padding-left: 0rem;">
- <button type="button" class="ui icon red button delete-contrib-button"><i class="trash icon"></i></button>
- </div>
- </div>
- `;
-
- var add_contrib_button = document.getElementById("add-contrib-button");
- add_contrib_button.addEventListener("click", function(){
- contrib_list.insertAdjacentHTML('beforeend', contrib_template);
- attach_contrib_delete_handler(contrib_list.lastElementChild);
- fixup_contrib_numbering(contrib_list);
- });
-
- console.log("Page loaded");
-
-});
-</script>
-{% endblock %}
diff --git a/python/fatcat_web/templates/release_edit.html b/python/fatcat_web/templates/release_edit.html
new file mode 100644
index 00000000..867ae665
--- /dev/null
+++ b/python/fatcat_web/templates/release_edit.html
@@ -0,0 +1,231 @@
+{% import "edit_macros.html" as edit_macros %}
+{% extends "base.html" %}
+
+{% block body %}
+{% block edit_form_prefix %}
+<div class="ui segment">
+<h1 class="ui header">Edit Release Entity</h1>
+
+<form class="ui form" id="edit_release_form" method="POST" action="/release/{{ entity.ident }}/edit">
+{% endblock %}
+ {{ form.hidden_tag() }}
+
+ <br>
+ <div class="ui accordion">
+ <div class="{% if not editgroup_id %}active{% endif %} title">
+ <h3><i class="dropdown icon"></i>Editgroup Meta</h3>
+ </div>
+ <div class="{% if not editgroup_id %}active{% endif %} content">
+ {% if editgroup_id %}
+ <p>You have an editgroup in progress, and this edit will be included by
+ default. You can override this below.
+ {% else %}
+ <p>No existing editgroup is in progress (or at least, not is selected).
+ An existing ID can be pasted in, or if you leave that blank but give a
+ description, a new editgroup will be created for this edit.
+ {% endif %}
+ {{ edit_macros.form_field_inline(form.editgroup_id) }}
+ {{ edit_macros.form_field_inline(form.editgroup_description) }}
+ </div>
+ </div>
+
+ <br>
+ <h3 class="ui dividing header">The Basics</h3>
+ <div class="ui grid">
+ <div class="three wide column" style="padding-bottom: 0px;"></div>
+ <div class="twelve wide column" style="padding-bottom: 0px;">
+ <div class="ui equal width fields">
+ {{ edit_macros.form_field_basic(form.release_type, "required") }}
+ {{ edit_macros.form_field_basic(form.release_status) }}
+ </div>
+ </div>
+ <div class="one wide column" style="padding-bottom: 0px;"></div>
+ </div>
+
+ {{ edit_macros.form_field_inline(form.title, "required") }}
+ {{ edit_macros.form_field_inline(form.original_title) }}
+ {{ edit_macros.form_field_inline(form.work_id) }}
+ {{ edit_macros.form_field_inline(form.release_date) }}
+ <div class="ui grid">
+ <div class="three wide column" style="padding-bottom: 0px;"></div>
+ <div class="twelve wide column" style="padding-bottom: 0px;">
+ <div class="ui equal width fields">
+ {{ edit_macros.form_field_basic(form.language) }}
+ {{ edit_macros.form_field_basic(form.license_slug) }}
+ </div>
+ </div>
+ <div class="one wide column" style="padding-bottom: 0px;"></div>
+ </div>
+
+ <br>
+ <h3 class="ui dividing header">Contributors</h3>
+ <div class="list-group" id="contrib_list" name="contrib_list">
+ {% for cform in form.contribs %}
+ <div class="list-group-item ui grid" style="padding-right: 1em;">
+ {{ cform.hidden_tag() }}
+ <div class="one wide column middle aligned center aligned sortable-handle" style="padding-bottom: 0px; padding-right: 0px; padding-left: 0px;">
+ <i class="arrows alternate vertical icon"></i>
+ </div>
+ <div class="three wide column" style="padding-bottom: 0px; padding-left: 0px;">
+ <div class="field {% if cform.role.errors %}error{% endif %}">
+ {{ cform.role() }}
+ </div>
+ </div>
+ <div class="eleven wide column" style="padding-bottom: 0px;">
+ <div class="field {% if cform.raw_name.errors %}error{% endif %}">
+ {{ cform.raw_name() }}
+ </div>
+ </div>
+ <div class="one wide column right aligned" style="padding-bottom: 0px; padding-left: 0rem;">
+ <button type="button" class="ui icon red button delete-contrib-button"><i class="trash icon"></i></button>
+ </div>
+ </div>
+ {% endfor %}
+ </div>
+ <br>
+ <button type="button" id="add-contrib-button" class="ui right floated icon green button" style="margin-right: 0.3rem;">
+ <i class="plus icon"></i>
+ </button>
+ <br>
+
+ <br>
+ <h3 class="ui dividing header">Identifers</h3>
+ <br>
+ {{ edit_macros.form_field_inline(form.doi) }}
+ {{ edit_macros.form_field_inline(form.wikidata_qid) }}
+ {{ edit_macros.form_field_inline(form.isbn13) }}
+ <div class="ui grid">
+ <div class="three wide column" style="padding-bottom: 0px;"></div>
+ <div class="twelve wide column" style="padding-bottom: 0px;">
+ <div class="ui equal width fields">
+ {{ edit_macros.form_field_basic(form.pmid) }}
+ {{ edit_macros.form_field_basic(form.pmcid) }}
+ </div>
+ </div>
+ <div class="one wide column" style="padding-bottom: 0px;"></div>
+ </div>
+
+ <br>
+ <h3 class="ui dividing header">Container</h3>
+ <br>
+ {{ edit_macros.form_field_inline(form.container_id) }}
+ {{ edit_macros.form_field_inline(form.publisher) }}
+ <br>
+ <div class="ui grid">
+ <div class="three wide column" style="padding-bottom: 0px;"></div>
+ <div class="twelve wide column" style="padding-bottom: 0px;">
+ <div class="ui equal width fields">
+ {{ edit_macros.form_field_basic(form.pages) }}
+ {{ edit_macros.form_field_basic(form.volume) }}
+ {{ edit_macros.form_field_basic(form.issue) }}
+ </div>
+ </div>
+ <div class="one wide column" style="padding-bottom: 0px;"></div>
+ </div>
+
+ <br><br>
+ <h3 class="ui dividing header">Submit</h3>
+ {{ edit_macros.form_field_basic(form.edit_description) }}
+ This description will be attached to this specific action, not to the
+ editgroup as a whole.
+{% block edit_form_suffix %}
+ <br><br>
+ <input class="ui primary submit button" type="submit" value="Update Release!">
+</form>
+</div>
+{% endblock %}
+{% endblock %}
+
+{% block postscript %}
+<script src="https://cdn.jsdelivr.net/npm/sortablejs@latest/Sortable.min.js"></script>
+<script>
+<!-- Form code -->
+$(document).ready(function() {
+
+ // these javascript dropdowns hide the original <input>, which breaks browser
+ // form focusing (eg, for required fields) :(
+ //$('#release_type').dropdown();
+ //$('#release_status').dropdown();
+ $('.ui.accordion').accordion();
+
+ var fixup_contrib_numbering = function(group_item) {
+ items = Array.from(group_item.querySelectorAll(".list-group-item"))
+ for (var i = 0; i < items.length; i++) {
+ var item_el = items[i];
+ prev_el = item_el.querySelectorAll("input")[0];
+ input_el = item_el.querySelectorAll("input")[1];
+ select_el = item_el.querySelectorAll("select")[0];
+ //console.log(input_el.id);
+ //console.log(select_el.id);
+ input_el.id = "contribs-" + i + "-raw_name";
+ input_el.name = input_el.id;
+ prev_el.id = "contribs-" + i + "-prev_index";
+ prev_el.name = prev_el.id;
+ select_el.id = "contribs-" + i + "-role";
+ select_el.name = select_el.id;
+ //console.log(input_el.id);
+ //console.log(select_el.id);
+ };
+ console.log("re-named contrib rows up to i=" + i);
+ };
+
+ var contrib_list = document.getElementById('contrib_list');
+ var contrib_sortable = Sortable.create(contrib_list, {
+ handle: '.sortable-handle',
+ animation: 150,
+ onSort: function(evt) {
+ fixup_contrib_numbering(contrib_list);
+ },
+ });
+ fixup_contrib_numbering(contrib_list);
+
+ var contrib_delete_handler = function(ev) {
+ row = ev.target.parentNode.parentNode;
+ // I don't understand why this hack is needed; maybe because of the sortable stuff?
+ if(!row.classList.contains("list-group-item")) {
+ row = row.parentNode;
+ }
+ // console.log(row);
+ console.assert(row.classList.contains("list-group-item"));
+ row.parentNode.removeChild(row);
+ fixup_contrib_numbering(contrib_list);
+ };
+
+ var attach_contrib_delete_handler = function(topthing) {
+ Array.from(topthing.querySelectorAll(".delete-contrib-button")).forEach((el) => {
+ el.addEventListener("click", contrib_delete_handler);
+ });
+ };
+ attach_contrib_delete_handler(document);
+
+ // XXX: really need some way to not duplicate this code from above...
+ var contrib_template = `
+ <div class="list-group-item ui grid" style="padding-right: 1em;">
+ <input id="contribs-X-prev_index" name="contribs-X-prev_index" type="hidden" value="">
+ <div class="one wide column middle aligned center aligned sortable-handle" style="padding-bottom: 0px; padding-right: 0px; padding-left: 0px;">
+ <i class="arrows alternate vertical icon"></i>
+ </div>
+ <div class="three wide column" style="padding-bottom: 0px; padding-left: 0px;">
+ <select id="contribs-X-role" name="contribs-X-role"><option value="author">Author</option><option value="editor">Editor</option><option value="translator">Translator</option></select>
+ </div>
+ <div class="eleven wide column" style="padding-bottom: 0px;">
+ <input id="contribs-X-raw_name" name="contribs-X-raw_name" type="text" value="">
+ </div>
+ <div class="one wide column right aligned" style="padding-bottom: 0px; padding-left: 0rem;">
+ <button type="button" class="ui icon red button delete-contrib-button"><i class="trash icon"></i></button>
+ </div>
+ </div>
+ `;
+
+ var add_contrib_button = document.getElementById("add-contrib-button");
+ add_contrib_button.addEventListener("click", function(){
+ contrib_list.insertAdjacentHTML('beforeend', contrib_template);
+ attach_contrib_delete_handler(contrib_list.lastElementChild);
+ fixup_contrib_numbering(contrib_list);
+ });
+
+ console.log("Page loaded");
+
+});
+</script>
+{% endblock %}