mirror of
https://github.com/minetest/contentdb.git
synced 2024-12-22 22:12:24 +01:00
Add meta package selector
This commit is contained in:
parent
5e4613a6ef
commit
82159d488d
@ -33,7 +33,7 @@ the current session:
|
||||
|
||||
If you need to, reset the db like so:
|
||||
|
||||
python3 setup.py -d
|
||||
python3 setup.py -t
|
||||
|
||||
Then run the server:
|
||||
|
||||
@ -43,6 +43,12 @@ Then view in your web browser: http://localhost:5000/
|
||||
|
||||
## How-tos
|
||||
|
||||
### Start celery worker
|
||||
|
||||
```sh
|
||||
FLASK_CONFIG=../config.cfg celery -A app.tasks.celery worker
|
||||
```
|
||||
|
||||
### Create migration
|
||||
|
||||
```sh
|
||||
|
@ -414,6 +414,19 @@ class MetaPackage(db.Model):
|
||||
def ListToSpec(list):
|
||||
return ",".join([str(x) for x in list])
|
||||
|
||||
@staticmethod
|
||||
def GetOrCreate(name, cache={}):
|
||||
mp = cache.get(name)
|
||||
if mp is None:
|
||||
mp = MetaPackage.query.filter_by(name=name).first()
|
||||
|
||||
if mp is None:
|
||||
mp = MetaPackage(name)
|
||||
db.session.add(mp)
|
||||
|
||||
cache[name] = mp
|
||||
return mp
|
||||
|
||||
@staticmethod
|
||||
def SpecToList(spec, cache={}):
|
||||
retval = []
|
||||
@ -430,16 +443,7 @@ class MetaPackage(db.Model):
|
||||
if not pattern.match(x):
|
||||
continue
|
||||
|
||||
mp = cache.get(x)
|
||||
if mp is None:
|
||||
mp = MetaPackage.query.filter_by(name=x).first()
|
||||
|
||||
if mp is None:
|
||||
mp = MetaPackage(x)
|
||||
db.session.add(mp)
|
||||
|
||||
cache[x] = mp
|
||||
retval.append(mp)
|
||||
retval.append(MetaPackage.GetOrCreate(x, cache))
|
||||
|
||||
return retval
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
* https://petprojects.googlecode.com/svn/trunk/GPL-LICENSE.txt
|
||||
*/
|
||||
(function($) {
|
||||
$.fn.tagSelector = function(source, name, select) {
|
||||
$.fn.selectSelector = function(source, name, select) {
|
||||
return this.each(function() {
|
||||
var selector = $(this),
|
||||
input = $('input[type=text]', this);
|
||||
@ -80,15 +80,115 @@
|
||||
});
|
||||
}
|
||||
|
||||
$.fn.csvSelector = function(source, name, result, allowSlash) {
|
||||
return this.each(function() {
|
||||
var selector = $(this),
|
||||
input = $('input[type=text]', this);
|
||||
|
||||
var selected = [];
|
||||
|
||||
selector.click(function() { input.focus(); })
|
||||
.delegate('.tag a', 'click', function() {
|
||||
var id = $(this).parent().data("id");
|
||||
for (var i = 0; i < selected.length; i++) {
|
||||
if (selected[i] == id) {
|
||||
selected.splice(i, 1);
|
||||
}
|
||||
}
|
||||
recreate();
|
||||
});
|
||||
|
||||
|
||||
function selectItem(id) {
|
||||
for (var i = 0; i < selected.length; i++) {
|
||||
if (selected[i] == id) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
selected.push(id);
|
||||
return true;
|
||||
}
|
||||
|
||||
function addTag(id, value) {
|
||||
var tag = $('<span class="tag"/>')
|
||||
.text(value)
|
||||
.data("id", id)
|
||||
.append(' <a>x</a>')
|
||||
.insertBefore(input);
|
||||
|
||||
input.attr("placeholder", null);
|
||||
}
|
||||
|
||||
function recreate() {
|
||||
selector.find("span").remove();
|
||||
for (var i = 0; i < selected.length; i++) {
|
||||
var value = source[selected[i]] || selected[i];
|
||||
addTag(selected[i], value);
|
||||
}
|
||||
result.val(selected.join(","))
|
||||
}
|
||||
recreate();
|
||||
|
||||
input.keydown(function(e) {
|
||||
if (e.keyCode === $.ui.keyCode.TAB && $(this).data('ui-autocomplete').menu.active)
|
||||
e.preventDefault();
|
||||
else if (e.keyCode === $.ui.keyCode.COMMA) {
|
||||
var item = input.val();
|
||||
if (item.match(/^([a-z0-9_]+)$/)) {
|
||||
selectItem(item);
|
||||
recreate();
|
||||
input.val("");
|
||||
} else {
|
||||
alert("Only lowercase alphanumeric and number names allowed.");
|
||||
}
|
||||
e.preventDefault();
|
||||
return true;
|
||||
} else if (e.keyCode === $.ui.keyCode.BACKSPACE) {
|
||||
if (input.val() == "") {
|
||||
var item = selected[selected.length - 1];
|
||||
selected.splice(selected.length - 1, 1);
|
||||
recreate();
|
||||
input.val(item);
|
||||
e.preventDefault();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
})
|
||||
.autocomplete({
|
||||
minLength: 0,
|
||||
source: source,
|
||||
select: function(event, ui) {
|
||||
selectItem(ui.item.id);
|
||||
recreate();
|
||||
input.val("");
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
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()
|
||||
));
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
$(function() {
|
||||
$(".multichoice_selector").each(function() {
|
||||
var ele = $(this);
|
||||
var sel = ele.parent().find("select");
|
||||
console.log(sel.attr("name"));
|
||||
sel.css("display", "none");
|
||||
sel.hide();
|
||||
|
||||
var options = [];
|
||||
|
||||
sel.find("option").each(function() {
|
||||
var text = $(this).text();
|
||||
options.push({
|
||||
@ -100,7 +200,13 @@
|
||||
});
|
||||
|
||||
console.log(options);
|
||||
ele.tagSelector(options, sel.attr("name"), sel);
|
||||
ele.selectSelector(options, sel.attr("name"), sel);
|
||||
});
|
||||
|
||||
$(".metapackage_selector").each(function() {
|
||||
var input = $(this).parent().children("input[type='text']");
|
||||
input.hide();
|
||||
$(this).csvSelector(meta_packages, input.attr("name"), input);
|
||||
})
|
||||
});
|
||||
})(jQuery);
|
||||
|
@ -87,7 +87,7 @@ a:hover {
|
||||
}
|
||||
|
||||
.button, .buttonset li a, input[type=submit], input[type=text],
|
||||
input[type=password], textarea, select, .multichoice_selector {
|
||||
input[type=password], textarea, select, .bulletselector {
|
||||
text-align: center;
|
||||
display: inline-block;
|
||||
padding: 0.4em 1em;
|
||||
@ -99,7 +99,7 @@ a:hover {
|
||||
font-size: 100%;
|
||||
}
|
||||
|
||||
input[type=text], input[type=password], textarea, select, .multichoice_selector {
|
||||
input[type=text], input[type=password], textarea, select, .bulletselector {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
@ -147,13 +147,13 @@ select:not([multiple]) {
|
||||
padding: 0 8px 8px 0;
|
||||
}
|
||||
|
||||
.form-group input, .form-group textarea, .form-group .multichoice_selector {
|
||||
.form-group input, .form-group textarea, .form-group .bulletselector {
|
||||
display: block;
|
||||
min-width: 100%;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.box .form-group input, .box .form-group textarea, .form-group .multichoice_selector {
|
||||
.box .form-group input, .box .form-group textarea, .form-group .bulletselector {
|
||||
min-width: 95%;
|
||||
max-width: 95%;
|
||||
}
|
||||
@ -197,7 +197,7 @@ select:not([multiple]) {
|
||||
}
|
||||
|
||||
|
||||
.multichoice_selector input {
|
||||
.bulletselector input {
|
||||
border: none;
|
||||
border-radius: 0;
|
||||
-moz-border-radius: 0;
|
||||
@ -211,7 +211,7 @@ select:not([multiple]) {
|
||||
white-space: nowrap;
|
||||
background: transparent;
|
||||
}
|
||||
.multichoice_selector .tag {
|
||||
.bulletselector .tag {
|
||||
background: #375D81;
|
||||
border-radius: 3px;
|
||||
-moz-border-radius: 3px;
|
||||
@ -223,11 +223,11 @@ select:not([multiple]) {
|
||||
margin-bottom: 0.3em;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
.multichoice_selector .tag a {
|
||||
.bulletselector .tag a {
|
||||
color: #FFF;
|
||||
cursor: pointer;
|
||||
}
|
||||
.multichoice_selector .tag a:hover {
|
||||
.bulletselector .tag a:hover {
|
||||
color: #0099CC;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
@ -26,7 +26,7 @@
|
||||
{% if not label %}{% set label=field.label.text %}{% endif %}
|
||||
<label for="{{ field.id }}" class="control-label">{{ label|safe }}</label>
|
||||
{% endif %}
|
||||
<div class="multichoice_selector">
|
||||
<div class="multichoice_selector bulletselector">
|
||||
<input type="text" placeholder="Start typing to see suggestions">
|
||||
<div class="clearboth"></div>
|
||||
</div>
|
||||
@ -45,7 +45,7 @@
|
||||
{% if not label %}{% set label=field.label.text %}{% endif %}
|
||||
<label for="{{ field.id }}" class="control-label">{{ label|safe }}</label>
|
||||
{% endif %}
|
||||
<div class="metapackage_selector">
|
||||
<div class="metapackage_selector bulletselector">
|
||||
<input type="text" placeholder="Start typing to see suggestions">
|
||||
<div class="clearboth"></div>
|
||||
</div>
|
||||
|
@ -10,6 +10,19 @@
|
||||
{% block content %}
|
||||
<h2>Create Package</h2>
|
||||
|
||||
<script>
|
||||
meta_packages = [
|
||||
{% for m in mpackages %}
|
||||
{# This is safe as name can only contain `[a-z0-9_]` #}
|
||||
{
|
||||
id: "{{ m.name }}",
|
||||
value: "{{ m.name }}",
|
||||
toString: function() { return "{{ m.name }}"; },
|
||||
},
|
||||
{% endfor %}
|
||||
]
|
||||
</script>
|
||||
|
||||
{% from "macros/forms.html" import render_field, render_submit_field, form_includes, render_multiselect_field, render_mpackage_field %}
|
||||
{{ form_includes() }}
|
||||
|
||||
|
@ -106,7 +106,7 @@ class PackageForm(FlaskForm):
|
||||
desc = TextAreaField("Long Description", [Optional(), Length(0,10000)])
|
||||
type = SelectField("Type", [InputRequired()], choices=PackageType.choices(), coerce=PackageType.coerce, default=PackageType.MOD)
|
||||
license = QuerySelectField("License", [InputRequired()], query_factory=lambda: License.query, get_pk=lambda a: a.id, get_label=lambda a: a.name)
|
||||
provides_str = StringField("Provides", [InputRequired(), Length(1,1000)])
|
||||
provides_str = StringField("Provides", [Optional(), Length(0,1000)])
|
||||
tags = QuerySelectMultipleField('Tags', query_factory=lambda: Tag.query.order_by(db.asc(Tag.name)), get_pk=lambda a: a.id, get_label=lambda a: a.title)
|
||||
repo = StringField("Repo URL", [Optional(), URL()])
|
||||
website = StringField("Website URL", [Optional(), URL()])
|
||||
@ -174,6 +174,11 @@ def create_edit_package_page(author=None, name=None):
|
||||
for m in mpackages:
|
||||
package.provides.append(m)
|
||||
|
||||
if wasNew and package.type == PackageType.MOD and not package.name in mpackage_cache:
|
||||
m = MetaPackage.GetOrCreate(package.name, mpackage_cache)
|
||||
package.provides.append(m)
|
||||
|
||||
|
||||
package.tags.clear()
|
||||
for tag in form.tags.raw_data:
|
||||
package.tags.append(Tag.query.get(tag))
|
||||
@ -188,7 +193,8 @@ def create_edit_package_page(author=None, name=None):
|
||||
|
||||
enableWizard = name is None and request.method != "POST"
|
||||
return render_template("packages/create_edit.html", package=package, \
|
||||
form=form, author=author, enable_wizard=enableWizard)
|
||||
form=form, author=author, enable_wizard=enableWizard, \
|
||||
mpackages=MetaPackage.query.order_by(db.asc(MetaPackage.name)).all())
|
||||
|
||||
@app.route("/packages/<author>/<name>/approve/", methods=["POST"])
|
||||
@login_required
|
||||
|
Loading…
Reference in New Issue
Block a user