@@ -243,14 +243,24 @@ input#reorder-change {
margin: 0.2em 0;
}
+/* common to patch and series */
+span.glyphicon-pencil {
+ cursor: pointer;
+}
+
+div.editable-field div.selectize-input {
+ width: 300px;
+}
+
/* patch view */
table.patchmeta th {
text-align: left;
+ height: 30px;
}
table.patchmeta tr th, table.patchmeta tr td {
text-align: left;
- padding: 3px 10px 3px 10px;
+ padding: 0 10px;
vertical-align: middle;
}
@@ -2,9 +2,26 @@ var pw = (function() {
var _this,
exports = {},
ctx = {
- project: null
+ project: null,
+ series: null
};
+ function get_cookie(name) {
+ var value = null;
+ if (document.cookie && document.cookie != '') {
+ var cookies = document.cookie.split(';');
+ for (var i = 0; i < cookies.length; i++) {
+ var cookie = jQuery.trim(cookies[i]);
+ // Does this cookie string begin with the name we want?
+ if (cookie.substring(0, name.length + 1) == (name + '=')) {
+ value = decodeURIComponent(cookie.substring(name.length + 1));
+ break;
+ }
+ }
+ }
+ return value;
+ }
+
var columnsMap = {
'Series': 'name',
'Patches': 'n_patches',
@@ -39,6 +56,8 @@ var pw = (function() {
this.amend_context(init_ctx);
+ ctx.csrftoken = get_cookie('csrftoken');
+
$.dynatableSetup({
dataset: {
perPageDefault: 20,
@@ -118,5 +137,137 @@ var pw = (function() {
}
}
+ function setup_autocompletion(field) {
+ var $s = $('#edit-' + field.name + ' input');
+ var s = $s[0].selectize;
+
+ if (!field.autocomplete)
+ return;
+
+ if (s)
+ return;
+
+ $s.selectize({
+ valueField: 'pk',
+ labelField: field.autocomplete.display_field,
+ searchField: field.autocomplete.search_fields,
+ maxItems: 1,
+ persist: false,
+ openOnFocus: false,
+ render: {
+ option: field.autocomplete.render || function(item, escape) {
+ return '<div>' + escape(item[field.autocomplete.display_field]) + '</div>';
+ },
+ item: field.autocomplete.render || function(item, escape) {
+ return '<div>' + escape(item[field.autocomplete.display_field]) + '</div>';
+ }
+ },
+ load: function(query, callback) {
+ if (query.length < 3)
+ return callback();
+
+ req = $.ajax({
+ url: field.autocomplete.url + '/?q=' + encodeURIComponent(query) + '&l=10',
+ error: function() {
+ callback();
+ },
+ success: function(res) {
+ callback(res);
+ }
+ });
+ }
+ });
+
+ s = $s[0].selectize;
+ s.on('item_add', function(value) {
+ $('#save-' + field.name).removeClass('disabled');
+ });
+
+ s.on('item_remove', function(value) {
+ $('#save-' + field.name).removeClass('disabled');
+ });
+
+ }
+
+ function cleanup_autocompletion(field) {
+ var $s = $('#edit-' + field.name + ' input');
+ var s = $s[0].selectize;
+
+ s.destroy();
+ delete $s[0].selectize;
+ }
+
+ function field_setup(field) {
+ /* what to do when the edit icon is clicked */
+ $('#field-' + field.name + ' .glyphicon-pencil').click(function() {
+ var input = $('#edit-' + field.name + ' input');
+
+ $(this).parent().hide();
+ $('#save-' + field.name).addClass('disabled');
+ $('#edit-' + field.name).show();
+
+ setup_autocompletion(field);
+
+ if (field.value) {
+ input[0].selectize.addOption(field.value);
+ input[0].selectize.setValue(field.value.pk);
+ }
+ input[0].selectize.focus();
+ });
+
+ function field_refresh(field) {
+ var content;
+
+ if (field.is_null())
+ content = '<em class="text-muted">None</em>';
+ else
+ content = field.text();
+
+ $('#field-' + field.name + '-text').html(content);
+ }
+
+ /* the save button is clicked */
+ $('#save-' + field.name).click(function() {
+ var $s = $('#edit-' + field.name + ' input');
+ var s = $s[0].selectize;
+ var val = parseInt(s.getValue()) || null;
+ var patch_data = {};
+
+ patch_data[field.name] = val;
+
+ $.ajax({
+ url: '/api/1.0/series/' + ctx.series + '/',
+ headers: {
+ 'X-HTTP-Method-Override': 'PATCH',
+ 'X-CSRFToken': ctx.csrftoken
+ },
+ type: 'POST',
+ data: patch_data,
+ success: function(response) {
+ field.init_from_series(response);
+ field_refresh(field);
+ $('#edit-' + field.name).hide();
+ $('#field-' + field.name).show();
+ },
+ /* TODO: show the error to the user, maybe use the 'details'
+ * from the response */
+ error: function(ctx, status, error) {
+ console.log("Couldn't save " + field.name + ": " + status, error);
+ }
+ })
+ });
+
+ /* the cancel button is clicked */
+ $('#cancel-' + field.name).click(function() {
+ $('#edit-' + field.name).hide();
+ $('#field-' + field.name).show();
+ });
+
+ }
+
+ exports.setup_editable_fields = function(fields) {
+ fields.forEach(field_setup);
+ }
+
return exports
}());
@@ -8,6 +8,25 @@
<script language="JavaScript" type="text/javascript">
$(function () {
pw.setup_series({ patches: 'series-patchlist' });
+ pw.amend_context({ series: {{ series.pk }} });
+ pw.setup_editable_fields([{
+ name: 'reviewer'
+{% if series.reviewer %}
+ ,value: { pk: {{ series.reviewer.pk }},
+ display_name: "{{ series.reviewer.name }}" }
+{% else %}
+ ,value: { pk: null, name: null }
+{% endif %}
+ ,init_from_series: function(o) {
+ this.value.pk = o.reviewer;
+ this.value.display_name = o.reviewer__name;
+ }
+ ,is_null: function() { return !this.value.pk; }
+ ,text: function() { return this.value.display_name; }
+ ,autocomplete: { url: '/complete_user',
+ display_field: 'display_name',
+ search_fields: ['username', 'display_name'] }
+ }]);
});
</script>
{% endblock %}
@@ -27,11 +46,25 @@ $(function () {
<table class="patchmeta">
<tr>
<th>Reviewer</th>
+ <td>
+ <span id="field-reviewer">
+ <span id="field-reviewer-text">
{% if series.reviewer %}
- <td>{{ series.reviewer }}</td>
+ {{ series.reviewer.name }}
{% else %}
- <td><em class="text-muted">None</em></td>
+ <em class="text-muted">None</em>
{% endif %}
+ </span>
+ <span class="glyphicon glyphicon-pencil" ></span>
+ </span>
+ <div id="edit-reviewer" class="form-inline" style="display:none;">
+ <div class="form-group">
+ <input type="text" class="form-control input-sm editable-field">
+ <button id="save-reviewer" type="button" class="btn btn-primary btn-sm">Save</button>
+ <button id="cancel-reviewer" type="button" class="btn btn-default btn-sm">Cancel</button>
+ </div>
+ </div>
+ </td>
</tr>
<tr>
<th>Submitted</th>
Signed-off-by: Damien Lespiau <damien.lespiau@intel.com> --- htdocs/css/style.css | 12 ++- htdocs/js/patchwork.js | 153 +++++++++++++++++++++++++++++- patchwork/templates/patchwork/series.html | 37 +++++++- 3 files changed, 198 insertions(+), 4 deletions(-)