ソースを参照

#17 Améliore l'édition du backlog

omassot 6 年 前
コミット
a302145b4f
5 ファイル変更207 行追加92 行削除
  1. 2 1
      .gitignore
  2. 26 1
      main/static/js/common.js
  3. 85 10
      main/static/js/custom.js
  4. 76 74
      main/templates/backlog_editor.html
  5. 18 6
      main/views.py

+ 2 - 1
.gitignore

@@ -9,4 +9,5 @@ tmp*
 ~$*
 .sqlite3
 main/migrations/*
-main/media/upload/*
+main/media/upload/*
+todo.txt

+ 26 - 1
main/static/js/common.js

@@ -36,4 +36,29 @@ function getCookie(name) {
     }
     return cookieValue;
 }
-var csrftoken = getCookie('csrftoken');
+var csrftoken = getCookie('csrftoken');
+
+function sameOrigin(url) {
+    // test that a given url is a same-origin URL
+    // url could be relative or scheme relative or absolute
+    var host = document.location.host; // host + port
+    var protocol = document.location.protocol;
+    var sr_origin = '//' + host;
+    var origin = protocol + sr_origin;
+    // Allow absolute or scheme relative URLs to same origin
+    return (url == origin || url.slice(0, origin.length + 1) == origin + '/') ||
+        (url == sr_origin || url.slice(0, sr_origin.length + 1) == sr_origin + '/') ||
+        // or any other URL that isn't scheme relative or absolute i.e relative.
+        !(/^(\/\/|http:|https:).*/.test(url));
+}
+
+$.ajaxSetup({
+    beforeSend: function(xhr, settings) {
+        if (!csrfSafeMethod(settings.type) && sameOrigin(settings.url)) {
+            // Send the token to same-origin, relative URLs only.
+            // Send the token only if the method warrants CSRF protection
+            // Using the CSRFToken value acquired earlier
+            xhr.setRequestHeader("X-CSRFToken", csrftoken);
+        }
+    }
+});

+ 85 - 10
main/static/js/custom.js

@@ -140,11 +140,6 @@ $(document).ready( function () {
             data: '{notif_id:' + notif_id + '}',
             contentType: "application/json; charset=utf-8",
             dataType: "json",
-            beforeSend: function(xhr, settings) {
-                if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
-                    xhr.setRequestHeader("X-CSRFToken", csrftoken);
-                }
-            },
             success: function (response) {
             	notif.remove();
             },
@@ -166,11 +161,6 @@ $(document).ready( function () {
 				url: "/notif/allseen/",
 				contentType: "application/json; charset=utf-8",
 				dataType: "json",
-				beforeSend: function(xhr, settings) {
-					if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
-						xhr.setRequestHeader("X-CSRFToken", csrftoken);
-					}
-				},
 				success: function (response) {
 					notif_list.html('');
 					$('.notif-footer').html('<i>Aucune notification à afficher</i>');
@@ -187,4 +177,89 @@ $(document).ready( function () {
 		}
 	});
 	
+	$("#backlog-editor").on('submit', 'form', function(event) {
+		event.preventDefault();
+		
+		var action = $(this).attr('action');
+		var val_field = $(this).find('input[name=value]');
+		
+		console.log(action);
+		console.log(val_field.val())
+		
+		$.ajax({
+			type: "POST",
+			url: action,
+			data : { value : val_field.val() },
+			success: function (response) {
+				val_field.animate({ borderColor: "#009933" }, 1500, function() {
+					                val_field.removeAttr('style'); } );
+			},
+			failure: function (response) {
+				val_field.animate({ borderColor: "#ff0000" }, 1500, function() {
+	                val_field.removeAttr('style'); } );
+				console.log('Ajax failure: ' + response.responseText);
+				$("#backlog-editor").unbind('submit');   // Ajax is not working: unbind
+				$(this).submit();
+			},
+			
+			error: function (response) {
+				val_field.animate({ borderColor: "#ff0000" }, 1500, function() {
+	                val_field.removeAttr('style'); } );
+				console.log('Ajax error: ' + response.responseText);
+				$("#backlog-editor").unbind('submit');   // Ajax is not working: unbind
+				$(this).submit();
+			}
+		});
+	
+	});
+	
+	$("#backlog-editor").on('click', '.btn-epic-close', function(event) {
+		event.preventDefault();
+		
+		var action = $(this).attr('href');
+		this_btn = $(this);
+		
+		$.ajax({
+			type: "POST",
+            url: action,
+            success: function (response) {
+            	this_btn.addClass('disabled');
+            	this_btn.closest('tr').find(".epic-name").addClass('story-closed');
+            },
+            failure: function (response) {
+                alert(response.responseText);
+            },
+            error: function (response) {
+                alert(response.responseText);
+            }
+		});
+	
+	});
+	
+	$("#backlog-editor").on('click', '.btn-epic-reopen', function(event) {
+		event.preventDefault();
+		
+		var action = $(this).attr('href');
+		this_btn = $(this);
+		name_field = this_btn.closest('tr').find(".epic-name");
+		
+		$.ajax({
+			type: "POST",
+			url: action,
+			success: function (response) {
+				this_btn.addClass('disabled');
+				name_field.removeClass('story-closed');
+				name_field.html(name_field.html().replace('[Fermée] ', ''));
+			},
+			failure: function (response) {
+				alert(response.responseText);
+			},
+			error: function (response) {
+				alert(response.responseText);
+			}
+		});
+		
+	});
+	
+	
 });

+ 76 - 74
main/templates/backlog_editor.html

@@ -1,75 +1,77 @@
-{% extends '_layout.html' %}
-
-{% block title %}
-	Edition du backlog
-{% endblock %}
-
-
-{% block breadcrumb %}
-	<li><a href="{% url 'index' %}">Accueil</a></li>
-	<li><a>Edition du backlog</a></li>
-{% endblock %}
-
-
-{% block main %}
-	<header>
-		<div class="flex-row">
-			<h2 class="flex-extend">Backlog : Edition</h2>
-			<span>
-				<a href="{% url 'epic_create' %}"><i class="fa fa-plus"></i> Ajouter une Epic</a>
-			</span>
-		</div>
-	</header>
-
-
-	<table id="backlog-editor">
-		
-		<thead>
-			<th>Epic</th>
-			<th>Valeur</th>
-			<th>Options</th>
-		</thead>
-		
-		<tbody>
-			{% for epic in epics %}
-			<tr>
-				<td class="backlog-editor-col1">
-					<i class="fa fa-circle" style="margin-right: 0.5em; color:{{ epic.project.color }};" title="{{ epic.project.name }}"></i> 
-					<a href="{% url 'epic_details' epic_id=epic.id %}">{{ epic.name }}</a>
-				</td>
-				<td class="backlog-editor-col2">
-					<form action="{% url 'epic_value_update' epic_id=epic.id %}" method="post" accept-charset="utf-8">
-						{% csrf_token %}
-				    	<input class="raw-input" name="value" type="text" value="{{ epic.value }}">
-				    </form>
-				</td>
-				<td class="backlog-editor-col3">
-					<a href="{% url 'epic_edit' epic_id=epic.id from_='backlog_editor' %}"><i class="fa fa-pencil" title="Editer"></i></a>
-					<a href="{% url 'epic_close' epic_id=epic.id %}"><i class="fa fa-archive" title="Clôre l'Epic"></i></a>
-				</td>
-			</tr>
-			{% endfor %}
-			
-			{% for epic in closed %}
-			<tr>
-				<td class="backlog-editor-col1">
-					<i class="fa fa-circle" style="margin-right: 0.5em; color:{{ epic.project.color }};" title="{{ epic.project.name }}"></i> 
-					<a href="{% url 'epic_details' epic_id=epic.id %}" class="story-closed">[Fermée] {{ epic.name }}</a>
-				</td>
-				<td class="backlog-editor-col2">
-					<form action="{% url 'epic_value_update' epic_id=epic.id %}" method="post" accept-charset="utf-8">
-						{% csrf_token %}
-				    	<input class="raw-input" name="value" type="text" value="{{ epic.value }}">
-				    </form>
-				</td>
-				<td class="backlog-editor-col3">
-					<a href="{% url 'epic_edit' epic_id=epic.id from_='backlog_editor' %}"><i class="fa fa-pencil" title="Editer"></i></a>
-					<a href="{% url 'epic_reopen' epic_id=epic.id %}"><i class="fa fa-folder-open" title="Réouvrir l'Epic"></i></a>
-				</td>
-			</tr>
-			{% endfor %}
-		</tbody>
-	
-	</table>
-
+{% extends '_layout.html' %}
+
+{% block title %}
+	Edition du backlog
+{% endblock %}
+
+
+{% block breadcrumb %}
+	<li><a href="{% url 'index' %}">Accueil</a></li>
+	<li><a>Edition du backlog</a></li>
+{% endblock %}
+
+
+{% block main %}
+	<header>
+		<div class="flex-row">
+			<h2 class="flex-extend">Backlog : Edition</h2>
+			<span>
+				<a href="{% url 'epic_create' %}"><i class="fa fa-plus"></i> Ajouter une Epic</a>
+			</span>
+		</div>
+	</header>
+
+
+	<table id="backlog-editor">
+		
+		<thead>
+			<th>Epic</th>
+			<th>Valeur</th>
+			<th>Options</th>
+		</thead>
+		
+		<tbody>
+		    
+			{% for epic in epics %}
+			<tr data-epic-id="{{ epic.id }}">
+				<td class="backlog-editor-col1">
+					<i class="fa fa-circle" style="margin-right: 0.5em; color:{{ epic.project.color }};" title="{{ epic.project.name }}"></i> 
+					<a class="epic-name" href="{% url 'epic_details' epic_id=epic.id %}">{{ epic.name }}</a>
+				</td>
+				<td class="backlog-editor-col2">
+					<form action="{% url 'epic_value_update' epic_id=epic.id %}" method="post" accept-charset="utf-8">
+						{% csrf_token %}
+				    	<input class="raw-input" name="value" type="text" value="{{ epic.value }}">
+				    </form>
+				</td>
+				<td class="backlog-editor-col3">
+					<a href="{% url 'epic_edit' epic_id=epic.id from_='backlog_editor' %}"><i class="fa fa-pencil" title="Editer"></i></a>
+					<a class="btn-epic-close" href="{% url 'epic_close' epic_id=epic.id %}"><i class="fa fa-archive" title="Clôre l'Epic"></i></a>
+				</td>
+			</tr>
+			{% endfor %}
+			
+			{% for epic in closed %}
+			<tr data-epic-id="{{ epic.id }}">
+				<td class="backlog-editor-col1">
+					<i class="fa fa-circle" style="margin-right: 0.5em; color:{{ epic.project.color }};" title="{{ epic.project.name }}"></i> 
+					<a class="epic-name story-closed" href="{% url 'epic_details' epic_id=epic.id %}">[Fermée] {{ epic.name }}</a>
+				</td>
+				<td class="backlog-editor-col2">
+					<form action="{% url 'epic_value_update' epic_id=epic.id %}" method="post" accept-charset="utf-8">
+						{% csrf_token %}
+				    	<input class="raw-input" name="value" type="text" value="{{ epic.value }}">
+				    </form>
+				</td>
+				<td class="backlog-editor-col3">
+					<a href="{% url 'epic_edit' epic_id=epic.id from_='backlog_editor' %}"><i class="fa fa-pencil" title="Editer"></i></a>
+					<a class="btn-epic-reopen" href="{% url 'epic_reopen' epic_id=epic.id %}"><i class="fa fa-folder-open" title="Réouvrir l'Epic"></i></a>
+				</td>
+			</tr>
+			{% endfor %}
+			
+		</tbody>
+	
+	</table>
+
 {% endblock %}

+ 18 - 6
main/views.py

@@ -302,9 +302,13 @@ def epic_delete(request, epic_id):
 def epic_value_update(request, epic_id):
     if request.method == 'POST':
         epic = get_object_or_404(Epic, id=epic_id)
-        epic.value = request.POST["value"]
+        epic.value = request.POST.get('value')
         epic.save()
-        return redirect("backlog_editor")
+            
+        if request.is_ajax():
+            return HttpResponse(epic.to_json())
+        else:
+            return redirect("backlog_editor")
     
 @login_required
 def epic_close(request, epic_id):
@@ -312,15 +316,23 @@ def epic_close(request, epic_id):
     epic.close()
     epic.save()
     notify_epic_closed(epic, request.user)
-    return redirect("backlog_editor")
-
+    
+    if request.is_ajax():
+        return HttpResponse(epic.to_json())
+    else:
+        return redirect("backlog_editor")
+    
 @login_required
 def epic_reopen(request, epic_id):
     epic = get_object_or_404(Epic, id=epic_id)
     epic.reopen()
     notify_epic_reopened(epic, request.user)
-    return redirect("backlog_editor")
-
+    
+    if request.is_ajax():
+        return HttpResponse(epic.to_json())
+    else:
+        return redirect("backlog_editor")
+    
 @login_required
 def reports(request):
     return render(request, 'reports/report_index.html')