mirror of
https://github.com/minetest/contentdb.git
synced 2025-03-14 14:22:30 +01:00
Add start of bulk tag editor
This commit is contained in:
@ -22,7 +22,7 @@ from . import bp
|
||||
|
||||
from app.rediscache import has_key, set_key, make_download_key
|
||||
from app.models import *
|
||||
from app.tasks.importtasks import makeVCSRelease, checkZipRelease
|
||||
from app.tasks.importtasks import makeVCSRelease, checkZipRelease, updateMetaFromRelease
|
||||
from app.utils import *
|
||||
|
||||
from celery import uuid
|
||||
@ -111,6 +111,7 @@ def create_release(package):
|
||||
db.session.commit()
|
||||
|
||||
checkZipRelease.apply_async((rel.id, uploadedPath), task_id=rel.task_id)
|
||||
updateMetaFromRelease.delay(rel.id, uploadedPath)
|
||||
|
||||
msg = "Release {} created".format(rel.title)
|
||||
addNotification(package.maintainers, current_user, msg, rel.getEditURL(), package)
|
||||
@ -120,6 +121,7 @@ def create_release(package):
|
||||
|
||||
return render_template("packages/release_new.html", package=package, form=form)
|
||||
|
||||
|
||||
@bp.route("/packages/<author>/<name>/releases/<id>/download/")
|
||||
@is_package_page
|
||||
def download_release(package, id):
|
||||
@ -149,6 +151,7 @@ def download_release(package, id):
|
||||
|
||||
return redirect(release.url, code=300)
|
||||
|
||||
|
||||
@bp.route("/packages/<author>/<name>/releases/<id>/", methods=["GET", "POST"])
|
||||
@login_required
|
||||
@is_package_page
|
||||
|
@ -100,3 +100,12 @@ def topics():
|
||||
topic_count=topic_count, query=qb.search, show_discarded=qb.show_discarded, \
|
||||
next_url=next_url, prev_url=prev_url, page=page, page_max=query.pages, \
|
||||
n=num, sort_by=qb.order_by)
|
||||
|
||||
|
||||
@bp.route("/todo/tags/")
|
||||
@login_required
|
||||
def tags():
|
||||
packages = Package.query.filter_by(approved=True, soft_deleted=False).all()
|
||||
tags = Tag.query.order_by(db.asc(Tag.title)).all()
|
||||
|
||||
return render_template("todo/tags.html", packages=packages, tags=tags)
|
||||
|
@ -19,80 +19,80 @@
|
||||
|
||||
$.fn.selectSelector = function(source, select) {
|
||||
return this.each(function() {
|
||||
var selector = $(this),
|
||||
input = $('input[type=text]', this);
|
||||
var selector = $(this),
|
||||
input = $('input[type=text]', this);
|
||||
|
||||
selector.click(function() { input.focus(); })
|
||||
.delegate('.badge a', 'click', function() {
|
||||
var id = $(this).parent().data("id");
|
||||
select.find("option[value=" + id + "]").attr("selected", false)
|
||||
recreate();
|
||||
});
|
||||
selector.click(function() { input.focus(); })
|
||||
.delegate('.badge a', 'click', function() {
|
||||
var id = $(this).parent().data("id");
|
||||
select.find("option[value=" + id + "]").attr("selected", false)
|
||||
recreate();
|
||||
});
|
||||
|
||||
function addTag(id, text) {
|
||||
$('<span class="badge badge-pill badge-primary"/>')
|
||||
.text(text + ' ')
|
||||
.data("id", id)
|
||||
.append('<a>x</a>')
|
||||
.insertBefore(input);
|
||||
input.attr("placeholder", null);
|
||||
select.find("option[value='" + id + "']").attr("selected", "selected")
|
||||
hide_error(input);
|
||||
}
|
||||
function addTag(id, text) {
|
||||
$('<span class="badge badge-pill badge-primary"/>')
|
||||
.text(text + ' ')
|
||||
.data("id", id)
|
||||
.append('<a>x</a>')
|
||||
.insertBefore(input);
|
||||
input.attr("placeholder", null);
|
||||
select.find("option[value='" + id + "']").attr("selected", "selected")
|
||||
hide_error(input);
|
||||
}
|
||||
|
||||
function recreate() {
|
||||
selector.find("span").remove();
|
||||
select.find("option").each(function() {
|
||||
if (this.hasAttribute("selected")) {
|
||||
addTag(this.getAttribute("value"), this.innerText);
|
||||
}
|
||||
});
|
||||
}
|
||||
recreate();
|
||||
|
||||
input.focusout(function(e) {
|
||||
var value = input.val().trim()
|
||||
if (value != "") {
|
||||
show_error(input, "Please select an existing tag, it;s not possible to add custom ones.");
|
||||
function recreate() {
|
||||
selector.find("span").remove();
|
||||
select.find("option").each(function() {
|
||||
if (this.hasAttribute("selected")) {
|
||||
addTag(this.getAttribute("value"), this.innerText);
|
||||
}
|
||||
});
|
||||
}
|
||||
recreate();
|
||||
|
||||
input.focusout(function(e) {
|
||||
var value = input.val().trim()
|
||||
if (value != "") {
|
||||
show_error(input, "Please select an existing tag, it;s not possible to add custom ones.");
|
||||
}
|
||||
})
|
||||
|
||||
input.keydown(function(e) {
|
||||
if (e.keyCode === $.ui.keyCode.TAB && $(this).data('ui-autocomplete').menu.active)
|
||||
e.preventDefault();
|
||||
})
|
||||
.autocomplete({
|
||||
minLength: 0,
|
||||
source: source,
|
||||
select: function(event, ui) {
|
||||
addTag(ui.item.id, ui.item.toString());
|
||||
input.val("");
|
||||
return false;
|
||||
}
|
||||
}).focus(function() {
|
||||
// The following works only once.
|
||||
// $(this).trigger('keydown.autocomplete');
|
||||
// As suggested by digitalPBK, works multiple times
|
||||
// $(this).data("autocomplete").search($(this).val());
|
||||
// As noted by Jonny in his answer, with newer versions use uiAutocomplete
|
||||
$(this).data("ui-autocomplete").search($(this).val());
|
||||
});
|
||||
|
||||
input.keydown(function(e) {
|
||||
if (e.keyCode === $.ui.keyCode.TAB && $(this).data('ui-autocomplete').menu.active)
|
||||
e.preventDefault();
|
||||
})
|
||||
.autocomplete({
|
||||
minLength: 0,
|
||||
source: source,
|
||||
select: function(event, ui) {
|
||||
addTag(ui.item.id, ui.item.toString());
|
||||
input.val("");
|
||||
return false;
|
||||
}
|
||||
}).focus(function() {
|
||||
// The following works only once.
|
||||
// $(this).trigger('keydown.autocomplete');
|
||||
// As suggested by digitalPBK, works multiple times
|
||||
// $(this).data("autocomplete").search($(this).val());
|
||||
// As noted by Jonny in his answer, with newer versions use uiAutocomplete
|
||||
$(this).data("ui-autocomplete").search($(this).val());
|
||||
});
|
||||
input.data('ui-autocomplete')._renderItem = function(ul, item) {
|
||||
return $('<li/>')
|
||||
.data('item.autocomplete', item)
|
||||
.append($('<a/>').text(item.toString()))
|
||||
.appendTo(ul);
|
||||
};
|
||||
|
||||
input.data('ui-autocomplete')._renderItem = function(ul, item) {
|
||||
return $('<li/>')
|
||||
.data('item.autocomplete', item)
|
||||
.append($('<a/>').text(item.toString()))
|
||||
.appendTo(ul);
|
||||
};
|
||||
|
||||
input.data('ui-autocomplete')._resizeMenu = function(ul, item) {
|
||||
var ul = this.menu.element;
|
||||
ul.outerWidth(Math.max(
|
||||
ul.width('').outerWidth(),
|
||||
selector.outerWidth()
|
||||
));
|
||||
};
|
||||
});
|
||||
input.data('ui-autocomplete')._resizeMenu = function(ul, item) {
|
||||
var ul = this.menu.element;
|
||||
ul.outerWidth(Math.max(
|
||||
ul.width('').outerWidth(),
|
||||
selector.outerWidth()
|
||||
));
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
$.fn.csvSelector = function(source, name, result, allowSlash) {
|
||||
|
@ -1,7 +1,7 @@
|
||||
.ui-autocomplete, ui-front {
|
||||
position:absolute;
|
||||
cursor:default;
|
||||
z-index:1001 !important
|
||||
z-index:1100 !important
|
||||
}
|
||||
|
||||
.ui-autocomplete {
|
||||
|
@ -299,6 +299,8 @@ def makeVCSRelease(id, branch):
|
||||
release.approve(release.package.author)
|
||||
db.session.commit()
|
||||
|
||||
updateMetaFromRelease.delay(release.id, destPath)
|
||||
|
||||
return release.url
|
||||
finally:
|
||||
shutil.rmtree(gitDir)
|
||||
|
@ -7,7 +7,7 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>{% block title %}title{% endblock %} - {{ config.USER_APP_NAME }}</title>
|
||||
<link rel="stylesheet" type="text/css" href="/static/bootstrap.css">
|
||||
<link rel="stylesheet" type="text/css" href="/static/custom.css?v=12">
|
||||
<link rel="stylesheet" type="text/css" href="/static/custom.css?v=13">
|
||||
<link rel="search" type="application/opensearchdescription+xml" href="/static/opensearch.xml" title="ContentDB" />
|
||||
<link rel="shortcut icon" href="/favicon-16.png" sizes="16x16">
|
||||
<link rel="icon" href="/favicon-128.png" sizes="128x128">
|
||||
|
113
app/templates/todo/tags.html
Normal file
113
app/templates/todo/tags.html
Normal file
@ -0,0 +1,113 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}
|
||||
Tags
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<style>
|
||||
table {
|
||||
width:auto;
|
||||
}
|
||||
td {
|
||||
white-space:nowrap;
|
||||
}
|
||||
table td:last-child {
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
|
||||
<table class="table">
|
||||
<tr>
|
||||
<th>Package</th>
|
||||
<th>Tags</th>
|
||||
</tr>
|
||||
{% for package in packages %}
|
||||
<tr>
|
||||
<td>
|
||||
<a href="{{ package.getDetailsURL() }}">
|
||||
{{ package.title }}
|
||||
</a>
|
||||
|
||||
by {{ package.author.display_name }}
|
||||
</td>
|
||||
<td class="tags">
|
||||
{% for tag in package.tags %}
|
||||
<span class="badge badge-primary mr-1">{{ tag.title }}</span>
|
||||
{% endfor %}
|
||||
<a class="badge badge-secondary add-btn px-2" href="#">
|
||||
<i class="fas fa-plus"></i>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
|
||||
<div class="modal">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">{{ _("Edit tags") }}</h5>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<select name="tags" multiple>
|
||||
{% for tag in tags %}
|
||||
<option value="{{ tag.name }}">{{ tag.title }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
|
||||
<button type="button" class="btn btn-primary">Update</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% from "macros/forms.html" import form_scripts %}
|
||||
|
||||
{% block scriptextra %}
|
||||
{{ form_scripts() }}
|
||||
|
||||
<script>
|
||||
$(".add-btn").click(function() {
|
||||
const row = $(this).parent().parent()
|
||||
|
||||
$(".modal select option").removeAttr("selected");
|
||||
$(".multichoice_selector").remove();
|
||||
|
||||
$(".modal .modal-body").prepend(`
|
||||
<div class="multichoice_selector bulletselector form-control">
|
||||
<input type="text" placeholder="Start typing to see suggestions">
|
||||
<div class="clearboth"></div>
|
||||
</div>
|
||||
`);
|
||||
|
||||
$(".modal").modal("show");
|
||||
$(".modal input").focus();
|
||||
$(".multichoice_selector").each(function() {
|
||||
var ele = $(this);
|
||||
var sel = ele.parent().find("select");
|
||||
sel.hide();
|
||||
|
||||
var options = [];
|
||||
sel.find("option").each(function() {
|
||||
var text = $(this).text();
|
||||
options.push({
|
||||
id: $(this).attr("value"),
|
||||
value: text,
|
||||
toString: function() { return text; },
|
||||
});
|
||||
});
|
||||
|
||||
ele.selectSelector(options, sel);
|
||||
});
|
||||
});
|
||||
|
||||
</script>
|
||||
{% endblock %}
|
Reference in New Issue
Block a user