# HG changeset patch # User Thierry Florac # Date 1511687661 -3600 # Node ID 79635dd71cca637f907eedb4406e29e3d9759943 # Parent 4b5ae98a90b136e33ca64005e35da9184c74d082 Added treeview plug-in and tree management features diff -r 4b5ae98a90b1 -r 79635dd71cca src/pyams_skin/resources/js/myams.js --- a/src/pyams_skin/resources/js/myams.js Sun Nov 26 10:09:52 2017 +0100 +++ b/src/pyams_skin/resources/js/myams.js Sun Nov 26 10:14:21 2017 +0100 @@ -2,7 +2,7 @@ * MyAMS * « My Application Management Skin » * - * $Tag$ (rev. 1) + * $Tag: 0.1.11 $ (rev. 1) * A bootstrap based application/administration skin * * Custom administration and application skin tools @@ -3205,6 +3205,69 @@ }, /** + * Treeview plug-in + */ + treeview: function(element) { + var treeviews = $('.treeview', element); + if (treeviews.length > 0) { + ams.ajax.check($.fn.treview, + ams.baseURL + 'ext/bootstrap-treeview' + ams.devext + '.js', + function(first_load) { + if (first_load) { + ams.getCSS(ams.baseURL + '../css/ext/bootstrap-treeview' + ams.devext + '.css', 'bootstrap-treeview'); + } + treeviews.each(function() { + var treeview = $(this); + var data = treeview.data(); + var dataOptions = { + data: data.amsTreeviewData, + levels: data.amsTreeviewLevels, + injectStyle: data.amsTreeviewInjectStyle, + expandIcon: data.amsTreeviewExpandIcon || 'fa fa-fw fa-plus-square-o', + collapseIcon: data.amsTreeviewCollaspeIcon || 'fa fa-fw fa-minus-square-o', + emptyIcon: data.amsTreeviewEmptyIcon || 'fa fa-fw', + nodeIcon: data.amsTreeviewNodeIcon, + selectedIcon: data.amsTreeviewSelectedIcon, + checkedIcon: data.amsTreeviewCheckedIcon || 'fa fa-fw fa-check-square-o', + uncheckedIcon: data.amsTreeviewUncheckedIcon || 'fa fa-fw fa-square-o', + color: data.amsTreeviewColor, + backColor: data.amsTreeviewBackColor, + borderColor: data.amsTreeviewBorderColor, + onHoverColor: data.amsTreeviewHoverColor, + selectedColor: data.amsTreeviewSelectedColor, + selectedBackColor: data.amsTreeviewSelectedBackColor, + unselectableColor: data.amsTreeviewUnselectableColor || 'rgba(1,1,1,0.25)', + unselectableBackColor: data.amsTreeviewUnselectableBackColor || 'rgba(1,1,1,0.25)', + enableLinks: data.amsTreeviewEnableLinks, + highlightSelected: data.amsTreeviewHighlightSelected, + highlightSearchResults: data.amsTreeviewhighlightSearchResults, + showBorder: data.amsTreeviewShowBorder, + showIcon: data.amsTreeviewShowIcon, + showCheckbox: data.amsTreeviewShowCheckbox, + showTags: data.amsTreeviewShowTags, + toggleUnselectable: data.amsTreeviewToggleUnselectable, + multiSelect: data.amsTreeviewMultiSelect, + onNodeChecked: ams.getFunctionByName(data.amsTreeviewNodeChecked), + onNodeCollapsed: ams.getFunctionByName(data.amsTreeviewNodeCollapsed), + onNodeDisabled: ams.getFunctionByName(data.amsTreeviewNodeDisabled), + onNodeEnabled: ams.getFunctionByName(data.amsTreeviewNodeEnabled), + onNodeExpanded: ams.getFunctionByName(data.amsTreeviewNodeExpanded), + onNodeSelected: ams.getFunctionByName(data.amsTreeviewNodeSelected), + onNodeUnchecked: ams.getFunctionByName(data.amsTreeviewNodeUnchecked), + onNodeUnselected: ams.getFunctionByName(data.amsTreeviewNodeUnselected), + onSearchComplete: ams.getFunctionByName(data.amsTreeviewSearchComplete), + onSearchCleared: ams.getFunctionByName(data.amsTreeviewSearchCleared) + }; + var settings = $.extend({}, dataOptions, data.amsTreeviewOptions); + settings = ams.executeFunctionByName(data.amsTreeviewInitcallback, treeview, settings) || settings; + var plugin = treeview.treeview(settings); + ams.executeFunctionByName(data.amsTreeviewAfterInitCallback, treeview, plugin, settings); + }); + }); + } + }, + + /** * Select2 plug-in */ select2: function(element) { @@ -3970,29 +4033,32 @@ if (target) { // Disable row click handler $(row).data('ams-disabled-handlers', 'click'); - var rows = []; - $(dnd_table.rows).each(function() { - var rowId = $(this).data('ams-element-name'); - if (rowId) { - rows.push(rowId); + try { + var rows = []; + $(dnd_table.rows).each(function() { + var rowId = $(this).data('ams-element-name'); + if (rowId) { + rows.push(rowId); + } + }); + var localTarget = ams.getFunctionByName(target); + if (typeof(localTarget) === 'function') { + localTarget.call(table, dnd_table, rows); + } else { + if (!target.startsWith(window.location.protocol)) { + var location = data.amsLocation; + if (location) { + target = location + '/' + target; + } + } + ams.ajax.post(target, {names: JSON.stringify(rows)}); } - }); - var localTarget = ams.getFunctionByName(target); - if (typeof(localTarget) === 'function') { - localTarget.call(table, dnd_table, rows); - } else { - if (!target.startsWith(window.location.protocol)) { - var location = data.amsLocation; - if (location) { - target = location + '/' + target; - } - } - ams.ajax.post(target, {names: JSON.stringify(rows)}); + } finally { + // Restore row click handler + setTimeout(function() { + $(row).removeData('ams-disabled-handlers'); + }, 50); } - // Restore row click handler - setTimeout(function() { - $(row).removeData('ams-disabled-handlers'); - }, 50); } return false; } @@ -4552,9 +4618,9 @@ buttons: ams.i18n.BTN_OK_CANCEL }, function(button) { if (button === ams.i18n.BTN_OK) { - var table = link.parents('table').first(); - var location = table.data('ams-location') || ''; var tr = link.parents('tr').first(); + var table = tr.parents('table').first(); + var location = tr.data('ams-location') || table.data('ams-location') || ''; var deleteTarget = tr.data('ams-delete-target') || table.data('ams-delete-target') || 'delete-element.json'; var objectName = tr.data('ams-element-name'); MyAMS.ajax.post(location + '/' + deleteTarget, {'object_name': objectName}, function(result, status) { @@ -4579,6 +4645,226 @@ /** + * Tree management + */ + MyAMS.tree = { + + /** + * Open close tree node inside a table + */ + switchTableNode: function() { + + function removeChildNodes(node_id) { + $('tr[data-ams-tree-node-parent-id="' + node_id + '"]').each(function() { + var row = $(this); + removeChildNodes(row.data('ams-tree-node-id')); + row.remove(); + }) + } + + var node = $(this); + var switcher = $('i.switch', node); + var tr = node.parents('tr').first(); + var table = tr.parents('table').first(); + if (switcher.hasClass('fa-minus-square-o')) { + removeChildNodes(tr.data('ams-tree-node-id')); + switcher.removeClass('fa-minus-square-o') + .addClass('fa-plus-square-o'); + } else { + var location = tr.data('ams-location') || table.data('ams-location') || ''; + var treeNodesTarget = tr.data('ams-tree-nodes-target') || table.data('ams-tree-nodes-target') || 'get-tree-nodes.json'; + var sourceName = tr.data('ams-element-name'); + switcher.removeClass('fa-plus-square-o') + .addClass('fa-cog fa-spin'); + MyAMS.ajax.post(location + '/' + sourceName + '/' + treeNodesTarget, { + can_sort: !$('td.sorter', tr).is(':empty') + }, function(result, status) { + if (result.length > 0) { + var old_row = tr; + for (var index = 0; index < result.length; index++) { + var new_row = $(result[index]); + new_row.insertAfter(old_row) + .addClass('no-drag-handle'); + ams.initContent(new_row); + old_row = new_row; + } + if (table.hasClass('table-dnd')) { + table.tableDnDUpdate(); + } + } + switcher.removeClass('fa-cog fa-spin') + .addClass('fa-minus-square-o'); + }); + } + }, + + /** + * Open close all tree nodes + */ + switchTree: function() { + var th = $(this); + var switcher = $('i.switch', th); + var table = $(this).parents('table').first(); + var tableID = table.data('ams-tree-node-id'); + if (switcher.hasClass('fa-minus-square-o')) { + $('tr[data-ams-tree-node-parent-id]').filter('tr[data-ams-tree-node-parent-id!="' + tableID + '"]').remove(); + $('i.switch', table).removeClass('fa-minus-square-o') + .addClass('fa-plus-square-o'); + } else { + var tr = $('tbody tr', table).first(); + var location = table.data('ams-location') || ''; + var target = table.data('ams-tree-nodes-target') || 'get-tree.json'; + switcher.removeClass('fa-plus-square-o') + .addClass('fa-cog fa-spin'); + MyAMS.ajax.post(location + '/' + target, { + can_sort: !$('td.sorter', tr).is(':empty') + }, function(result, status) { + $('tr[data-ams-tree-node-id]', table).remove(); + var old_row = null; + for (var index = 0; index < result.length; index++) { + var new_row = $(result[index]); + if (old_row === null) { + new_row.appendTo($('tbody', table)); + } else { + new_row.insertAfter(old_row); + } + new_row.addClass('no-drag-handle'); + ams.initContent(new_row); + old_row = new_row; + } + if (table.hasClass('table-dnd')) { + table.tableDnDUpdate(); + } + $('i.switch', table).removeClass('fa-plus-square-o') + .addClass('fa-minus-square-o'); + switcher.removeClass('fa-cog fa-spin') + .addClass('fa-minus-square-o'); + }); + } + }, + + /** + * Sort and re-parent tree elements + */ + sortTree: function(dnd_table, row) { + var data = $(dnd_table).data(); + var target = data.amsTabledndDropTarget; + if (target) { + // Disable row click handler + row = $(row); + row.data('ams-disabled-handlers', 'click'); + try { + // Get root ID + var tableID = row.parents('table').first().data('ams-tree-node-id'); + // Get moved row ID + var rowID = row.data('ams-tree-node-id'); + var rowParentID = row.data('ams-tree-node-parent-id'); + // Get new parent ID + var parent = row.prev('tr'); + if (parent.exists()) { + // Move below an existing row + var parentID = parent.data('ams-tree-node-id'); + // Check switcher state + var switcher = $('.switch', parent); + if (switcher.hasClass('fa-minus-square-o')) { + // Opened folder: move as child + if (rowParentID === parentID) { + // Don't change parent + var action = 'reorder'; + } else { + // Change parent + action = 'reparent'; + } + } else { + // Closed folder or simple item: move as sibling + parentID = parent.data('ams-tree-node-parent-id'); + if (rowParentID === parentID) { + // Don't change parent + action = 'reorder'; + } else { + // Change parent + action = 'reparent'; + } + } + } else { + // Move to site root + parentID = tableID; + switcher = null; + if (rowParentID === parentID) { + // Already child of site root + action = 'reorder'; + } else { + // Move from inner folder to site root + action = 'reparent'; + } + } + // Call ordering target + var localTarget = ams.getFunctionByName(target); + if (typeof(localTarget) === 'function') { + localTarget.call(table, dnd_table, post_data); + } else { + if (!target.startsWith(window.location.protocol)) { + var location = data.amsLocation; + if (location) { + target = location + '/' + target; + } + } + var post_data = { + action: action, + child: rowID, + parent: parentID, + order: JSON.stringify($('tr[data-ams-tree-node-id]').listattr('data-ams-tree-node-id')), + can_sort: !$('td.sorter', row).is(':empty') + }; + ams.ajax.post(target, post_data, function(result) { + + function removeChildRows(rowID) { + var childs = $('tr[data-ams-tree-node-parent-id="' + rowID + '"]'); + childs.each(function() { + var childRow = $(this); + var childID = childRow.attr('data-ams-tree-node-id'); + removeChildRows(childID); + childRow.remove(); + }); + } + + // Remove moved row childrens + var body = $(row).parents('tbody').first(); + removeChildRows(rowID); + if (post_data.action === 'reparent') { + // Remove new parent childrens + removeChildRows(parentID); + row.remove(); + var old_row = $('tr[data-ams-tree-node-id="' + parentID + '"]'); + for (var index = 0; index < result.length; index++) { + var new_row = $(result[index]); + if (old_row.exists()) { + new_row.insertAfter(old_row) + .addClass('no-drag-handle'); + } else { + new_row.prependTo(body) + .addClass('no-drag-handle'); + } + ams.initContent(new_row); + old_row = new_row; + } + } + $('tr').parents('table').tableDnDUpdate(); + }); + } + } finally { + // Restore row click handler + setTimeout(function() { + $(row).removeData('ams-disabled-handlers'); + }, 50); + } + } + return false; + } + }; + + + /** * Generic skin features */ MyAMS.skin = { @@ -4651,6 +4937,57 @@ }, /** + * Replace given form with new content + */ + refreshContent: function(changes) { + var target = $('[id="' + changes.object_id + '"]'); + target.replaceWith($(changes.content)); + target = $('[id="' + changes.object_id + '"]'); + MyAMS.initContent(target); + return target; + }, + + /** + * Replace given table with new content + */ + refreshTable: function(changes) { + var widget = $('[id="' + changes.object_id + '"]').parent('.ams-widget'); + widget.replaceWith($(changes.table)); + widget = $('[id="' + changes.object_id + '"]').parent('.ams-widget'); + MyAMS.initContent(widget); + return widget; + }, + /** + * Replace given row with new content + */ + refreshRow: function(changes) { + var tr = $('tr[id="' + changes.object_id + '"]'); + var table = tr.parents('table').first(); + tr = tr.replaceWith($(changes.row)); + MyAMS.initContent(tr); + if (table.hasClass('table-dnd')) { + table.tableDnDUpdate(); + } + return tr; + }, + + /** + * Replace given row cell with new content + */ + refreshRowCell: function(changes) { + var tr = $('tr[id="' + changes.object_id + '"]'); + var table = tr.parents('table').first(); + var headRow = $('tr', $('thead', table)); + var headCell = $('th[data-ams-column-name="' + changes.col_name + '"]', headRow); + var index = $('th', headRow).index(headCell); + if (index > -1) { + var cell = $($('td', tr).get(index)); + cell.html(changes.cell); + MyAMS.initContent(cell); + } + }, + + /** * Initialize desktop and mobile widgets */ _initDesktopWidgets: function(element) { @@ -5527,6 +5864,11 @@ }); }); + // Enable custom MyAMS refresh events + $(document).on('myams.refresh', function(event, settings) { + MyAMS.executeFunctionByName(settings.handler || MyAMS.skin.refreshContent, event.target, settings); + }); + // Init page content ams.initContent(document); if (ams.ajaxNav && nav.exists()) { diff -r 4b5ae98a90b1 -r 79635dd71cca src/pyams_skin/resources/js/myams.min.js --- a/src/pyams_skin/resources/js/myams.min.js Sun Nov 26 10:09:52 2017 +0100 +++ b/src/pyams_skin/resources/js/myams.min.js Sun Nov 26 10:14:21 2017 +0100 @@ -1,1 +1,1 @@ -!function(e,a){"use strict";var t=a.console;String.prototype.startsWith=function(e){var a=this.length,t=e.length;return!(a0},void 0===e.scrollbarWidth&&(e.scrollbarWidth=function(){var a=e('
').appendTo("body"),t=a.children(),n=t.innerWidth()-t.height(99).innerWidth();return a.remove(),n}),e.fn.extend({exists:function(){return e(this).length>0},objectOrParentWithClass:function(e){return this.hasClass(e)?this:this.parents("."+e)},listattr:function(a){var t=[];return this.each(function(){t.push(e(this).attr(a))}),t},style:function(e,a,t){if(void 0!==this.get(0)){var n=this.get(0).style;return void 0!==e?void 0!==a?(t=void 0!==t?t:"",n.setProperty(e,a,t),this):n.getPropertyValue(e):n}},removeClassPrefix:function(a){return this.each(function(t,n){var i=n.className.split(" ").map(function(e){return e.startsWith(a)?"":e});n.className=e.trim(i.join(" "))}),this},contextMenu:function(a){function t(t,n,i){var s=e(window)[n](),r=e(a.menuSelector)[n](),o=t;return t+r>s&&r',openedSign:''},a),n=e(this);n.find("LI").each(function(){var a=e(this);if(a.find("UL").size()>0){a.find("A:first").append(""+t.closedSign+"");var n=a.find("A:first");"#"===n.attr("href")&&n.click(function(){return!1})}}),n.find("LI.active").each(function(){var a=e(this).parents("UL"),n=a.parent("LI");a.slideDown(t.speed),n.find("b:first").html(t.openedSign),n.addClass("open")}),n.find("LI A").on("click",function(){var a=e(this);if(!a.hasClass("active")){var i=a.attr("href").replace(/^#/,""),s=a.parent().find("UL");if(t.accordion){var r=a.parent().parents("UL"),o=n.find("UL:visible");o.each(function(a){var n=!0;if(r.each(function(e){if(r[e]===o[a])return n=!1,!1}),n&&s!==o[a]){var c=e(o[a]);!i&&c.hasClass("active")||c.slideUp(t.speed,function(){e(this).parent("LI").removeClass("open").find("B:first").delay(t.speed).html(t.closedSign)})}})}var c=a.parent().find("UL:first");i||!c.is(":visible")||c.hasClass("active")?c.slideDown(t.speed,function(){a.parent("LI").addClass("open").find("B:first").delay(t.speed).html(t.openedSign)}):c.slideUp(t.speed,function(){a.parent("LI").removeClass("open").find("B:first").delay(t.speed).html(t.closedSign)})}})}}),e.UTF8={encode:function(e){e=e.replace(/\r\n/g,"\n");for(var a="",t=0;t127&&n<2048?(a+=String.fromCharCode(n>>6|192),a+=String.fromCharCode(63&n|128)):(a+=String.fromCharCode(n>>12|224),a+=String.fromCharCode(n>>6&63|128),a+=String.fromCharCode(63&n|128))}return a},decode:function(e){for(var a="",t=0,n=0,i=0,s=0;t191&&n<224?(i=e.charCodeAt(t+1),a+=String.fromCharCode((31&n)<<6|63&i),t+=2):(i=e.charCodeAt(t+1),s=e.charCodeAt(t+2),a+=String.fromCharCode((15&n)<<12|(63&i)<<6|63&s),t+=3);return a}},void 0===a.MyAMS&&(a.MyAMS={devmode:!0,devext:"",lang:"en",throttleDelay:350,menuSpeed:235,navbarHeight:49,ajaxNav:!0,enableWidgets:!0,enableMobile:!1,enableFastclick:!1,warnOnFormChange:!1,ismobile:/iphone|ipad|ipod|android|blackberry|mini|windows\sce|palm/i.test(navigator.userAgent.toLowerCase())});var n=a.MyAMS,i=n;n.baseURL=function(){var a=e('script[src*="/myams.js"], script[src*="/myams.min.js"]').attr("src");return i.devmode=a.indexOf(".min.js")<0,i.devext=i.devmode?"":".min",a.substring(0,a.lastIndexOf("/")+1)}(),n.log=function(){t&&t.debug&&t.debug(this,arguments)},n.getQueryVar=function(e,a){if(e.indexOf("?")<0)return!1;e.endsWith("&")||(e+="&");var t=new RegExp(".*?[&\\?]"+a+"=(.*?)&.*"),n=e.replace(t,"$1");return n!==e&&n},n.rgb2hex=function(a){return"#"+e.map(a.match(/\b(\d+)\b/g),function(e){return("0"+parseInt(e).toString(16)).slice(-2)}).join("")},n.generateId=function(){function e(){return Math.floor(65536*(1+Math.random())).toString(16).substring(1)}return e()+e()+e()+e()},n.generateUUID=function(){var e=(new Date).getTime();return"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,function(a){var t=(e+16*Math.random())%16|0;return e=Math.floor(e/16),("x"===a?t:3&t|8).toString(16)})},n.getObject=function(e,a){if(e){if("string"!=typeof e)return e;var t=e.split(".");a=void 0===a||null===a?window:a;for(var n=0;n").attr({rel:"stylesheet",type:"text/css",href:s,"data-ams-id":t}).appendTo(n)}},n.event={stop:function(e){e||(e=window.event),e&&(e.stopPropagation?(e.stopPropagation(),e.preventDefault()):(e.cancelBubble=!0,e.returnValue=!1))}},n.browser={getInternetExplorerVersion:function(){var e=-1;if("Microsoft Internet Explorer"===navigator.appName){var a=navigator.userAgent;null!==new RegExp("MSIE ([0-9]{1,}[.0-9]{0,})").exec(a)&&(e=parseFloat(RegExp.$1))}return e},checkVersion:function(){var e="You're not using Windows Internet Explorer.",t=this.getInternetExplorerVersion();t>-1&&(e=t>=8?"You're using a recent copy of Windows Internet Explorer.":"You should upgrade your copy of Windows Internet Explorer."),a.alert&&a.alert(e)},isIE8orlower:function(){var e="0",a=this.getInternetExplorerVersion();return a>-1&&(e=a>=9?0:1),e},copyToClipboard:function(s){function r(s){var r=!1;if(window.clipboardData&&window.clipboardData.setData)r=clipboardData.setData("Text",s);else if(document.queryCommandSupported&&document.queryCommandSupported("copy")){var o=e("