all screens are now covered (but not completed)
authorduong tam kien <tk@deveha.com>
Tue, 18 Jul 2017 18:15:51 +0200
changeset 121 21ac67ebf9e7
parent 120 892980a3af09
child 122 964633aa5d45
all screens are now covered (but not completed)
design/_includes/sessions.list.html
design/_layouts/default.html
design/group-info-edit.html
design/group-info.html
design/group-protocol-edit.html
design/group.html
design/js/jquery-sortable.js
design/js/tether.min.js
design/tooltip.html
--- a/design/_includes/sessions.list.html	Wed Jul 19 16:20:29 2017 +0200
+++ b/design/_includes/sessions.list.html	Tue Jul 18 18:15:51 2017 +0200
@@ -18,13 +18,13 @@
 		{{ session.first | date: "%d/%m/%Y %H:%M" }} → {{ session.last | date: "%d/%m/%Y %H:%M" }}
 	</small>
 
-	<div>
-		{{ session.annotations }} notes / <span><small class="text-muted"><a href="compare-1.html">comparer avec une autre session</a></small></span>
+	<div class="mb-2">
+		<small><strong>{{ session.annotations }} notes</strong> &bull; <a href="#">partager avec le groupe</a>  &bull; <a href="compare-1.html">comparer avec une autre session</a></small>
 	</div>
 
 	<div>{{ session.description  }}</div>
 
-	<div class="keywords">
+	<div class="keywords mt-1">
 	<i class="fa fa-book" aria-hidden="true"></i> mots-clés : 
 
 	{% for keyword in session.keywords  %}
--- a/design/_layouts/default.html	Wed Jul 19 16:20:29 2017 +0200
+++ b/design/_layouts/default.html	Tue Jul 18 18:15:51 2017 +0200
@@ -11,10 +11,10 @@
 		<script src="https://use.fontawesome.com/fb0eb75d4e.js"></script>
 
 
-	<link rel="stylesheet" href="/css/main.css" />
+	<link rel="stylesheet" href="./css/main.css" />
 
   </head>
-  <body>
+  <body class="pb-5">
    
 	{{ content }}
 
@@ -22,5 +22,23 @@
     <script src="https://code.jquery.com/jquery-3.1.1.slim.min.js" integrity="sha384-A7FZj7v+d/sdmMqp/nOQwliLvUsJfDHW+k9Omg/a/EheAdgtzNs3hpfag6Ed950n" crossorigin="anonymous"></script>
     <script src="https://cdnjs.cloudflare.com/ajax/libs/tether/1.4.0/js/tether.min.js" integrity="sha384-DztdAPBWPRXSA/3eYEEUWrWCy7G5KFbe8fFjk5JAIxUYHKkDx6Qin1DkWx51bBrb" crossorigin="anonymous"></script>
     <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/js/bootstrap.min.js" integrity="sha384-vBWWzlZJ8ea9aCX4pEW3rVHjgjt7zpkNpZk+02D9phzyeVkE+jo0ieGizqPLForn" crossorigin="anonymous"></script>
-  </body>
+		 
+	
+		<script src="./js/jquery-sortable.js"></script>
+
+		<script>
+		$('#metacategories-extra').sortable();
+
+		$(function () {
+  		$('[data-toggle="tooltip"]').tooltip();
+  		$('[data-toggle="popover"]').popover();
+		});
+		</script>
+
+		{% if page.javascript %}
+		<script>
+			{{ page.javascript }}
+		</script>
+		{% endif %}
+	</body>
 </html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/design/group-info-edit.html	Tue Jul 18 18:15:51 2017 +0200
@@ -0,0 +1,87 @@
+---
+layout: default
+---
+
+{% include nav.html search=true %}
+
+<div class="container">
+	<div class="row justify-content-center">
+		<div class="col col-6">
+
+		<h2>Lorem ipsum</h2>
+		
+		<p class="lead">Nostrud esse amet deserunt exercitation proident in cupidatat ipsum reprehenderit adipisicing do ipsum aute. Dolor est elit voluptate voluptate velit cillum laborum eiusmod nisi.</p>
+
+		<form>
+			<div class="form-group">
+    		<label for="formGroupExampleInput">Nom du groupe</label>
+    		<input type="text" class="form-control" id="formGroupExampleInput" placeholder="Example input">
+  		</div>
+  		<div class="form-group">
+    		<label for="formGroupExampleInput2">Description</label>
+    		<input type="text" class="form-control" id="formGroupExampleInput2" placeholder="Another input">
+  		</div>
+
+			<button type="submit" class="btn btn-primary">Enregistrer</button>
+		</form>
+	
+		<h3 class="mt-5">
+			Protocole d'annotations 
+		</h3>
+
+		<p class="text-muted small">Le procole d'annotation est ensemble de méta-catégories définies par le groupe afin d'avoir un langage commun d'intentions.</p>
+
+		<ul class="list-group" id="metacategories">
+		{% for metacategory in site.data.metacategories %}
+			<li class="list-group-item">
+			<h4><span style="border-bottom: 3px solid rgb{{ metacategory.color  }};">{{ metacategory.label }}</span></h4>
+
+			<p>{{ metacategory.description  }}</p>
+			</li>
+		{% endfor %}
+		</ul>
+
+		<ol class="list-group mt-3 mb-3" id="metacategories-extra">
+		{% for metacategory in site.data.metacategories-extra %}
+			<li class="list-group-item">
+			<h4><span style="border-bottom: 3px solid rgb{{ metacategory.color  }};">{{ metacategory.label }}</span></h4>
+
+			<p>{{ metacategory.description  }}</p>
+			</li>
+		{% endfor %}
+		</ol>
+		<button type="submit" class="btn btn-primary">Enregistrer</button> <span class="small ml-2"><a href="#">voir l'historique</a></span>
+		
+		</div>
+	</div>
+</div>
+
+
+<style>
+body.dragging, body.dragging * {
+  cursor: move !important;
+}
+
+.dragged {
+  position: absolute;
+  opacity: 0.5;
+  z-index: 2000;
+}
+
+#metacategories-extra li.placeholder {
+  position: relative;
+  /** More li styles **/
+	background-color: rgba(0,0,0,.125);
+	list-style-type: none;
+	height: 10px;
+}
+#metacategories-extra li.placeholder:before {
+  position: absolute;
+  /** Define arrowhead **/
+
+	color: red;
+	content: "";
+	width:0;
+	height: 0;
+}
+</style>
--- a/design/group-info.html	Wed Jul 19 16:20:29 2017 +0200
+++ b/design/group-info.html	Tue Jul 18 18:15:51 2017 +0200
@@ -13,7 +13,7 @@
 		<p class="lead">Nostrud esse amet deserunt exercitation proident in cupidatat ipsum reprehenderit adipisicing do ipsum aute. Dolor est elit voluptate voluptate velit cillum laborum eiusmod nisi.</p>
 
 		<h3 class="mt-5">
-			Protocole d'annotations 
+			Protocole d'annotations <a href="group-protocol-edit.html">modifier</a>
 		</h3>
 
 		<p class="text-muted small">Le procole d'annotation est ensemble de méta-catégories définies par le groupe afin d'avoir un langage commun d'intentions.</p>
@@ -24,6 +24,8 @@
 			<p>{{ metacategory.description  }}</p>
 		{% endfor %}
 
+		<hr />
+
 		{% for metacategory in site.data.metacategories-extra %}
 			<h4><span style="border-bottom: 3px solid rgb{{ metacategory.color  }};">{{ metacategory.label }}</span></h4>
 
--- a/design/group-protocol-edit.html	Wed Jul 19 16:20:29 2017 +0200
+++ b/design/group-protocol-edit.html	Tue Jul 18 18:15:51 2017 +0200
@@ -7,44 +7,121 @@
 <div class="container">
 	<div class="row justify-content-center">
 		<div class="col col-6">
-
-		<h2>Lorem ipsum</h2>
-		
-		<p class="lead">Nostrud esse amet deserunt exercitation proident in cupidatat ipsum reprehenderit adipisicing do ipsum aute. Dolor est elit voluptate voluptate velit cillum laborum eiusmod nisi.</p>
-
-		<form>
-			<div class="form-group">
-    		<label for="formGroupExampleInput">Nom du groupe</label>
-    		<input type="text" class="form-control" id="formGroupExampleInput" placeholder="Example input">
-  		</div>
-  		<div class="form-group">
-    		<label for="formGroupExampleInput2">Description</label>
-    		<input type="text" class="form-control" id="formGroupExampleInput2" placeholder="Another input">
-  		</div>
-
-			<button type="submit" class="btn btn-primary">Enregistrer</button>
-		</form>
 	
 		<h3 class="mt-5">
-			Protocole d'annotations 
+			Protocole d'annotation 
 		</h3>
 
 		<p class="text-muted small">Le procole d'annotation est ensemble de méta-catégories définies par le groupe afin d'avoir un langage commun d'intentions.</p>
 
+		<p class="small text-muted mb-1">Méta-catégories obligatoires</p>
+
+		<ul class="list-group mb-3" id="metacategories">
 		{% for metacategory in site.data.metacategories %}
-			<h4><span style="border-bottom: 3px solid rgb{{ metacategory.color  }};">{{ metacategory.label }}</span></h4>
+			<li class="list-group-item">
+			<p class="mb-1"><span class="badge" style="background-color: rgb{{ metacategory.color  }};">{{ metacategory.label }}</span></p>
 
-			<p>{{ metacategory.description  }}</p>
+			<p class="small text-muted mb-0">{{ metacategory.description }}</p>
+			</li>
 		{% endfor %}
+		</ul>
 
+		<p class="small text-muted mb-1">Méta-catégories propres au groupe</p>
+
+		<ol class="list-group mb-2" id="metacategories-extra">
 		{% for metacategory in site.data.metacategories-extra %}
-			<h4><span style="border-bottom: 3px solid rgb{{ metacategory.color  }};">{{ metacategory.label }}</span></h4>
+			<li class="list-group-item">
+			<p class="mb-1 d-flex w-100 justify-content-between">
+				<span class="badge" style="background-color: rgb{{ metacategory.color  }};">{{ metacategory.label }}</span>
+				<a class="small" href="metacategory-edit.html" data-toggle="modal" data-target="#exampleModal">éditer</a>
+			</p>
+
+			<p class="small text-muted mb-0">{{ metacategory.description }}</p>
+			</li>
+		{% endfor %}
+		</ol>
 
-			<p>{{ metacategory.description  }}</p>
-		{% endfor %}
+		<div class="text-right mb-3">
+				<a href="#" class="" data-toggle="modal" data-target="#exampleModal">Ajouter une nouvelle méta-catégorie</a>
+			</div>
 
-		<button type="submit" class="btn btn-primary">Enregistrer</button> <span class="small ml-2"><a href="#">voir l'historique</a></span>
+		<div class="d-flex w-100 justify-content-between">
+			<div> </div>
+
+			<div>
+				<span class="mr-2"><a href="#">voir l'historique</a></span><button type="submit" class="btn btn-primary">Enregistrer</button> 
+			</div>
+		</div>
+
 		
 		</div>
 	</div>
 </div>
+
+
+<!-- Modal -->
+<div class="modal fade" id="exampleModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
+  <div class="modal-dialog" role="document">
+    <div class="modal-content">
+      <div class="modal-header">
+        <h5 class="modal-title" id="exampleModalLabel">Ajouter ou modifier</h5>
+        <button type="button" class="close" data-dismiss="modal" aria-label="Close">
+          <span aria-hidden="true">&times;</span>
+        </button>
+      </div>
+      <div class="modal-body">
+            <div class="modal-body">
+        			<form>
+          			<div class="form-group">
+            			<label for="metacategory-label" class="form-control-label">Étiquette</label>
+            			<input type="text" class="form-control" id="metacategory-label">
+          			</div>
+          			<div class="form-group">
+            			<label for="metacategory-color" class="form-control-label">Couleur</label>
+            			<input type="text" class="form-control" id="metacategory-color">
+          			</div>
+          			<div class="form-group">
+            			<label for="message-text" class="form-control-label">Description</label>
+            			<textarea class="form-control" id="message-text"></textarea>
+          		</div>
+        			</form>
+      			</div>
+			</div>
+      <div class="modal-footer">
+				<a href="#" class="mr-auto text-danger">supprimer</a>
+        <button type="button" class="btn btn-secondary" data-dismiss="modal">Fermer</button>
+        <button type="button" class="btn btn-primary">Enregistrer</button>
+      </div>
+    </div>
+  </div>
+</div>
+
+
+<style>
+body.dragging, body.dragging * {
+  cursor: move !important;
+}
+
+.dragged {
+  position: absolute;
+  opacity: 0.5;
+  z-index: 2000;
+}
+
+#metacategories-extra li.placeholder {
+  position: relative;
+  /** More li styles **/
+	background-color: rgba(0,0,0,.125);
+	list-style-type: none;
+	height: 10px;
+}
+#metacategories-extra li.placeholder:before {
+  position: absolute;
+  /** Define arrowhead **/
+
+	color: red;
+	content: "";
+	width:0;
+	height: 0;
+}
+</style>
--- a/design/group.html	Wed Jul 19 16:20:29 2017 +0200
+++ b/design/group.html	Tue Jul 18 18:15:51 2017 +0200
@@ -4,29 +4,67 @@
 
 {% include nav.html search=true %}
 <div class="container">
+
+	<h3 class="mb-3">Lorem ipsum</h3>
+
 	<div class="row">
 		<div class="col col-8">		
 			{% include sessions.list.html show_author=true %}
 		</div>
 		<div class="col col-4">
 			
-			<h3>Lorem ipsum</h3>
+			<small><strong>à propos</strong> &bull; <a href="group-info.html">éditer</a></small>
+
+			<div class="card mb-3">
+				<div class="card-block">
+					<p class="mb-0">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras nisi tortor, viverra id porta id, porttitor at justo. Curabitur pharetra, sapien sit amet ornare finibus, diam tortor varius sapien, non laoreet tellus ante a justo. Donec id lacus sit amet metus gravida tempus vel vitae justo.</p>
+				</div>
+			</div>
+
+			<small><strong>Protocole d'annotation</strong> &bull; <a href="group-protocol-edit.html">modifier</a></small>
 
-			<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras nisi tortor, viverra id porta id, porttitor at justo. Curabitur pharetra, sapien sit amet ornare finibus, diam tortor varius sapien, non laoreet tellus ante a justo. Donec id lacus sit amet metus gravida tempus vel vitae justo.</p>
+			<div class="card mb-3"><div class="card-block">
 
-			<h3>Protocole d'annotations</h3>
+			{% for metacategory in site.data.metacategories %}
+			
+			<div class="mb-2">
+				<span class="badge" style="background-color: rgb{{ metacategory.color }}">{{ metacategory.label }}</span> <span class="small">{{ metacategory.description }}</span>
+			</div>
+
+			{% endfor %}
+
+			<hr />
 
-			<h3>Membres</h3>
+			{% for metacategory in site.data.metacategories-extra %}
+			
+			<div class="mb-2">
+				<span class="badge" style="background-color: rgb{{ metacategory.color }}">{{ metacategory.label }}</span> <span class="small">{{ metacategory.description }}</span>
+			</div>
 
-			<div>
+			{% endfor %}
+			</div></div>
+
+
+			<small><strong>Membres</strong></small>
+		
+			<div class="card">
+			
+			<div class="list-group list-group-flush">
 			{% for member in site.data.members %}
-			<div class="mb-2">
-				<div>{{ member.name  }} <span class="text-muted">{{ member.shared_sessions }}</span></div>
-				<div><span class="text-muted small">{{ member.last_seen }}</span></div>
+			<div class="list-group-item d-flex flex-row flex-nowrap">
+				<div class="mr-3">
+					<span class="badge badge-default badge-pill">{{ member.shared_sessions }}</span>
+				</div>
+				<div>
+					{{ member.name  }}
+					<div><span class="text-muted small">{{ member.last_seen }}</span></div>
+				</div>
 			</div>
 			{% endfor %}
 			</div>
 
+			</div>
+
 		</div>
 	</div>
 </div>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/design/js/jquery-sortable.js	Tue Jul 18 18:15:51 2017 +0200
@@ -0,0 +1,693 @@
+/* ===================================================
+ *  jquery-sortable.js v0.9.13
+ *  http://johnny.github.com/jquery-sortable/
+ * ===================================================
+ *  Copyright (c) 2012 Jonas von Andrian
+ *  All rights reserved.
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *  * The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ *  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ *  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ *  DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
+ *  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ *  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ *  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ========================================================== */
+
+
+!function ( $, window, pluginName, undefined){
+  var containerDefaults = {
+    // If true, items can be dragged from this container
+    drag: true,
+    // If true, items can be droped onto this container
+    drop: true,
+    // Exclude items from being draggable, if the
+    // selector matches the item
+    exclude: "",
+    // If true, search for nested containers within an item.If you nest containers,
+    // either the original selector with which you call the plugin must only match the top containers,
+    // or you need to specify a group (see the bootstrap nav example)
+    nested: true,
+    // If true, the items are assumed to be arranged vertically
+    vertical: true
+  }, // end container defaults
+  groupDefaults = {
+    // This is executed after the placeholder has been moved.
+    // $closestItemOrContainer contains the closest item, the placeholder
+    // has been put at or the closest empty Container, the placeholder has
+    // been appended to.
+    afterMove: function ($placeholder, container, $closestItemOrContainer) {
+    },
+    // The exact css path between the container and its items, e.g. "> tbody"
+    containerPath: "",
+    // The css selector of the containers
+    containerSelector: "ol, ul",
+    // Distance the mouse has to travel to start dragging
+    distance: 0,
+    // Time in milliseconds after mousedown until dragging should start.
+    // This option can be used to prevent unwanted drags when clicking on an element.
+    delay: 0,
+    // The css selector of the drag handle
+    handle: "",
+    // The exact css path between the item and its subcontainers.
+    // It should only match the immediate items of a container.
+    // No item of a subcontainer should be matched. E.g. for ol>div>li the itemPath is "> div"
+    itemPath: "",
+    // The css selector of the items
+    itemSelector: "li",
+    // The class given to "body" while an item is being dragged
+    bodyClass: "dragging",
+    // The class giving to an item while being dragged
+    draggedClass: "dragged",
+    // Check if the dragged item may be inside the container.
+    // Use with care, since the search for a valid container entails a depth first search
+    // and may be quite expensive.
+    isValidTarget: function ($item, container) {
+      return true
+    },
+    // Executed before onDrop if placeholder is detached.
+    // This happens if pullPlaceholder is set to false and the drop occurs outside a container.
+    onCancel: function ($item, container, _super, event) {
+    },
+    // Executed at the beginning of a mouse move event.
+    // The Placeholder has not been moved yet.
+    onDrag: function ($item, position, _super, event) {
+      $item.css(position)
+    },
+    // Called after the drag has been started,
+    // that is the mouse button is being held down and
+    // the mouse is moving.
+    // The container is the closest initialized container.
+    // Therefore it might not be the container, that actually contains the item.
+    onDragStart: function ($item, container, _super, event) {
+      $item.css({
+        height: $item.outerHeight(),
+        width: $item.outerWidth()
+      })
+      $item.addClass(container.group.options.draggedClass)
+      $("body").addClass(container.group.options.bodyClass)
+    },
+    // Called when the mouse button is being released
+    onDrop: function ($item, container, _super, event) {
+      $item.removeClass(container.group.options.draggedClass).removeAttr("style")
+      $("body").removeClass(container.group.options.bodyClass)
+    },
+    // Called on mousedown. If falsy value is returned, the dragging will not start.
+    // Ignore if element clicked is input, select or textarea
+    onMousedown: function ($item, _super, event) {
+      if (!event.target.nodeName.match(/^(input|select|textarea)$/i)) {
+        event.preventDefault()
+        return true
+      }
+    },
+    // The class of the placeholder (must match placeholder option markup)
+    placeholderClass: "placeholder",
+    // Template for the placeholder. Can be any valid jQuery input
+    // e.g. a string, a DOM element.
+    // The placeholder must have the class "placeholder"
+    placeholder: '<li class="placeholder"></li>',
+    // If true, the position of the placeholder is calculated on every mousemove.
+    // If false, it is only calculated when the mouse is above a container.
+    pullPlaceholder: true,
+    // Specifies serialization of the container group.
+    // The pair $parent/$children is either container/items or item/subcontainers.
+    serialize: function ($parent, $children, parentIsContainer) {
+      var result = $.extend({}, $parent.data())
+
+      if(parentIsContainer)
+        return [$children]
+      else if ($children[0]){
+        result.children = $children
+      }
+
+      delete result.subContainers
+      delete result.sortable
+
+      return result
+    },
+    // Set tolerance while dragging. Positive values decrease sensitivity,
+    // negative values increase it.
+    tolerance: 0
+  }, // end group defaults
+  containerGroups = {},
+  groupCounter = 0,
+  emptyBox = {
+    left: 0,
+    top: 0,
+    bottom: 0,
+    right:0
+  },
+  eventNames = {
+    start: "touchstart.sortable mousedown.sortable",
+    drop: "touchend.sortable touchcancel.sortable mouseup.sortable",
+    drag: "touchmove.sortable mousemove.sortable",
+    scroll: "scroll.sortable"
+  },
+  subContainerKey = "subContainers"
+
+  /*
+   * a is Array [left, right, top, bottom]
+   * b is array [left, top]
+   */
+  function d(a,b) {
+    var x = Math.max(0, a[0] - b[0], b[0] - a[1]),
+    y = Math.max(0, a[2] - b[1], b[1] - a[3])
+    return x+y;
+  }
+
+  function setDimensions(array, dimensions, tolerance, useOffset) {
+    var i = array.length,
+    offsetMethod = useOffset ? "offset" : "position"
+    tolerance = tolerance || 0
+
+    while(i--){
+      var el = array[i].el ? array[i].el : $(array[i]),
+      // use fitting method
+      pos = el[offsetMethod]()
+      pos.left += parseInt(el.css('margin-left'), 10)
+      pos.top += parseInt(el.css('margin-top'),10)
+      dimensions[i] = [
+        pos.left - tolerance,
+        pos.left + el.outerWidth() + tolerance,
+        pos.top - tolerance,
+        pos.top + el.outerHeight() + tolerance
+      ]
+    }
+  }
+
+  function getRelativePosition(pointer, element) {
+    var offset = element.offset()
+    return {
+      left: pointer.left - offset.left,
+      top: pointer.top - offset.top
+    }
+  }
+
+  function sortByDistanceDesc(dimensions, pointer, lastPointer) {
+    pointer = [pointer.left, pointer.top]
+    lastPointer = lastPointer && [lastPointer.left, lastPointer.top]
+
+    var dim,
+    i = dimensions.length,
+    distances = []
+
+    while(i--){
+      dim = dimensions[i]
+      distances[i] = [i,d(dim,pointer), lastPointer && d(dim, lastPointer)]
+    }
+    distances = distances.sort(function  (a,b) {
+      return b[1] - a[1] || b[2] - a[2] || b[0] - a[0]
+    })
+
+    // last entry is the closest
+    return distances
+  }
+
+  function ContainerGroup(options) {
+    this.options = $.extend({}, groupDefaults, options)
+    this.containers = []
+
+    if(!this.options.rootGroup){
+      this.scrollProxy = $.proxy(this.scroll, this)
+      this.dragProxy = $.proxy(this.drag, this)
+      this.dropProxy = $.proxy(this.drop, this)
+      this.placeholder = $(this.options.placeholder)
+
+      if(!options.isValidTarget)
+        this.options.isValidTarget = undefined
+    }
+  }
+
+  ContainerGroup.get = function  (options) {
+    if(!containerGroups[options.group]) {
+      if(options.group === undefined)
+        options.group = groupCounter ++
+
+      containerGroups[options.group] = new ContainerGroup(options)
+    }
+
+    return containerGroups[options.group]
+  }
+
+  ContainerGroup.prototype = {
+    dragInit: function  (e, itemContainer) {
+      this.$document = $(itemContainer.el[0].ownerDocument)
+
+      // get item to drag
+      var closestItem = $(e.target).closest(this.options.itemSelector);
+      // using the length of this item, prevents the plugin from being started if there is no handle being clicked on.
+      // this may also be helpful in instantiating multidrag.
+      if (closestItem.length) {
+        this.item = closestItem;
+        this.itemContainer = itemContainer;
+        if (this.item.is(this.options.exclude) || !this.options.onMousedown(this.item, groupDefaults.onMousedown, e)) {
+            return;
+        }
+        this.setPointer(e);
+        this.toggleListeners('on');
+        this.setupDelayTimer();
+        this.dragInitDone = true;
+      }
+    },
+    drag: function  (e) {
+      if(!this.dragging){
+        if(!this.distanceMet(e) || !this.delayMet)
+          return
+
+        this.options.onDragStart(this.item, this.itemContainer, groupDefaults.onDragStart, e)
+        this.item.before(this.placeholder)
+        this.dragging = true
+      }
+
+      this.setPointer(e)
+      // place item under the cursor
+      this.options.onDrag(this.item,
+                          getRelativePosition(this.pointer, this.item.offsetParent()),
+                          groupDefaults.onDrag,
+                          e)
+
+      var p = this.getPointer(e),
+      box = this.sameResultBox,
+      t = this.options.tolerance
+
+      if(!box || box.top - t > p.top || box.bottom + t < p.top || box.left - t > p.left || box.right + t < p.left)
+        if(!this.searchValidTarget()){
+          this.placeholder.detach()
+          this.lastAppendedItem = undefined
+        }
+    },
+    drop: function  (e) {
+      this.toggleListeners('off')
+
+      this.dragInitDone = false
+
+      if(this.dragging){
+        // processing Drop, check if placeholder is detached
+        if(this.placeholder.closest("html")[0]){
+          this.placeholder.before(this.item).detach()
+        } else {
+          this.options.onCancel(this.item, this.itemContainer, groupDefaults.onCancel, e)
+        }
+        this.options.onDrop(this.item, this.getContainer(this.item), groupDefaults.onDrop, e)
+
+        // cleanup
+        this.clearDimensions()
+        this.clearOffsetParent()
+        this.lastAppendedItem = this.sameResultBox = undefined
+        this.dragging = false
+      }
+    },
+    searchValidTarget: function  (pointer, lastPointer) {
+      if(!pointer){
+        pointer = this.relativePointer || this.pointer
+        lastPointer = this.lastRelativePointer || this.lastPointer
+      }
+
+      var distances = sortByDistanceDesc(this.getContainerDimensions(),
+                                         pointer,
+                                         lastPointer),
+      i = distances.length
+
+      while(i--){
+        var index = distances[i][0],
+        distance = distances[i][1]
+
+        if(!distance || this.options.pullPlaceholder){
+          var container = this.containers[index]
+          if(!container.disabled){
+            if(!this.$getOffsetParent()){
+              var offsetParent = container.getItemOffsetParent()
+              pointer = getRelativePosition(pointer, offsetParent)
+              lastPointer = getRelativePosition(lastPointer, offsetParent)
+            }
+            if(container.searchValidTarget(pointer, lastPointer))
+              return true
+          }
+        }
+      }
+      if(this.sameResultBox)
+        this.sameResultBox = undefined
+    },
+    movePlaceholder: function  (container, item, method, sameResultBox) {
+      var lastAppendedItem = this.lastAppendedItem
+      if(!sameResultBox && lastAppendedItem && lastAppendedItem[0] === item[0])
+        return;
+
+      item[method](this.placeholder)
+      this.lastAppendedItem = item
+      this.sameResultBox = sameResultBox
+      this.options.afterMove(this.placeholder, container, item)
+    },
+    getContainerDimensions: function  () {
+      if(!this.containerDimensions)
+        setDimensions(this.containers, this.containerDimensions = [], this.options.tolerance, !this.$getOffsetParent())
+      return this.containerDimensions
+    },
+    getContainer: function  (element) {
+      return element.closest(this.options.containerSelector).data(pluginName)
+    },
+    $getOffsetParent: function  () {
+      if(this.offsetParent === undefined){
+        var i = this.containers.length - 1,
+        offsetParent = this.containers[i].getItemOffsetParent()
+
+        if(!this.options.rootGroup){
+          while(i--){
+            if(offsetParent[0] != this.containers[i].getItemOffsetParent()[0]){
+              // If every container has the same offset parent,
+              // use position() which is relative to this parent,
+              // otherwise use offset()
+              // compare #setDimensions
+              offsetParent = false
+              break;
+            }
+          }
+        }
+
+        this.offsetParent = offsetParent
+      }
+      return this.offsetParent
+    },
+    setPointer: function (e) {
+      var pointer = this.getPointer(e)
+
+      if(this.$getOffsetParent()){
+        var relativePointer = getRelativePosition(pointer, this.$getOffsetParent())
+        this.lastRelativePointer = this.relativePointer
+        this.relativePointer = relativePointer
+      }
+
+      this.lastPointer = this.pointer
+      this.pointer = pointer
+    },
+    distanceMet: function (e) {
+      var currentPointer = this.getPointer(e)
+      return (Math.max(
+        Math.abs(this.pointer.left - currentPointer.left),
+        Math.abs(this.pointer.top - currentPointer.top)
+      ) >= this.options.distance)
+    },
+    getPointer: function(e) {
+      var o = e.originalEvent || e.originalEvent.touches && e.originalEvent.touches[0]
+      return {
+        left: e.pageX || o.pageX,
+        top: e.pageY || o.pageY
+      }
+    },
+    setupDelayTimer: function () {
+      var that = this
+      this.delayMet = !this.options.delay
+
+      // init delay timer if needed
+      if (!this.delayMet) {
+        clearTimeout(this._mouseDelayTimer);
+        this._mouseDelayTimer = setTimeout(function() {
+          that.delayMet = true
+        }, this.options.delay)
+      }
+    },
+    scroll: function  (e) {
+      this.clearDimensions()
+      this.clearOffsetParent() // TODO is this needed?
+    },
+    toggleListeners: function (method) {
+      var that = this,
+      events = ['drag','drop','scroll']
+
+      $.each(events,function  (i,event) {
+        that.$document[method](eventNames[event], that[event + 'Proxy'])
+      })
+    },
+    clearOffsetParent: function () {
+      this.offsetParent = undefined
+    },
+    // Recursively clear container and item dimensions
+    clearDimensions: function  () {
+      this.traverse(function(object){
+        object._clearDimensions()
+      })
+    },
+    traverse: function(callback) {
+      callback(this)
+      var i = this.containers.length
+      while(i--){
+        this.containers[i].traverse(callback)
+      }
+    },
+    _clearDimensions: function(){
+      this.containerDimensions = undefined
+    },
+    _destroy: function () {
+      containerGroups[this.options.group] = undefined
+    }
+  }
+
+  function Container(element, options) {
+    this.el = element
+    this.options = $.extend( {}, containerDefaults, options)
+
+    this.group = ContainerGroup.get(this.options)
+    this.rootGroup = this.options.rootGroup || this.group
+    this.handle = this.rootGroup.options.handle || this.rootGroup.options.itemSelector
+
+    var itemPath = this.rootGroup.options.itemPath
+    this.target = itemPath ? this.el.find(itemPath) : this.el
+
+    this.target.on(eventNames.start, this.handle, $.proxy(this.dragInit, this))
+
+    if(this.options.drop)
+      this.group.containers.push(this)
+  }
+
+  Container.prototype = {
+    dragInit: function  (e) {
+      var rootGroup = this.rootGroup
+
+      if( !this.disabled &&
+          !rootGroup.dragInitDone &&
+          this.options.drag &&
+          this.isValidDrag(e)) {
+        rootGroup.dragInit(e, this)
+      }
+    },
+    isValidDrag: function(e) {
+      return e.which == 1 ||
+        e.type == "touchstart" && e.originalEvent.touches.length == 1
+    },
+    searchValidTarget: function  (pointer, lastPointer) {
+      var distances = sortByDistanceDesc(this.getItemDimensions(),
+                                         pointer,
+                                         lastPointer),
+      i = distances.length,
+      rootGroup = this.rootGroup,
+      validTarget = !rootGroup.options.isValidTarget ||
+        rootGroup.options.isValidTarget(rootGroup.item, this)
+
+      if(!i && validTarget){
+        rootGroup.movePlaceholder(this, this.target, "append")
+        return true
+      } else
+        while(i--){
+          var index = distances[i][0],
+          distance = distances[i][1]
+          if(!distance && this.hasChildGroup(index)){
+            var found = this.getContainerGroup(index).searchValidTarget(pointer, lastPointer)
+            if(found)
+              return true
+          }
+          else if(validTarget){
+            this.movePlaceholder(index, pointer)
+            return true
+          }
+        }
+    },
+    movePlaceholder: function  (index, pointer) {
+      var item = $(this.items[index]),
+      dim = this.itemDimensions[index],
+      method = "after",
+      width = item.outerWidth(),
+      height = item.outerHeight(),
+      offset = item.offset(),
+      sameResultBox = {
+        left: offset.left,
+        right: offset.left + width,
+        top: offset.top,
+        bottom: offset.top + height
+      }
+      if(this.options.vertical){
+        var yCenter = (dim[2] + dim[3]) / 2,
+        inUpperHalf = pointer.top <= yCenter
+        if(inUpperHalf){
+          method = "before"
+          sameResultBox.bottom -= height / 2
+        } else
+          sameResultBox.top += height / 2
+      } else {
+        var xCenter = (dim[0] + dim[1]) / 2,
+        inLeftHalf = pointer.left <= xCenter
+        if(inLeftHalf){
+          method = "before"
+          sameResultBox.right -= width / 2
+        } else
+          sameResultBox.left += width / 2
+      }
+      if(this.hasChildGroup(index))
+        sameResultBox = emptyBox
+      this.rootGroup.movePlaceholder(this, item, method, sameResultBox)
+    },
+    getItemDimensions: function  () {
+      if(!this.itemDimensions){
+        this.items = this.$getChildren(this.el, "item").filter(
+          ":not(." + this.group.options.placeholderClass + ", ." + this.group.options.draggedClass + ")"
+        ).get()
+        setDimensions(this.items, this.itemDimensions = [], this.options.tolerance)
+      }
+      return this.itemDimensions
+    },
+    getItemOffsetParent: function  () {
+      var offsetParent,
+      el = this.el
+      // Since el might be empty we have to check el itself and
+      // can not do something like el.children().first().offsetParent()
+      if(el.css("position") === "relative" || el.css("position") === "absolute"  || el.css("position") === "fixed")
+        offsetParent = el
+      else
+        offsetParent = el.offsetParent()
+      return offsetParent
+    },
+    hasChildGroup: function (index) {
+      return this.options.nested && this.getContainerGroup(index)
+    },
+    getContainerGroup: function  (index) {
+      var childGroup = $.data(this.items[index], subContainerKey)
+      if( childGroup === undefined){
+        var childContainers = this.$getChildren(this.items[index], "container")
+        childGroup = false
+
+        if(childContainers[0]){
+          var options = $.extend({}, this.options, {
+            rootGroup: this.rootGroup,
+            group: groupCounter ++
+          })
+          childGroup = childContainers[pluginName](options).data(pluginName).group
+        }
+        $.data(this.items[index], subContainerKey, childGroup)
+      }
+      return childGroup
+    },
+    $getChildren: function (parent, type) {
+      var options = this.rootGroup.options,
+      path = options[type + "Path"],
+      selector = options[type + "Selector"]
+
+      parent = $(parent)
+      if(path)
+        parent = parent.find(path)
+
+      return parent.children(selector)
+    },
+    _serialize: function (parent, isContainer) {
+      var that = this,
+      childType = isContainer ? "item" : "container",
+
+      children = this.$getChildren(parent, childType).not(this.options.exclude).map(function () {
+        return that._serialize($(this), !isContainer)
+      }).get()
+
+      return this.rootGroup.options.serialize(parent, children, isContainer)
+    },
+    traverse: function(callback) {
+      $.each(this.items || [], function(item){
+        var group = $.data(this, subContainerKey)
+        if(group)
+          group.traverse(callback)
+      });
+
+      callback(this)
+    },
+    _clearDimensions: function  () {
+      this.itemDimensions = undefined
+    },
+    _destroy: function() {
+      var that = this;
+
+      this.target.off(eventNames.start, this.handle);
+      this.el.removeData(pluginName)
+
+      if(this.options.drop)
+        this.group.containers = $.grep(this.group.containers, function(val){
+          return val != that
+        })
+
+      $.each(this.items || [], function(){
+        $.removeData(this, subContainerKey)
+      })
+    }
+  }
+
+  var API = {
+    enable: function() {
+      this.traverse(function(object){
+        object.disabled = false
+      })
+    },
+    disable: function (){
+      this.traverse(function(object){
+        object.disabled = true
+      })
+    },
+    serialize: function () {
+      return this._serialize(this.el, true)
+    },
+    refresh: function() {
+      this.traverse(function(object){
+        object._clearDimensions()
+      })
+    },
+    destroy: function () {
+      this.traverse(function(object){
+        object._destroy();
+      })
+    }
+  }
+
+  $.extend(Container.prototype, API)
+
+  /**
+   * jQuery API
+   *
+   * Parameters are
+   *   either options on init
+   *   or a method name followed by arguments to pass to the method
+   */
+  $.fn[pluginName] = function(methodOrOptions) {
+    var args = Array.prototype.slice.call(arguments, 1)
+
+    return this.map(function(){
+      var $t = $(this),
+      object = $t.data(pluginName)
+
+      if(object && API[methodOrOptions])
+        return API[methodOrOptions].apply(object, args) || this
+      else if(!object && (methodOrOptions === undefined ||
+                          typeof methodOrOptions === "object"))
+        $t.data(pluginName, new Container($t, methodOrOptions))
+
+      return this
+    });
+  };
+
+}(jQuery, window, 'sortable');
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/design/js/tether.min.js	Tue Jul 18 18:15:51 2017 +0200
@@ -0,0 +1,1 @@
+!function(t,e){"function"==typeof define&&define.amd?define(e):"object"==typeof exports?module.exports=e(require,exports,module):t.Tether=e()}(this,function(t,e,o){"use strict";function i(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function n(t){var e=t.getBoundingClientRect(),o={};for(var i in e)o[i]=e[i];if(t.ownerDocument!==document){var r=t.ownerDocument.defaultView.frameElement;if(r){var s=n(r);o.top+=s.top,o.bottom+=s.top,o.left+=s.left,o.right+=s.left}}return o}function r(t){var e=getComputedStyle(t)||{},o=e.position,i=[];if("fixed"===o)return[t];for(var n=t;(n=n.parentNode)&&n&&1===n.nodeType;){var r=void 0;try{r=getComputedStyle(n)}catch(s){}if("undefined"==typeof r||null===r)return i.push(n),i;var a=r,f=a.overflow,l=a.overflowX,h=a.overflowY;/(auto|scroll|overlay)/.test(f+h+l)&&("absolute"!==o||["relative","absolute","fixed"].indexOf(r.position)>=0)&&i.push(n)}return i.push(t.ownerDocument.body),t.ownerDocument!==document&&i.push(t.ownerDocument.defaultView),i}function s(){A&&document.body.removeChild(A),A=null}function a(t){var e=void 0;t===document?(e=document,t=document.documentElement):e=t.ownerDocument;var o=e.documentElement,i=n(t),r=P();return i.top-=r.top,i.left-=r.left,"undefined"==typeof i.width&&(i.width=document.body.scrollWidth-i.left-i.right),"undefined"==typeof i.height&&(i.height=document.body.scrollHeight-i.top-i.bottom),i.top=i.top-o.clientTop,i.left=i.left-o.clientLeft,i.right=e.body.clientWidth-i.width-i.left,i.bottom=e.body.clientHeight-i.height-i.top,i}function f(t){return t.offsetParent||document.documentElement}function l(){if(M)return M;var t=document.createElement("div");t.style.width="100%",t.style.height="200px";var e=document.createElement("div");h(e.style,{position:"absolute",top:0,left:0,pointerEvents:"none",visibility:"hidden",width:"200px",height:"150px",overflow:"hidden"}),e.appendChild(t),document.body.appendChild(e);var o=t.offsetWidth;e.style.overflow="scroll";var i=t.offsetWidth;o===i&&(i=e.clientWidth),document.body.removeChild(e);var n=o-i;return M={width:n,height:n}}function h(){var t=arguments.length<=0||void 0===arguments[0]?{}:arguments[0],e=[];return Array.prototype.push.apply(e,arguments),e.slice(1).forEach(function(e){if(e)for(var o in e)({}).hasOwnProperty.call(e,o)&&(t[o]=e[o])}),t}function d(t,e){if("undefined"!=typeof t.classList)e.split(" ").forEach(function(e){e.trim()&&t.classList.remove(e)});else{var o=new RegExp("(^| )"+e.split(" ").join("|")+"( |$)","gi"),i=c(t).replace(o," ");g(t,i)}}function p(t,e){if("undefined"!=typeof t.classList)e.split(" ").forEach(function(e){e.trim()&&t.classList.add(e)});else{d(t,e);var o=c(t)+(" "+e);g(t,o)}}function u(t,e){if("undefined"!=typeof t.classList)return t.classList.contains(e);var o=c(t);return new RegExp("(^| )"+e+"( |$)","gi").test(o)}function c(t){return t.className instanceof t.ownerDocument.defaultView.SVGAnimatedString?t.className.baseVal:t.className}function g(t,e){t.setAttribute("class",e)}function m(t,e,o){o.forEach(function(o){e.indexOf(o)===-1&&u(t,o)&&d(t,o)}),e.forEach(function(e){u(t,e)||p(t,e)})}function i(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function v(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}function y(t,e){var o=arguments.length<=2||void 0===arguments[2]?1:arguments[2];return t+o>=e&&e>=t-o}function b(){return"undefined"!=typeof performance&&"undefined"!=typeof performance.now?performance.now():+new Date}function w(){for(var t={top:0,left:0},e=arguments.length,o=Array(e),i=0;i<e;i++)o[i]=arguments[i];return o.forEach(function(e){var o=e.top,i=e.left;"string"==typeof o&&(o=parseFloat(o,10)),"string"==typeof i&&(i=parseFloat(i,10)),t.top+=o,t.left+=i}),t}function C(t,e){return"string"==typeof t.left&&t.left.indexOf("%")!==-1&&(t.left=parseFloat(t.left,10)/100*e.width),"string"==typeof t.top&&t.top.indexOf("%")!==-1&&(t.top=parseFloat(t.top,10)/100*e.height),t}function O(t,e){return"scrollParent"===e?e=t.scrollParents[0]:"window"===e&&(e=[pageXOffset,pageYOffset,innerWidth+pageXOffset,innerHeight+pageYOffset]),e===document&&(e=e.documentElement),"undefined"!=typeof e.nodeType&&!function(){var t=e,o=a(e),i=o,n=getComputedStyle(e);if(e=[i.left,i.top,o.width+i.left,o.height+i.top],t.ownerDocument!==document){var r=t.ownerDocument.defaultView;e[0]+=r.pageXOffset,e[1]+=r.pageYOffset,e[2]+=r.pageXOffset,e[3]+=r.pageYOffset}G.forEach(function(t,o){t=t[0].toUpperCase()+t.substr(1),"Top"===t||"Left"===t?e[o]+=parseFloat(n["border"+t+"Width"]):e[o]-=parseFloat(n["border"+t+"Width"])})}(),e}var E=function(){function t(t,e){for(var o=0;o<e.length;o++){var i=e[o];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(t,i.key,i)}}return function(e,o,i){return o&&t(e.prototype,o),i&&t(e,i),e}}(),x=void 0;"undefined"==typeof x&&(x={modules:[]});var A=null,T=function(){var t=0;return function(){return++t}}(),S={},P=function(){var t=A;t&&document.body.contains(t)||(t=document.createElement("div"),t.setAttribute("data-tether-id",T()),h(t.style,{top:0,left:0,position:"absolute"}),document.body.appendChild(t),A=t);var e=t.getAttribute("data-tether-id");return"undefined"==typeof S[e]&&(S[e]=n(t),k(function(){delete S[e]})),S[e]},M=null,W=[],k=function(t){W.push(t)},_=function(){for(var t=void 0;t=W.pop();)t()},B=function(){function t(){i(this,t)}return E(t,[{key:"on",value:function(t,e,o){var i=!(arguments.length<=3||void 0===arguments[3])&&arguments[3];"undefined"==typeof this.bindings&&(this.bindings={}),"undefined"==typeof this.bindings[t]&&(this.bindings[t]=[]),this.bindings[t].push({handler:e,ctx:o,once:i})}},{key:"once",value:function(t,e,o){this.on(t,e,o,!0)}},{key:"off",value:function(t,e){if("undefined"!=typeof this.bindings&&"undefined"!=typeof this.bindings[t])if("undefined"==typeof e)delete this.bindings[t];else for(var o=0;o<this.bindings[t].length;)this.bindings[t][o].handler===e?this.bindings[t].splice(o,1):++o}},{key:"trigger",value:function(t){if("undefined"!=typeof this.bindings&&this.bindings[t]){for(var e=0,o=arguments.length,i=Array(o>1?o-1:0),n=1;n<o;n++)i[n-1]=arguments[n];for(;e<this.bindings[t].length;){var r=this.bindings[t][e],s=r.handler,a=r.ctx,f=r.once,l=a;"undefined"==typeof l&&(l=this),s.apply(l,i),f?this.bindings[t].splice(e,1):++e}}}}]),t}();x.Utils={getActualBoundingClientRect:n,getScrollParents:r,getBounds:a,getOffsetParent:f,extend:h,addClass:p,removeClass:d,hasClass:u,updateClasses:m,defer:k,flush:_,uniqueId:T,Evented:B,getScrollBarSize:l,removeUtilElements:s};var z=function(){function t(t,e){var o=[],i=!0,n=!1,r=void 0;try{for(var s,a=t[Symbol.iterator]();!(i=(s=a.next()).done)&&(o.push(s.value),!e||o.length!==e);i=!0);}catch(f){n=!0,r=f}finally{try{!i&&a["return"]&&a["return"]()}finally{if(n)throw r}}return o}return function(e,o){if(Array.isArray(e))return e;if(Symbol.iterator in Object(e))return t(e,o);throw new TypeError("Invalid attempt to destructure non-iterable instance")}}(),E=function(){function t(t,e){for(var o=0;o<e.length;o++){var i=e[o];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(t,i.key,i)}}return function(e,o,i){return o&&t(e.prototype,o),i&&t(e,i),e}}(),j=function(t,e,o){for(var i=!0;i;){var n=t,r=e,s=o;i=!1,null===n&&(n=Function.prototype);var a=Object.getOwnPropertyDescriptor(n,r);if(void 0!==a){if("value"in a)return a.value;var f=a.get;if(void 0===f)return;return f.call(s)}var l=Object.getPrototypeOf(n);if(null===l)return;t=l,e=r,o=s,i=!0,a=l=void 0}};if("undefined"==typeof x)throw new Error("You must include the utils.js file before tether.js");var Y=x.Utils,r=Y.getScrollParents,a=Y.getBounds,f=Y.getOffsetParent,h=Y.extend,p=Y.addClass,d=Y.removeClass,m=Y.updateClasses,k=Y.defer,_=Y.flush,l=Y.getScrollBarSize,s=Y.removeUtilElements,L=function(){if("undefined"==typeof document)return"";for(var t=document.createElement("div"),e=["transform","WebkitTransform","OTransform","MozTransform","msTransform"],o=0;o<e.length;++o){var i=e[o];if(void 0!==t.style[i])return i}}(),D=[],X=function(){D.forEach(function(t){t.position(!1)}),_()};!function(){var t=null,e=null,o=null,i=function n(){return"undefined"!=typeof e&&e>16?(e=Math.min(e-16,250),void(o=setTimeout(n,250))):void("undefined"!=typeof t&&b()-t<10||(null!=o&&(clearTimeout(o),o=null),t=b(),X(),e=b()-t))};"undefined"!=typeof window&&"undefined"!=typeof window.addEventListener&&["resize","scroll","touchmove"].forEach(function(t){window.addEventListener(t,i)})}();var F={center:"center",left:"right",right:"left"},H={middle:"middle",top:"bottom",bottom:"top"},N={top:0,left:0,middle:"50%",center:"50%",bottom:"100%",right:"100%"},U=function(t,e){var o=t.left,i=t.top;return"auto"===o&&(o=F[e.left]),"auto"===i&&(i=H[e.top]),{left:o,top:i}},V=function(t){var e=t.left,o=t.top;return"undefined"!=typeof N[t.left]&&(e=N[t.left]),"undefined"!=typeof N[t.top]&&(o=N[t.top]),{left:e,top:o}},R=function(t){var e=t.split(" "),o=z(e,2),i=o[0],n=o[1];return{top:i,left:n}},q=R,I=function(t){function e(t){var o=this;i(this,e),j(Object.getPrototypeOf(e.prototype),"constructor",this).call(this),this.position=this.position.bind(this),D.push(this),this.history=[],this.setOptions(t,!1),x.modules.forEach(function(t){"undefined"!=typeof t.initialize&&t.initialize.call(o)}),this.position()}return v(e,t),E(e,[{key:"getClass",value:function(){var t=arguments.length<=0||void 0===arguments[0]?"":arguments[0],e=this.options.classes;return"undefined"!=typeof e&&e[t]?this.options.classes[t]:this.options.classPrefix?this.options.classPrefix+"-"+t:t}},{key:"setOptions",value:function(t){var e=this,o=arguments.length<=1||void 0===arguments[1]||arguments[1],i={offset:"0 0",targetOffset:"0 0",targetAttachment:"auto auto",classPrefix:"tether"};this.options=h(i,t);var n=this.options,s=n.element,a=n.target,f=n.targetModifier;if(this.element=s,this.target=a,this.targetModifier=f,"viewport"===this.target?(this.target=document.body,this.targetModifier="visible"):"scroll-handle"===this.target&&(this.target=document.body,this.targetModifier="scroll-handle"),["element","target"].forEach(function(t){if("undefined"==typeof e[t])throw new Error("Tether Error: Both element and target must be defined");"undefined"!=typeof e[t].jquery?e[t]=e[t][0]:"string"==typeof e[t]&&(e[t]=document.querySelector(e[t]))}),p(this.element,this.getClass("element")),this.options.addTargetClasses!==!1&&p(this.target,this.getClass("target")),!this.options.attachment)throw new Error("Tether Error: You must provide an attachment");this.targetAttachment=q(this.options.targetAttachment),this.attachment=q(this.options.attachment),this.offset=R(this.options.offset),this.targetOffset=R(this.options.targetOffset),"undefined"!=typeof this.scrollParents&&this.disable(),"scroll-handle"===this.targetModifier?this.scrollParents=[this.target]:this.scrollParents=r(this.target),this.options.enabled!==!1&&this.enable(o)}},{key:"getTargetBounds",value:function(){if("undefined"==typeof this.targetModifier)return a(this.target);if("visible"===this.targetModifier){if(this.target===document.body)return{top:pageYOffset,left:pageXOffset,height:innerHeight,width:innerWidth};var t=a(this.target),e={height:t.height,width:t.width,top:t.top,left:t.left};return e.height=Math.min(e.height,t.height-(pageYOffset-t.top)),e.height=Math.min(e.height,t.height-(t.top+t.height-(pageYOffset+innerHeight))),e.height=Math.min(innerHeight,e.height),e.height-=2,e.width=Math.min(e.width,t.width-(pageXOffset-t.left)),e.width=Math.min(e.width,t.width-(t.left+t.width-(pageXOffset+innerWidth))),e.width=Math.min(innerWidth,e.width),e.width-=2,e.top<pageYOffset&&(e.top=pageYOffset),e.left<pageXOffset&&(e.left=pageXOffset),e}if("scroll-handle"===this.targetModifier){var t=void 0,o=this.target;o===document.body?(o=document.documentElement,t={left:pageXOffset,top:pageYOffset,height:innerHeight,width:innerWidth}):t=a(o);var i=getComputedStyle(o),n=o.scrollWidth>o.clientWidth||[i.overflow,i.overflowX].indexOf("scroll")>=0||this.target!==document.body,r=0;n&&(r=15);var s=t.height-parseFloat(i.borderTopWidth)-parseFloat(i.borderBottomWidth)-r,e={width:15,height:.975*s*(s/o.scrollHeight),left:t.left+t.width-parseFloat(i.borderLeftWidth)-15},f=0;s<408&&this.target===document.body&&(f=-11e-5*Math.pow(s,2)-.00727*s+22.58),this.target!==document.body&&(e.height=Math.max(e.height,24));var l=this.target.scrollTop/(o.scrollHeight-s);return e.top=l*(s-e.height-f)+t.top+parseFloat(i.borderTopWidth),this.target===document.body&&(e.height=Math.max(e.height,24)),e}}},{key:"clearCache",value:function(){this._cache={}}},{key:"cache",value:function(t,e){return"undefined"==typeof this._cache&&(this._cache={}),"undefined"==typeof this._cache[t]&&(this._cache[t]=e.call(this)),this._cache[t]}},{key:"enable",value:function(){var t=this,e=arguments.length<=0||void 0===arguments[0]||arguments[0];this.options.addTargetClasses!==!1&&p(this.target,this.getClass("enabled")),p(this.element,this.getClass("enabled")),this.enabled=!0,this.scrollParents.forEach(function(e){e!==t.target.ownerDocument&&e.addEventListener("scroll",t.position)}),e&&this.position()}},{key:"disable",value:function(){var t=this;d(this.target,this.getClass("enabled")),d(this.element,this.getClass("enabled")),this.enabled=!1,"undefined"!=typeof this.scrollParents&&this.scrollParents.forEach(function(e){e.removeEventListener("scroll",t.position)})}},{key:"destroy",value:function(){var t=this;this.disable(),D.forEach(function(e,o){e===t&&D.splice(o,1)}),0===D.length&&s()}},{key:"updateAttachClasses",value:function(t,e){var o=this;t=t||this.attachment,e=e||this.targetAttachment;var i=["left","top","bottom","right","middle","center"];"undefined"!=typeof this._addAttachClasses&&this._addAttachClasses.length&&this._addAttachClasses.splice(0,this._addAttachClasses.length),"undefined"==typeof this._addAttachClasses&&(this._addAttachClasses=[]);var n=this._addAttachClasses;t.top&&n.push(this.getClass("element-attached")+"-"+t.top),t.left&&n.push(this.getClass("element-attached")+"-"+t.left),e.top&&n.push(this.getClass("target-attached")+"-"+e.top),e.left&&n.push(this.getClass("target-attached")+"-"+e.left);var r=[];i.forEach(function(t){r.push(o.getClass("element-attached")+"-"+t),r.push(o.getClass("target-attached")+"-"+t)}),k(function(){"undefined"!=typeof o._addAttachClasses&&(m(o.element,o._addAttachClasses,r),o.options.addTargetClasses!==!1&&m(o.target,o._addAttachClasses,r),delete o._addAttachClasses)})}},{key:"position",value:function(){var t=this,e=arguments.length<=0||void 0===arguments[0]||arguments[0];if(this.enabled){this.clearCache();var o=U(this.targetAttachment,this.attachment);this.updateAttachClasses(this.attachment,o);var i=this.cache("element-bounds",function(){return a(t.element)}),n=i.width,r=i.height;if(0===n&&0===r&&"undefined"!=typeof this.lastSize){var s=this.lastSize;n=s.width,r=s.height}else this.lastSize={width:n,height:r};var h=this.cache("target-bounds",function(){return t.getTargetBounds()}),d=h,p=C(V(this.attachment),{width:n,height:r}),u=C(V(o),d),c=C(this.offset,{width:n,height:r}),g=C(this.targetOffset,d);p=w(p,c),u=w(u,g);for(var m=h.left+u.left-p.left,v=h.top+u.top-p.top,y=0;y<x.modules.length;++y){var b=x.modules[y],O=b.position.call(this,{left:m,top:v,targetAttachment:o,targetPos:h,elementPos:i,offset:p,targetOffset:u,manualOffset:c,manualTargetOffset:g,scrollbarSize:S,attachment:this.attachment});if(O===!1)return!1;"undefined"!=typeof O&&"object"==typeof O&&(v=O.top,m=O.left)}var E={page:{top:v,left:m},viewport:{top:v-pageYOffset,bottom:pageYOffset-v-r+innerHeight,left:m-pageXOffset,right:pageXOffset-m-n+innerWidth}},A=this.target.ownerDocument,T=A.defaultView,S=void 0;return T.innerHeight>A.documentElement.clientHeight&&(S=this.cache("scrollbar-size",l),E.viewport.bottom-=S.height),T.innerWidth>A.documentElement.clientWidth&&(S=this.cache("scrollbar-size",l),E.viewport.right-=S.width),["","static"].indexOf(A.body.style.position)!==-1&&["","static"].indexOf(A.body.parentElement.style.position)!==-1||(E.page.bottom=A.body.scrollHeight-v-r,E.page.right=A.body.scrollWidth-m-n),"undefined"!=typeof this.options.optimizations&&this.options.optimizations.moveElement!==!1&&"undefined"==typeof this.targetModifier&&!function(){var e=t.cache("target-offsetparent",function(){return f(t.target)}),o=t.cache("target-offsetparent-bounds",function(){return a(e)}),i=getComputedStyle(e),n=o,r={};if(["Top","Left","Bottom","Right"].forEach(function(t){r[t.toLowerCase()]=parseFloat(i["border"+t+"Width"])}),o.right=A.body.scrollWidth-o.left-n.width+r.right,o.bottom=A.body.scrollHeight-o.top-n.height+r.bottom,E.page.top>=o.top+r.top&&E.page.bottom>=o.bottom&&E.page.left>=o.left+r.left&&E.page.right>=o.right){var s=e.scrollTop,l=e.scrollLeft;E.offset={top:E.page.top-o.top+s-r.top,left:E.page.left-o.left+l-r.left}}}(),this.move(E),this.history.unshift(E),this.history.length>3&&this.history.pop(),e&&_(),!0}}},{key:"move",value:function(t){var e=this;if("undefined"!=typeof this.element.parentNode){var o={};for(var i in t){o[i]={};for(var n in t[i]){for(var r=!1,s=0;s<this.history.length;++s){var a=this.history[s];if("undefined"!=typeof a[i]&&!y(a[i][n],t[i][n])){r=!0;break}}r||(o[i][n]=!0)}}var l={top:"",left:"",right:"",bottom:""},d=function(t,o){var i="undefined"!=typeof e.options.optimizations,n=i?e.options.optimizations.gpu:null;if(n!==!1){var r=void 0,s=void 0;if(t.top?(l.top=0,r=o.top):(l.bottom=0,r=-o.bottom),t.left?(l.left=0,s=o.left):(l.right=0,s=-o.right),window.matchMedia){var a=window.matchMedia("only screen and (min-resolution: 1.3dppx)").matches||window.matchMedia("only screen and (-webkit-min-device-pixel-ratio: 1.3)").matches;a||(s=Math.round(s),r=Math.round(r))}l[L]="translateX("+s+"px) translateY("+r+"px)","msTransform"!==L&&(l[L]+=" translateZ(0)")}else t.top?l.top=o.top+"px":l.bottom=o.bottom+"px",t.left?l.left=o.left+"px":l.right=o.right+"px"},p=!1;if((o.page.top||o.page.bottom)&&(o.page.left||o.page.right)?(l.position="absolute",d(o.page,t.page)):(o.viewport.top||o.viewport.bottom)&&(o.viewport.left||o.viewport.right)?(l.position="fixed",d(o.viewport,t.viewport)):"undefined"!=typeof o.offset&&o.offset.top&&o.offset.left?!function(){l.position="absolute";var i=e.cache("target-offsetparent",function(){return f(e.target)});f(e.element)!==i&&k(function(){e.element.parentNode.removeChild(e.element),i.appendChild(e.element)}),d(o.offset,t.offset),p=!0}():(l.position="absolute",d({top:!0,left:!0},t.page)),!p)if(this.options.bodyElement)this.options.bodyElement.appendChild(this.element);else{for(var u=!0,c=this.element.parentNode;c&&1===c.nodeType&&"BODY"!==c.tagName;){if("static"!==getComputedStyle(c).position){u=!1;break}c=c.parentNode}u||(this.element.parentNode.removeChild(this.element),this.element.ownerDocument.body.appendChild(this.element))}var g={},m=!1;for(var n in l){var v=l[n],b=this.element.style[n];b!==v&&(m=!0,g[n]=v)}m&&k(function(){h(e.element.style,g),e.trigger("repositioned")})}}}]),e}(B);I.modules=[],x.position=X;var $=h(I,x),z=function(){function t(t,e){var o=[],i=!0,n=!1,r=void 0;try{for(var s,a=t[Symbol.iterator]();!(i=(s=a.next()).done)&&(o.push(s.value),!e||o.length!==e);i=!0);}catch(f){n=!0,r=f}finally{try{!i&&a["return"]&&a["return"]()}finally{if(n)throw r}}return o}return function(e,o){if(Array.isArray(e))return e;if(Symbol.iterator in Object(e))return t(e,o);throw new TypeError("Invalid attempt to destructure non-iterable instance")}}(),Y=x.Utils,a=Y.getBounds,h=Y.extend,m=Y.updateClasses,k=Y.defer,G=["left","top","right","bottom"];x.modules.push({position:function(t){var e=this,o=t.top,i=t.left,n=t.targetAttachment;if(!this.options.constraints)return!0;var r=this.cache("element-bounds",function(){return a(e.element)}),s=r.height,f=r.width;if(0===f&&0===s&&"undefined"!=typeof this.lastSize){var l=this.lastSize;f=l.width,s=l.height}var d=this.cache("target-bounds",function(){return e.getTargetBounds()}),p=d.height,u=d.width,c=[this.getClass("pinned"),this.getClass("out-of-bounds")];this.options.constraints.forEach(function(t){var e=t.outOfBoundsClass,o=t.pinnedClass;e&&c.push(e),o&&c.push(o)}),c.forEach(function(t){["left","top","right","bottom"].forEach(function(e){c.push(t+"-"+e)})});var g=[],v=h({},n),y=h({},this.attachment);return this.options.constraints.forEach(function(t){var r=t.to,a=t.attachment,l=t.pin;"undefined"==typeof a&&(a="");var h=void 0,d=void 0;if(a.indexOf(" ")>=0){var c=a.split(" "),m=z(c,2);d=m[0],h=m[1]}else h=d=a;var b=O(e,r);"target"!==d&&"both"!==d||(o<b[1]&&"top"===v.top&&(o+=p,v.top="bottom"),o+s>b[3]&&"bottom"===v.top&&(o-=p,v.top="top")),"together"===d&&("top"===v.top&&("bottom"===y.top&&o<b[1]?(o+=p,v.top="bottom",o+=s,y.top="top"):"top"===y.top&&o+s>b[3]&&o-(s-p)>=b[1]&&(o-=s-p,v.top="bottom",y.top="bottom")),"bottom"===v.top&&("top"===y.top&&o+s>b[3]?(o-=p,v.top="top",o-=s,y.top="bottom"):"bottom"===y.top&&o<b[1]&&o+(2*s-p)<=b[3]&&(o+=s-p,v.top="top",y.top="top")),"middle"===v.top&&(o+s>b[3]&&"top"===y.top?(o-=s,y.top="bottom"):o<b[1]&&"bottom"===y.top&&(o+=s,y.top="top"))),"target"!==h&&"both"!==h||(i<b[0]&&"left"===v.left&&(i+=u,v.left="right"),i+f>b[2]&&"right"===v.left&&(i-=u,v.left="left")),"together"===h&&(i<b[0]&&"left"===v.left?"right"===y.left?(i+=u,v.left="right",i+=f,y.left="left"):"left"===y.left&&(i+=u,v.left="right",i-=f,y.left="right"):i+f>b[2]&&"right"===v.left?"left"===y.left?(i-=u,v.left="left",i-=f,y.left="right"):"right"===y.left&&(i-=u,v.left="left",i+=f,y.left="left"):"center"===v.left&&(i+f>b[2]&&"left"===y.left?(i-=f,y.left="right"):i<b[0]&&"right"===y.left&&(i+=f,y.left="left"))),"element"!==d&&"both"!==d||(o<b[1]&&"bottom"===y.top&&(o+=s,y.top="top"),o+s>b[3]&&"top"===y.top&&(o-=s,y.top="bottom")),"element"!==h&&"both"!==h||(i<b[0]&&("right"===y.left?(i+=f,y.left="left"):"center"===y.left&&(i+=f/2,y.left="left")),i+f>b[2]&&("left"===y.left?(i-=f,y.left="right"):"center"===y.left&&(i-=f/2,y.left="right"))),"string"==typeof l?l=l.split(",").map(function(t){return t.trim()}):l===!0&&(l=["top","left","right","bottom"]),l=l||[];var w=[],C=[];o<b[1]&&(l.indexOf("top")>=0?(o=b[1],w.push("top")):C.push("top")),o+s>b[3]&&(l.indexOf("bottom")>=0?(o=b[3]-s,w.push("bottom")):C.push("bottom")),i<b[0]&&(l.indexOf("left")>=0?(i=b[0],w.push("left")):C.push("left")),i+f>b[2]&&(l.indexOf("right")>=0?(i=b[2]-f,w.push("right")):C.push("right")),w.length&&!function(){var t=void 0;t="undefined"!=typeof e.options.pinnedClass?e.options.pinnedClass:e.getClass("pinned"),g.push(t),w.forEach(function(e){g.push(t+"-"+e)})}(),C.length&&!function(){var t=void 0;t="undefined"!=typeof e.options.outOfBoundsClass?e.options.outOfBoundsClass:e.getClass("out-of-bounds"),g.push(t),C.forEach(function(e){g.push(t+"-"+e)})}(),(w.indexOf("left")>=0||w.indexOf("right")>=0)&&(y.left=v.left=!1),(w.indexOf("top")>=0||w.indexOf("bottom")>=0)&&(y.top=v.top=!1),v.top===n.top&&v.left===n.left&&y.top===e.attachment.top&&y.left===e.attachment.left||(e.updateAttachClasses(y,v),e.trigger("update",{attachment:y,targetAttachment:v}))}),k(function(){e.options.addTargetClasses!==!1&&m(e.target,g,c),m(e.element,g,c)}),{top:o,left:i}}});var Y=x.Utils,a=Y.getBounds,m=Y.updateClasses,k=Y.defer;x.modules.push({position:function(t){var e=this,o=t.top,i=t.left,n=this.cache("element-bounds",function(){return a(e.element)}),r=n.height,s=n.width,f=this.getTargetBounds(),l=o+r,h=i+s,d=[];o<=f.bottom&&l>=f.top&&["left","right"].forEach(function(t){var e=f[t];e!==i&&e!==h||d.push(t)}),i<=f.right&&h>=f.left&&["top","bottom"].forEach(function(t){var e=f[t];e!==o&&e!==l||d.push(t)});var p=[],u=[],c=["left","top","right","bottom"];return p.push(this.getClass("abutted")),c.forEach(function(t){p.push(e.getClass("abutted")+"-"+t)}),d.length&&u.push(this.getClass("abutted")),d.forEach(function(t){u.push(e.getClass("abutted")+"-"+t)}),k(function(){e.options.addTargetClasses!==!1&&m(e.target,u,p),m(e.element,u,p)}),!0}});var z=function(){function t(t,e){var o=[],i=!0,n=!1,r=void 0;try{for(var s,a=t[Symbol.iterator]();!(i=(s=a.next()).done)&&(o.push(s.value),!e||o.length!==e);i=!0);}catch(f){n=!0,r=f}finally{try{!i&&a["return"]&&a["return"]()}finally{if(n)throw r}}return o}return function(e,o){if(Array.isArray(e))return e;if(Symbol.iterator in Object(e))return t(e,o);throw new TypeError("Invalid attempt to destructure non-iterable instance")}}();return x.modules.push({position:function(t){var e=t.top,o=t.left;if(this.options.shift){var i=this.options.shift;"function"==typeof this.options.shift&&(i=this.options.shift.call(this,{top:e,left:o}));var n=void 0,r=void 0;if("string"==typeof i){i=i.split(" "),i[1]=i[1]||i[0];var s=i,a=z(s,2);n=a[0],r=a[1],n=parseFloat(n,10),r=parseFloat(r,10)}else n=i.top,r=i.left;return e+=n,o+=r,{top:e,left:o}}}}),$});
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/design/tooltip.html	Tue Jul 18 18:15:51 2017 +0200
@@ -0,0 +1,83 @@
+---
+layout: default
+javascript: |
+  console.log('yolo');
+
+  $(function(){
+    $("#tooltip").popover({
+      placement: 'bottom',
+      title: 'annotation',
+      html: true,
+      content: $('#annotation-control').html()
+    }); 
+  
+  $("#tooltip2").popover({
+      placement: 'bottom',
+      title: 'annotation',
+      html: true,
+      content: $('#annotation-control-2').html()
+    });
+
+  $('.metacategory').change(function(e){
+    console.log(e);
+  });
+
+  });
+---
+
+<div class="container my-3">
+
+<button id="tooltip" type="button" class="btn btn-secondary">Voir tooltip</button>
+
+
+<button id="tooltip2" type="button" class="btn btn-secondary">Voir tooltip (commentaire)</button>
+
+</div>
+
+<div id="annotation-control" class="invisible">
+	<select class="metacategory custom-select mb-2 w-100">
+
+<optgroup label="général">
+{% for meta in site.data.metacategories %}
+		<option value="{{ meta.label  }}">{{ meta.label }}</option>
+{% endfor %}
+</optgroup>
+
+<optgroup label="groupe">
+{% for meta in site.data.metacategories-extra %}
+	<option value="{{ meta.label  }}">{{ meta.label }}</option>
+{% endfor %}
+	</optgroup>
+	</select>
+
+  <textarea rows="3" name="comment-content" id="about" class="comment-content1 form-control input-md" style="display:none;"></textarea>
+
+	<div class="text-right">
+		<button class="btn btn-primary btn-sm mt-1">annoter</button>
+	</div>
+
+</div>
+
+<div id="annotation-control-2" class="invisible">
+	<select class="metacategory custom-select mb-2 w-100">
+
+<optgroup label="général">
+{% for meta in site.data.metacategories %}
+		<option {% if meta.label == "commentaire" %}selected{% endif %} value="{{ meta.label  }}">{{ meta.label }}</option>
+{% endfor %}
+</optgroup>
+
+<optgroup label="groupe">
+{% for meta in site.data.metacategories-extra %}
+	<option value="{{ meta.label  }}">{{ meta.label }}</option>
+{% endfor %}
+	</optgroup>
+	</select>
+
+  <textarea rows="3" name="comment-content" id="about" class="comment-content form-control input-md"></textarea>
+
+	<div class="text-right">
+		<button class="btn btn-primary btn-sm mt-2">annoter</button>
+	</div>
+
+</div>