Added slots and portlets "switchers"
authorThierry Florac <thierry.florac@onf.fr>
Mon, 11 Jun 2018 15:30:26 +0200
changeset 96 43a99de860f2
parent 95 b4e5117061d3
child 97 926d36ad8b8c
Added slots and portlets "switchers"
src/pyams_portal/resources/js/portal.js
src/pyams_portal/resources/js/portal.min.js
src/pyams_portal/zmi/templates/layout.pt
--- a/src/pyams_portal/resources/js/portal.js	Mon Jun 11 15:29:20 2018 +0200
+++ b/src/pyams_portal/resources/js/portal.js	Mon Jun 11 15:30:26 2018 +0200
@@ -231,7 +231,9 @@
 				var new_slot = $('<div></div>').addClass('slot context-menu col col-xs-12 col-sm-12 col-md-12 col-lg-12 resizable')
 											   .attr('data-ams-slot-name', slot_name)
 											   .append($('<div></div>').addClass('header padding-x-5')
-																	   .text(slot_name))
+																	   .append('<i class="fa fa-fw fa-minus-square pull-right padding-top-2" ' +
+																			   '   data-ams-click-handler="PyAMS_portal.template.switchSlot"></i>')
+																	   .append(slot_name))
 											   .append($('<div></div>').addClass('portlets')
 																	   .sortable({
 																			placeholder: 'portlet-highlight',
@@ -374,6 +376,20 @@
 								{order: JSON.stringify(order)});
 			},
 
+			switchSlot: function() {
+				var switcher = $(this);
+				var portlets = switcher.parents('.header').first().siblings('.portlets');
+				if (portlets.hasClass('hidden')) {
+					portlets.removeClass('hidden');
+					switcher.removeClass('fa-plus-square')
+							.addClass('fa-minus-square');
+				} else {
+					portlets.addClass('hidden');
+					switcher.removeClass('fa-minus-square')
+							.addClass('fa-plus-square');
+				}
+			},
+
 			deleteSlot: function() {
 				return function(slot) {
 					MyAMS.skin.bigBox({
@@ -410,7 +426,9 @@
 				var portlet = $('<div></div>').addClass('portlet context-menu')
 											  .attr('data-ams-portlet-id', result.portlet_id)
 											  .append($('<div></div>').addClass('header padding-x-5')
-																	  .text(result.label))
+																	  .append('<i class="fa fa-fw fa-minus-square pull-right padding-top-2" ' +
+																			  '   data-ams-click-handler="PyAMS_portal.template.switchPortlet"></i>')
+																	  .append(result.label))
 											.  append($('<div></div>').addClass('preview')
 																	  .html(result.preview || ''))
 											  .contextMenu({
@@ -493,6 +511,20 @@
 								{order: JSON.stringify(order)});
 			},
 
+			switchPortlet: function() {
+				var switcher = $(this);
+				var portlet = switcher.parents('.header').first().siblings('.preview');
+				if (portlet.hasClass('hidden')) {
+					portlet.removeClass('hidden');
+					switcher.removeClass('fa-plus-square')
+							.addClass('fa-minus-square');
+				} else {
+					portlet.addClass('hidden');
+					switcher.removeClass('fa-minus-square')
+							.addClass('fa-plus-square');
+				}
+			},
+
 			deletePortlet: function() {
 				return function(portlet) {
 					MyAMS.skin.bigBox({
--- a/src/pyams_portal/resources/js/portal.min.js	Mon Jun 11 15:29:20 2018 +0200
+++ b/src/pyams_portal/resources/js/portal.min.js	Mon Jun 11 15:30:26 2018 +0200
@@ -1,1 +1,1 @@
-!function(t,e){"use strict";var a=e.MyAMS,o={template:{initConfig:function(){var e=t("#portal_config");e.data("ams-allowed-change")&&(t(".rows",e).addClass("sortable"),t(".slots",e).addClass("sortable"),t(".slot",e).addClass("resizable"),t(".portlets",e).addClass("sortable"),a.plugins.enabled.sortable(e),a.plugins.enabled.resizable(e),t(".btn-row",".btn-toolbar").draggable({cursor:"move",helper:"clone",revert:"invalid",connectToSortable:".rows"}),t(".rows",e).droppable({accept:".btn-row",drop:o.template.dropRowButton}),t(".btn-slot",".btn-toolbar").draggable({cursor:"move",helper:"clone",revert:"invalid",connectToSortable:".slots"}),t(".slots",e).droppable({accept:".btn-slot",drop:o.template.dropSlotButton}),t(".btn-portlet",".btn-toolbar").draggable({cursor:"move",helper:"clone",revert:"invalid",connectToSortable:".portlets"}),t(".portlets",e).droppable({accept:".btn-portlet",hoverClass:"portlets-hover",activeClass:"portlets-active",drop:o.template.dropPortletButton}))},selectDisplay:function(){var e=t(this).val();a.ajax.post("get-slots-width.json",{device:e},function(a){var o=t("#portal_config");o.removeClassPrefix("container-"),e&&o.addClass("container-"+e),t(".slot",o).removeClassPrefix("col-");for(var s in a)if(a.hasOwnProperty(s)){var l=a[s],r=t('.slot[data-ams-slot-name="'+s+'"]',o);if(e)r.addClass("col-"+l[e]);else for(var n in l)l.hasOwnProperty(n)&&r.addClass("col-"+n+"-"+l[n])}})},addRow:function(){return function(){t(this).parents(".btn-group").removeClass("open"),a.ajax.post("add-template-row.json",{},function(e){var s=e.row_id,l=t(".rows","#portal_config");t("<div></div>").addClass("row context-menu").attr("data-ams-row-id",s).append(t("<span></span>").addClass("row_id label label-success pull-right").text(s)).append(t("<div></div>").addClass("slots").sortable({placeholder:"slot-highlight",connectWith:".slots",over:o.template.overSlots,stop:o.template.sortSlots}).droppable({accept:".btn-slot",drop:o.template.dropSlotButton})).contextMenu({menuSelector:"#rowMenu",menuSelected:a.helpers.contextMenuHandler}).appendTo(l),l.sortable("refresh")})}},dropRowButton:function(e,s){s.draggable.hasClass("already-dropped")||(s.draggable.addClass("already-dropped"),a.ajax.post("add-template-row.json",{},function(e){var l=e.row_id,r=t(".rows","#portal_config");s.draggable.removeClassPrefix("btn").removeClassPrefix("ui-").removeClass("already-dropped").removeAttr("style").addClass("row context-menu").attr("data-ams-row-id",l).empty().append(t("<span></span>").addClass("row_id label label-success pull-right").text(l)).append(t("<div></div>").addClass("slots").sortable({placeholder:"slot-highlight",connectWith:".slots",over:o.template.overSlots,stop:o.template.sortSlots}).droppable({accept:".btn-slot",drop:o.template.dropSlotButton})).contextMenu({menuSelector:"#rowMenu",menuSelected:a.helpers.contextMenuHandler}),o.template.sortRows(),r.sortable("refresh")}))},overRows:function(e,a){t(a.placeholder).attr("class",t(a.item).attr("class")).removeClassPrefix("ui-").addClass("row-highlight").css("height",t(a.item).outerHeight())},sortRows:function(e,o){if(!o||!o.item.hasClass("already-dropped")){var s=t("#portal_config"),l=t(".row",s).listattr("data-ams-row-id");a.ajax.post("set-template-row-order.json",{rows:JSON.stringify(l)},function(e){"success"===e.status&&t(".row",s).each(function(e){t(this).attr("data-ams-row-id",e),t("span.row_id",t(this)).text(e)})})}},deleteRow:function(){return function(e){a.skin.bigBox({title:a.i18n.WARNING,content:'<i class="text-danger fa fa-2x fa-bell shake animated"></i>&nbsp; '+a.i18n.DELETE_WARNING,buttons:a.i18n.BTN_OK_CANCEL},function(o){o===a.i18n.BTN_OK&&(e.hasClass("row")||(e=e.parents(".row")),a.ajax.post("delete-template-row.json",{row_id:e.data("ams-row-id")},function(a){"success"===a.status&&(e.remove(),t(".row","#portal_config").each(function(e){t(this).removeData().attr("data-ams-row-id",e),t("span.row_id",t(this)).text(e)}))}))})}},addSlotCallback:function(e){var s=t(".slots",'.row[data-ams-row-id="'+e.row_id+'"]'),l=e.slot_name,r=t("<div></div>").addClass("slot context-menu col col-xs-12 col-sm-12 col-md-12 col-lg-12 resizable").attr("data-ams-slot-name",l).append(t("<div></div>").addClass("header padding-x-5").text(l)).append(t("<div></div>").addClass("portlets").sortable({placeholder:"portlet-highlight",connectWith:".portlets",over:o.template.overPortlets,stop:o.template.sortPortlets}).droppable({accept:".btn-portlet",hoverClass:"portlets-hover",activeClass:"portlets-active",drop:o.template.dropPortletButton})).append(t("<div></div>").addClass("clearfix")).contextMenu({menuSelector:"#slotMenu",menuSelected:a.helpers.contextMenuHandler}),n=t(".btn-slot",s);n.exists()?(n.replaceWith(r),t(".slot",s).each(function(){t(this).removeData()}),o.template.sortSlots()):r.appendTo(s),r.resizable({start:o.template.startSlotResize,stop:o.template.stopSlotResize,handles:"e"}),s.sortable("refresh")},dropSlotButton:function(t,e){if(!e.draggable.hasClass("already-dropped")){e.draggable.addClass("already-dropped");var o=e.helper.parents(".row:first").data("ams-row-id");a.dialog.open("add-template-slot.html?add_form.widgets.row_id="+o)}},startSlotResize:function(t,e){var a=e.element,o=a.parents(".slots:first"),s=(o.innerWidth()-110)/12,l=a.height();e.element.resizable("option","grid",[s,l]),e.element.resizable("option","minWidth",s),e.element.resizable("option","minHeight",l),e.element.resizable("option","maxWidth",o.innerWidth()),e.element.resizable("option","maxHeight",l)},stopSlotResize:function(e,o){var s=o.element,l=(s.parents(".slots:first").innerWidth()-10)/12,r=Math.round(t(s).width()/l),n=t("#device_selector").val();if(!n){var i=t("body").width();n=i>1170?"lg":i>970?"md":i>750?"sm":"xs"}a.ajax.post("set-slot-width.json",{slot_name:s.data("ams-slot-name"),device:n,width:r},function(t){s.removeClassPrefix("col-"),s.removeAttr("style");var e=t[s.data("ams-slot-name")];n?s.addClass("col-"+n+"-"+e[n]):s.addClass("col-"+e[n])})},editSlot:function(){return function(t){t.hasClass("slot")||(t=t.parents(".slot")),a.dialog.open("slot-properties.html?slot.widgets.slot_name="+t.data("ams-slot-name"))}},editSlotCallback:function(e){var a=t('.slot[data-ams-slot-name="'+e.slot_name+'"]');a.attr("class","slot context-menu col");var o=t("#device_selector").val();if(o)a.addClass("col-"+e.width[o]);else for(o in e.width)e.width.hasOwnProperty(o)&&a.addClass("col-"+o+"-"+e.width[o])},overSlots:function(e,a){t(a.placeholder).attr("class",t(a.item).attr("class")).removeClassPrefix("ui-").addClass("slot-highlight").css("height",t(a.item).outerHeight())},sortSlots:function(e,o){if(!o||!o.item.hasClass("already-dropped")){var s=t("#portal_config"),l={};t(".row",s).each(function(){var e=t(this),a=[];t(".slot",e).each(function(){a.push(t(this).data("ams-slot-name"))}),l[parseInt(e.attr("data-ams-row-id"))]=a}),a.ajax.post("set-template-slot-order.json",{order:JSON.stringify(l)})}},deleteSlot:function(){return function(e){a.skin.bigBox({title:a.i18n.WARNING,content:'<i class="text-danger fa fa-2x fa-bell shake animated"></i>&nbsp; '+a.i18n.DELETE_WARNING,buttons:a.i18n.BTN_OK_CANCEL},function(o){o===a.i18n.BTN_OK&&(e.hasClass("slot")||(e=e.parents(".slot")),a.ajax.post("delete-template-slot.json",{slot_name:e.data("ams-slot-name")},function(a){"success"===a.status&&(e.remove(),t(".slot","#portal_config").each(function(){t(this).removeData()}))}))})}},addPortletCallback:function(e){var s=t(".portlets",'.slot[data-ams-slot-name="'+e.slot_name+'"]'),l=t("<div></div>").addClass("portlet context-menu").attr("data-ams-portlet-id",e.portlet_id).append(t("<div></div>").addClass("header padding-x-5").text(e.label)).append(t("<div></div>").addClass("preview").html(e.preview||"")).contextMenu({menuSelector:"#portletMenu",menuSelected:a.helpers.contextMenuHandler});a.initContent(t(".preview",l));var r=t(".btn-portlet",s);r.exists()?(r.replaceWith(l),t(".portlet",s).each(function(){t(this).removeData()}),o.template.sortPortlets(null,{item:l})):l.appendTo(s),s.sortable("refresh"),a.dialog.open("portlet-properties.html?portlet.widgets.portlet_id="+e.portlet_id)},dropPortletButton:function(e,o){if(!o.draggable.hasClass("already-dropped")){o.draggable.addClass("already-dropped");var s=o.draggable,l=t(this).parents(".slot:first");a.ajax.post("drag-template-portlet.json",{portlet_name:s.data("ams-portlet-name"),slot_name:l.data("ams-slot-name")},function(t){a.ajax.handleJSON(t)})}},editPortlet:function(){return function(t){t.hasClass("portlet")||(t=t.parents(".portlet:first")),a.dialog.open("portlet-properties.html?portlet.widgets.portlet_id="+t.data("ams-portlet-id"))}},editPortletCallback:function(e){if(e.preview){var o=t("#portal_config"),s=t('.portlet[data-ams-portlet-id="'+e.portlet_id+'"]',o),l=t(".header",s);e.inherit_parent?t("i",l).removeClass("fa-chain-broken"):t("i",l).addClass("fa-chain-broken"),t(".preview",s).html(e.preview),a.initContent(t(".preview",s))}},overPortlets:function(e,a){t(a.placeholder).attr("class",t(a.item).attr("class")).removeClassPrefix("ui-").addClass("portlet-highlight").css("height",t(a.item).outerHeight())},sortPortlets:function(e,o){if(!o.item.hasClass("already-dropped")){var s=o.item,l=s.parents(".slot"),r=t(".portlet",l),n={from:s.data("ams-portlet-id"),to:{slot:l.data("ams-slot-name"),portlet_ids:r.listattr("data-ams-portlet-id")}};a.ajax.post("set-template-portlet-order.json",{order:JSON.stringify(n)})}},deletePortlet:function(){return function(e){a.skin.bigBox({title:a.i18n.WARNING,content:'<i class="text-danger fa fa-2x fa-bell shake animated"></i>&nbsp; '+a.i18n.DELETE_WARNING,buttons:a.i18n.BTN_OK_CANCEL},function(o){o===a.i18n.BTN_OK&&(e.hasClass("portlet")||(e=e.parents(".portlet")),a.ajax.post("delete-template-portlet.json",{portlet_id:e.data("ams-portlet-id")},function(a){"success"===a.status&&(e.remove(),t(".portlet","#portal_config").each(function(){t(this).removeData()}))}))})}}}};e.PyAMS_portal=o}(jQuery,this);
+!function(t,e){"use strict";var a=e.MyAMS,s={template:{initConfig:function(){var e=t("#portal_config");e.data("ams-allowed-change")&&(t(".rows",e).addClass("sortable"),t(".slots",e).addClass("sortable"),t(".slot",e).addClass("resizable"),t(".portlets",e).addClass("sortable"),a.plugins.enabled.sortable(e),a.plugins.enabled.resizable(e),t(".btn-row",".btn-toolbar").draggable({cursor:"move",helper:"clone",revert:"invalid",connectToSortable:".rows"}),t(".rows",e).droppable({accept:".btn-row",drop:s.template.dropRowButton}),t(".btn-slot",".btn-toolbar").draggable({cursor:"move",helper:"clone",revert:"invalid",connectToSortable:".slots"}),t(".slots",e).droppable({accept:".btn-slot",drop:s.template.dropSlotButton}),t(".btn-portlet",".btn-toolbar").draggable({cursor:"move",helper:"clone",revert:"invalid",connectToSortable:".portlets"}),t(".portlets",e).droppable({accept:".btn-portlet",hoverClass:"portlets-hover",activeClass:"portlets-active",drop:s.template.dropPortletButton}))},selectDisplay:function(){var e=t(this).val();a.ajax.post("get-slots-width.json",{device:e},function(a){var s=t("#portal_config");s.removeClassPrefix("container-"),e&&s.addClass("container-"+e),t(".slot",s).removeClassPrefix("col-");for(var o in a)if(a.hasOwnProperty(o)){var l=a[o],r=t('.slot[data-ams-slot-name="'+o+'"]',s);if(e)r.addClass("col-"+l[e]);else for(var n in l)l.hasOwnProperty(n)&&r.addClass("col-"+n+"-"+l[n])}})},addRow:function(){return function(){t(this).parents(".btn-group").removeClass("open"),a.ajax.post("add-template-row.json",{},function(e){var o=e.row_id,l=t(".rows","#portal_config");t("<div></div>").addClass("row context-menu").attr("data-ams-row-id",o).append(t("<span></span>").addClass("row_id label label-success pull-right").text(o)).append(t("<div></div>").addClass("slots").sortable({placeholder:"slot-highlight",connectWith:".slots",over:s.template.overSlots,stop:s.template.sortSlots}).droppable({accept:".btn-slot",drop:s.template.dropSlotButton})).contextMenu({menuSelector:"#rowMenu",menuSelected:a.helpers.contextMenuHandler}).appendTo(l),l.sortable("refresh")})}},dropRowButton:function(e,o){o.draggable.hasClass("already-dropped")||(o.draggable.addClass("already-dropped"),a.ajax.post("add-template-row.json",{},function(e){var l=e.row_id,r=t(".rows","#portal_config");o.draggable.removeClassPrefix("btn").removeClassPrefix("ui-").removeClass("already-dropped").removeAttr("style").addClass("row context-menu").attr("data-ams-row-id",l).empty().append(t("<span></span>").addClass("row_id label label-success pull-right").text(l)).append(t("<div></div>").addClass("slots").sortable({placeholder:"slot-highlight",connectWith:".slots",over:s.template.overSlots,stop:s.template.sortSlots}).droppable({accept:".btn-slot",drop:s.template.dropSlotButton})).contextMenu({menuSelector:"#rowMenu",menuSelected:a.helpers.contextMenuHandler}),s.template.sortRows(),r.sortable("refresh")}))},overRows:function(e,a){t(a.placeholder).attr("class",t(a.item).attr("class")).removeClassPrefix("ui-").addClass("row-highlight").css("height",t(a.item).outerHeight())},sortRows:function(e,s){if(!s||!s.item.hasClass("already-dropped")){var o=t("#portal_config"),l=t(".row",o).listattr("data-ams-row-id");a.ajax.post("set-template-row-order.json",{rows:JSON.stringify(l)},function(e){"success"===e.status&&t(".row",o).each(function(e){t(this).attr("data-ams-row-id",e),t("span.row_id",t(this)).text(e)})})}},deleteRow:function(){return function(e){a.skin.bigBox({title:a.i18n.WARNING,content:'<i class="text-danger fa fa-2x fa-bell shake animated"></i>&nbsp; '+a.i18n.DELETE_WARNING,buttons:a.i18n.BTN_OK_CANCEL},function(s){s===a.i18n.BTN_OK&&(e.hasClass("row")||(e=e.parents(".row")),a.ajax.post("delete-template-row.json",{row_id:e.data("ams-row-id")},function(a){"success"===a.status&&(e.remove(),t(".row","#portal_config").each(function(e){t(this).removeData().attr("data-ams-row-id",e),t("span.row_id",t(this)).text(e)}))}))})}},addSlotCallback:function(e){var o=t(".slots",'.row[data-ams-row-id="'+e.row_id+'"]'),l=e.slot_name,r=t("<div></div>").addClass("slot context-menu col col-xs-12 col-sm-12 col-md-12 col-lg-12 resizable").attr("data-ams-slot-name",l).append(t("<div></div>").addClass("header padding-x-5").append('<i class="fa fa-fw fa-minus-square pull-right padding-top-2"    data-ams-click-handler="PyAMS_portal.template.switchSlot"></i>').append(l)).append(t("<div></div>").addClass("portlets").sortable({placeholder:"portlet-highlight",connectWith:".portlets",over:s.template.overPortlets,stop:s.template.sortPortlets}).droppable({accept:".btn-portlet",hoverClass:"portlets-hover",activeClass:"portlets-active",drop:s.template.dropPortletButton})).append(t("<div></div>").addClass("clearfix")).contextMenu({menuSelector:"#slotMenu",menuSelected:a.helpers.contextMenuHandler}),n=t(".btn-slot",o);n.exists()?(n.replaceWith(r),t(".slot",o).each(function(){t(this).removeData()}),s.template.sortSlots()):r.appendTo(o),r.resizable({start:s.template.startSlotResize,stop:s.template.stopSlotResize,handles:"e"}),o.sortable("refresh")},dropSlotButton:function(t,e){if(!e.draggable.hasClass("already-dropped")){e.draggable.addClass("already-dropped");var s=e.helper.parents(".row:first").data("ams-row-id");a.dialog.open("add-template-slot.html?add_form.widgets.row_id="+s)}},startSlotResize:function(t,e){var a=e.element,s=a.parents(".slots:first"),o=(s.innerWidth()-110)/12,l=a.height();e.element.resizable("option","grid",[o,l]),e.element.resizable("option","minWidth",o),e.element.resizable("option","minHeight",l),e.element.resizable("option","maxWidth",s.innerWidth()),e.element.resizable("option","maxHeight",l)},stopSlotResize:function(e,s){var o=s.element,l=(o.parents(".slots:first").innerWidth()-10)/12,r=Math.round(t(o).width()/l),n=t("#device_selector").val();if(!n){var i=t("body").width();n=i>1170?"lg":i>970?"md":i>750?"sm":"xs"}a.ajax.post("set-slot-width.json",{slot_name:o.data("ams-slot-name"),device:n,width:r},function(t){o.removeClassPrefix("col-"),o.removeAttr("style");var e=t[o.data("ams-slot-name")];n?o.addClass("col-"+n+"-"+e[n]):o.addClass("col-"+e[n])})},editSlot:function(){return function(t){t.hasClass("slot")||(t=t.parents(".slot")),a.dialog.open("slot-properties.html?slot.widgets.slot_name="+t.data("ams-slot-name"))}},editSlotCallback:function(e){var a=t('.slot[data-ams-slot-name="'+e.slot_name+'"]');a.attr("class","slot context-menu col");var s=t("#device_selector").val();if(s)a.addClass("col-"+e.width[s]);else for(s in e.width)e.width.hasOwnProperty(s)&&a.addClass("col-"+s+"-"+e.width[s])},overSlots:function(e,a){t(a.placeholder).attr("class",t(a.item).attr("class")).removeClassPrefix("ui-").addClass("slot-highlight").css("height",t(a.item).outerHeight())},sortSlots:function(e,s){if(!s||!s.item.hasClass("already-dropped")){var o=t("#portal_config"),l={};t(".row",o).each(function(){var e=t(this),a=[];t(".slot",e).each(function(){a.push(t(this).data("ams-slot-name"))}),l[parseInt(e.attr("data-ams-row-id"))]=a}),a.ajax.post("set-template-slot-order.json",{order:JSON.stringify(l)})}},switchSlot:function(){var e=t(this),a=e.parents(".header").first().siblings(".portlets");a.hasClass("hidden")?(a.removeClass("hidden"),e.removeClass("fa-plus-square").addClass("fa-minus-square")):(a.addClass("hidden"),e.removeClass("fa-minus-square").addClass("fa-plus-square"))},deleteSlot:function(){return function(e){a.skin.bigBox({title:a.i18n.WARNING,content:'<i class="text-danger fa fa-2x fa-bell shake animated"></i>&nbsp; '+a.i18n.DELETE_WARNING,buttons:a.i18n.BTN_OK_CANCEL},function(s){s===a.i18n.BTN_OK&&(e.hasClass("slot")||(e=e.parents(".slot")),a.ajax.post("delete-template-slot.json",{slot_name:e.data("ams-slot-name")},function(a){"success"===a.status&&(e.remove(),t(".slot","#portal_config").each(function(){t(this).removeData()}))}))})}},addPortletCallback:function(e){var o=t(".portlets",'.slot[data-ams-slot-name="'+e.slot_name+'"]'),l=t("<div></div>").addClass("portlet context-menu").attr("data-ams-portlet-id",e.portlet_id).append(t("<div></div>").addClass("header padding-x-5").append('<i class="fa fa-fw fa-minus-square pull-right padding-top-2"    data-ams-click-handler="PyAMS_portal.template.switchPortlet"></i>').append(e.label)).append(t("<div></div>").addClass("preview").html(e.preview||"")).contextMenu({menuSelector:"#portletMenu",menuSelected:a.helpers.contextMenuHandler});a.initContent(t(".preview",l));var r=t(".btn-portlet",o);r.exists()?(r.replaceWith(l),t(".portlet",o).each(function(){t(this).removeData()}),s.template.sortPortlets(null,{item:l})):l.appendTo(o),o.sortable("refresh"),a.dialog.open("portlet-properties.html?portlet.widgets.portlet_id="+e.portlet_id)},dropPortletButton:function(e,s){if(!s.draggable.hasClass("already-dropped")){s.draggable.addClass("already-dropped");var o=s.draggable,l=t(this).parents(".slot:first");a.ajax.post("drag-template-portlet.json",{portlet_name:o.data("ams-portlet-name"),slot_name:l.data("ams-slot-name")},function(t){a.ajax.handleJSON(t)})}},editPortlet:function(){return function(t){t.hasClass("portlet")||(t=t.parents(".portlet:first")),a.dialog.open("portlet-properties.html?portlet.widgets.portlet_id="+t.data("ams-portlet-id"))}},editPortletCallback:function(e){if(e.preview){var s=t("#portal_config"),o=t('.portlet[data-ams-portlet-id="'+e.portlet_id+'"]',s),l=t(".header",o);e.inherit_parent?t("i",l).removeClass("fa-chain-broken"):t("i",l).addClass("fa-chain-broken"),t(".preview",o).html(e.preview),a.initContent(t(".preview",o))}},overPortlets:function(e,a){t(a.placeholder).attr("class",t(a.item).attr("class")).removeClassPrefix("ui-").addClass("portlet-highlight").css("height",t(a.item).outerHeight())},sortPortlets:function(e,s){if(!s.item.hasClass("already-dropped")){var o=s.item,l=o.parents(".slot"),r=t(".portlet",l),n={from:o.data("ams-portlet-id"),to:{slot:l.data("ams-slot-name"),portlet_ids:r.listattr("data-ams-portlet-id")}};a.ajax.post("set-template-portlet-order.json",{order:JSON.stringify(n)})}},switchPortlet:function(){var e=t(this),a=e.parents(".header").first().siblings(".preview");a.hasClass("hidden")?(a.removeClass("hidden"),e.removeClass("fa-plus-square").addClass("fa-minus-square")):(a.addClass("hidden"),e.removeClass("fa-minus-square").addClass("fa-plus-square"))},deletePortlet:function(){return function(e){a.skin.bigBox({title:a.i18n.WARNING,content:'<i class="text-danger fa fa-2x fa-bell shake animated"></i>&nbsp; '+a.i18n.DELETE_WARNING,buttons:a.i18n.BTN_OK_CANCEL},function(s){s===a.i18n.BTN_OK&&(e.hasClass("portlet")||(e=e.parents(".portlet")),a.ajax.post("delete-template-portlet.json",{portlet_id:e.data("ams-portlet-id")},function(a){"success"===a.status&&(e.remove(),t(".portlet","#portal_config").each(function(){t(this).removeData()}))}))})}}}};e.PyAMS_portal=s}(jQuery,this);
--- a/src/pyams_portal/zmi/templates/layout.pt	Mon Jun 11 15:29:20 2018 +0200
+++ b/src/pyams_portal/zmi/templates/layout.pt	Mon Jun 11 15:30:26 2018 +0200
@@ -20,12 +20,14 @@
 			<div class="btn-toolbar" role="toolbar"
 				 tal:condition="can_change">
 				<div class="btn-group" role="group">
-					<div class="btn btn-default btn-row hint" title="Add row" i18n:attributes="title"
-						 data-ams-hint-gravity="n">
+					<div class="btn btn-default btn-row hint"
+						 title="Add row<br />Drag and drop button to page template to position new row" i18n:attributes="title"
+						 data-ams-hint-gravity="n" data-ams-hint-html="true">
 						<i class="fa fa-fw fa-2x fa-indent"></i>
 					</div>
-					<div class="btn btn-default btn-slot hint" title="Add slot" i18n:attributes="title"
-						 data-ams-hint-gravity="n">
+					<div class="btn btn-default btn-slot hint"
+						 title="Add slot<br />Drag and drop button to page template to position new slot" i18n:attributes="title"
+						 data-ams-hint-gravity="n" data-ams-hint-html="true">
 						<i class="fa fa-fw fa-2x fa-columns"></i>
 					</div>
 				</div>
@@ -91,8 +93,10 @@
 								 tal:repeat="slot_name template_config.get_slots(row)"
 								 tal:attributes="class string:slot context-menu col ${template_config.get_slot_configuration(slot_name).get_css_class()};
 												 data-ams-slot-name slot_name;">
-								<div class="header padding-x-5"
-									 tal:content="slot_name"></div>
+								<div class="header padding-x-5">
+									<i class="fa fa-fw fa-minus-square pull-right padding-top-2" data-ams-click-handler="PyAMS_portal.template.switchSlot"></i>
+									<tal:var content="slot_name" />
+								</div>
 								<div class="portlets"
 									 data-ams-sortable-placeholder="portlet-highlight"
 									 data-ams-sortable-connectwith=".portlets"
@@ -105,6 +109,7 @@
 										<div class="header padding-x-5"
 											 tal:define="current_config portlet_config.get_portlet_configuration(portlet_id);
 														 portlet_name current_config.portlet_name;">
+											<i class="fa fa-fw fa-minus-square pull-right padding-top-2" data-ams-click-handler="PyAMS_portal.template.switchPortlet"></i>
 											<tal:var content="view.get_portlet_label(portlet_name)" />
 											<tal:if condition="current_config.can_inherit">
 												<i title="Override parent or template settings" i18n:attributes="title"