Re: [xwiki-devs] [xwiki-notifications] r34685 - in platform: core/trunk/xwiki-core/src/main/resources core/trunk/xwiki-rendering/xwiki-rendering-macros/xwiki-rendering-macro-dashboard/src/main/java/org/xwiki/rendering/internal/macro/dashboard core/trunk/xwiki-ren
On Tue, Feb 15, 2011 at 2:55 PM, lucaa <[email protected]>wrote:
Author: lucaa Date: 2011-02-15 14:55:47 +0100 (Tue, 15 Feb 2011) New Revision: 34685
Added:
platform/web/trunk/standard/src/main/webapp/resources/uicomponents/dashboard/dashboard.js Modified:
platform/core/trunk/xwiki-core/src/main/resources/ApplicationResources.properties
platform/core/trunk/xwiki-rendering/xwiki-rendering-macros/xwiki-rendering-macro-dashboard/src/main/java/org/xwiki/rendering/internal/macro/dashboard/ColumnsDashboardRenderer.java
platform/core/trunk/xwiki-rendering/xwiki-rendering-macros/xwiki-rendering-macro-dashboard/src/main/java/org/xwiki/rendering/internal/macro/dashboard/DashboardMacro.java
platform/core/trunk/xwiki-rendering/xwiki-rendering-macros/xwiki-rendering-macro-dashboard/src/test/java/org/xwiki/rendering/RenderingTests.java
platform/core/trunk/xwiki-rendering/xwiki-rendering-macros/xwiki-rendering-macro-dashboard/src/test/resources/macrodashboard1.test
platform/web/trunk/standard/src/main/webapp/resources/uicomponents/container/columns.css
platform/web/trunk/standard/src/main/webapp/resources/uicomponents/dashboard/dashboard.css Log: XWIKI-5939: Allow to edit the positions of gadgets on a dashboard with drag & drop XWIKI-5941: Allow to remove a gadget from a dashboard * Added dashboard visual editor in edit inline mode, with drag & drop for gadgets positions and remove button Fixed the columns layout to use columns spacing on both sides of columns (instead of only the right side), and to handle empty columns
[snip]
Added: platform/web/trunk/standard/src/main/webapp/resources/uicomponents/dashboard/dashboard.js =================================================================== --- platform/web/trunk/standard/src/main/webapp/resources/uicomponents/dashboard/dashboard.js (rev 0) +++ platform/web/trunk/standard/src/main/webapp/resources/uicomponents/dashboard/dashboard.js 2011-02-15 13:55:47 UTC (rev 34685) @@ -0,0 +1,280 @@ +var XWiki = (function (XWiki) { +// Start XWiki augmentation. +XWiki.Dashboard = Class.create( { + initialize : function(element) { + //the class of the gadget objects + this.gadgetsClass = "XWiki.GadgetClass"; + // the source of the dashboard, the document where the objects are stored and which needs to be updated + // TODO: put me here, but it's a bit tough because we don't know if as URL or as fullname or space, page, wiki vars + // flag to know if the dashboard was edited or not, to know if requests should be sent on save or not + this.edited = false; + // the list of removed gadgets, to really remove when the inline form is submitted + this.removed = new Array(); + this.element = element; + // add an extra class to this element, to know that it's editing, for css that needs to be special on edit + this.element.addClassName("dashboard-edit"); + // find out all the gadget-containers in element and add them ids + this.containers = element.select(".gadget-container"); + this.createDragAndDrops(); + this.addGadgetsHandlers(); + + // add save listener, to save the dashboard before submit of the form + document.observe("xwiki:actions:save", this.saveChanges.bindAsEventListener(this)); + }, + + /** + * @param container the container to get the id of + * @return the original container id, parsed from the HTML id of this container. + * This is used to be able to have unique ids of containers in the HTML, and at the same time be able to match + * containers ids to the model. + * FIXME: this will cause issues with multiple dashboards, add the name of the dashboard to the ids + */ + _getContainerId : function (container) { + // the gadget container id is of the form gadgetcontainer_<containerId>, so parse it back + return container.readAttribute('id').substring(16); + }, + + /** + * @param gadget the gadget to get the id of + * @return the original gadget id, parsed from the HTML id of this gadget. + * This is used to be able to have unique ids of gadgets in the HTML, and at the same time be able to match + * gadgets ids to the model. + * FIXME: this will cause issues with multiple dashboards, add the name of the dashboard to the ids + */ + _getGadgetId : function(gadget) { + // gadget ids are of the form gadget_<id> + return gadget.readAttribute('id').substring(7); + }, + + /* + * Drag & drop decorators functions, to display nice placeholders when dragging & dropping. + */ + _insertPlaceholder: function (container) { + if ( container.down('.gadget') || container.down('.gadget-placeholder')) { + return; + } + var placeholder = new Element('div', {'class' : 'gadget-placeholder'}) + .update('$msg.get("dashboard.gadget.actions.drop")'); + container.insert(placeholder); + }, + + _removePlaceholder: function (container) { + var placeholders = container.select('.gadget-placeholder'); + placeholders.each(function (el) { + el.remove(); + }); + }, + + _doOnStartDrag: function() { + this.containers.each(this._insertPlaceholder); + }, + _doOnEndDrag: function() { + this.containers.each(this._removePlaceholder); + }, + + /** + * Creates drag and drops for the gadgets inside the gadget containers. + */ + createDragAndDrops : function() { + // put all the container ids in a list, to be able to pass it to the sortables + var containerIds = new Array(); + this.containers.each(function(container) { + containerIds.push(container.readAttribute('id')); + }); + + // create a sortable for each gadget container + containerIds.each(function(containerId) { + Sortable.create(containerId, { + tag:'div', + only:'gadget', + handle:'gadget-title', + overlap: 'vertical', + scroll: window, + containment: containerIds, + dropOnEmpty: true, + constraint: false, + ghosting:false, + hoverclass: 'gadget-container-hover-highlight', + onUpdate: this.onMoveGadget.bind(this) + }); + }.bind(this)); + }, + + /** + * Adds handlers to the gadgets on the dashboard, the remove. + */ + addGadgetsHandlers : function() { + // iterate through all the gadgets and add settings handlers + this.element.select('.gadget').each(function(gadget){ + // create a settings menu button and add it to the gadget-title + var itemMenu = new Element('div', {'class' : 'settings', 'title' : '$msg.get("dashboard.gadget.actions.tooltip")'}); + var gadgetTitle = gadget.down('.gadget-title'); + if (!gadgetTitle) { + return; + } + // create a remove button in the settings menu + var removeLink = new Element('div', {'class' : 'remove', 'title' : '$msg.get("dashboard.gadget.action.delete.tooltip")'}); + removeLink.observe('click', this.onRemoveGadget.bindAsEventListener(this)); + var actionsContainer = new Element('div', {'class' : 'settings-menu'}) + actionsContainer.hide(); + actionsContainer.insert(removeLink); + itemMenu.hide(); + gadgetTitle.insert(itemMenu); + gadgetTitle.insert(actionsContainer); + // and listen to the click to open the menu + itemMenu.observe('click', function(event){ + // toggle actions container + actionsContainer.toggle(); + // and add a class to the item menu, to be able to color it properly + itemMenu.toggleClassName('settings-open'); + }); + + // display the link remove link only when the gadget is hovered + gadget.observe('mouseover', function() { + itemMenu.show(); + }); + gadget.observe('mouseout', function(event) { + var relatedTarget = event.relatedTarget || event.toElement; + if ((event.element() == gadget || event.element().up('.gadget')) && (relatedTarget == null || relatedTarget.up('.gadget') == null)) { + // enough propagation + event.stop(); + itemMenu.hide(); + actionsContainer.hide(); + itemMenu.removeClassName('settings-open'); + } + }); + }.bind(this)); + + // add the decorators to the gadgets on drag & drop + var doOnStartDrag = this._doOnStartDrag.bind(this); + var doOnEndDrag = this._doOnEndDrag.bind(this); + Draggables.addObserver({ + onStart: doOnStartDrag, + onEnd: doOnEndDrag + }); + }, + + /** + * Removes the gadget passed by its id. + * + * @param event the click event on the remove button for a gadget + */ + onRemoveGadget : function(event) { + // get the clicked button + var item = event.element(); + // get the gadget to remove + var gadget = item.up(".gadget"); + if (!gadget) { + return; + } + var gadgetId = this._getGadgetId(gadget); + this.removed.push(gadgetId); + // send a request to the REST url to remove the object corresponding to this gadget + // TODO: this should be the URI to the dashboard source, not to the current page + var gadgetObjectURL = XWiki.contextPath + '/rest/wikis/' + encodeURIComponent(XWiki.currentWiki) + '/spaces/' + + encodeURIComponent(XWiki.currentSpace) + '/pages/' + encodeURIComponent(XWiki.currentPage) + + '/objects/' + encodeURIComponent(this.gadgetsClass) + '/' + gadgetId + '?media=json&method=DELETE';
Why not use XWiki.currentDocument.getRestUrl ?
+ new XWiki.widgets.ConfirmedAjaxRequest( + gadgetObjectURL, + { + onCreate : function() { + // Disable the button, to avoid a cascade of clicks from impatient users + item.disabled = true; + }, + onSuccess : function(response) { + // remove the gadget from the page + gadget.remove(); + }.bind(this) + }, + /* Interaction parameters */ + { + confirmationText: "$msg.get('dashboard.gadget.action.delete.confirm')", + progressMessageText : "$msg.get('dashboard.gadget.action.delete.inProgress')", + successMessageText : "$msg.get('dashboard.gadget.action.delete.done')", + failureMessageText : "$msg.get('dashboard.gadget.action.delete.failed')" + } + ); + }, + + /** + * Function called when a gadget has been moved from a container to another. + * + * @param container the source and target container for the move, depending on the particular call of this function + */ + onMoveGadget : function(container) { + // just flag that the dashboard was edited, actual changes were performed when the save button will be clicked + this.edited = true; + }, + + /** + * Saves the changes on the dashboard in this document: perform all removes and injects the object edit fields in the + * inline edit form. + */ + saveChanges : function(event) { + if (!this.edited) { + return; + } + + var editFields = this.prepareEditParameters(); + // get the edit form + var editForm = event.memo.form; + // put the fields in a dashboard layout fieldset, to be able to update them on subsequent saves + // (in case of save & continue) + // FIXME: add the name of the dashboard in here, will cause issues when there are multiple dashboards + var dashboardFieldSet = editForm.down('.dashboard-layout-fieldset'); + if (dashboardFieldSet) { + // empty the dashboard field set, to fill in with the new fields after + dashboardFieldSet.update(''); + } else { + // create the dashboard field set, to fill in with the new fields + dashboardFieldSet = new Element('fieldset', {'class' : 'dashboard-layout-fieldset'}); + editForm.insert(dashboardFieldSet); + } + editFields.each(function(editField) { + // create a hidden input for the update of the position of the gadget object and append it to the form + var fieldInput = new Element('input', {'name' : editField.key, 'value' : editField.value, 'type' : 'hidden'}); + dashboardFieldSet.insert(fieldInput); + }.bind(this)); + }, + + /** + * Prepares a hashmap of parameters that would update the positions of the gadget fields. + * @return the hash of parameters to submit to the object edit URL, to update the gadget object positions in this + * dashboard + */ + prepareEditParameters : function() { + var parameters = new Hash(); + // for each gadget in the containers, put it in the map, along with its new position + this.element.select('.gadget-container').each(function(container) { + // get the id of the container + var containerId = this._getContainerId(container); + // foreach of its gadget children, get the position and compose the position update field + container.select('.gadget').each(function(gadget, index) { + // get the id of the current gadget -> object number, actually + var gadgetId = this._getGadgetId(gadget); + // the position field name as in the inline form edit XWiki.GadgetClass_0_position + var positionFieldName = this.gadgetsClass + '_' + gadgetId + '_' + 'position'; + // compose the position field value as container, index (1 based, though) + var positionFieldValue = containerId + ', ' + (index + 1); + // and put these in the prepared hash + parameters.set(positionFieldName, positionFieldValue); + }, this); + }, this); + + return parameters; + } +}); +//End XWiki augmentation. +return XWiki; +}(XWiki || {})); + +document.observe('xwiki:dom:loaded', function(event) { + // editable dashboard only in inline mode + if (XWiki.contextaction == 'inline') { + // edit first dashboard FIXME: to create a dashboard editor for all dashboards + var dashboardRootElt = $$('.dashboard')[0];
You can use $('mainContentArea').down('.dashboard') which should be less greedy Jerome.
+ if (dashboardRootElt) { + var dashboard = new XWiki.Dashboard(dashboardRootElt); + } + } +}); \ No newline at end of file
Property changes on: platform/web/trunk/standard/src/main/webapp/resources/uicomponents/dashboard/dashboard.js ___________________________________________________________________ Added: svn:keywords + Author Id Revision HeadURL Added: svn:eol-style + native
_______________________________________________ notifications mailing list [email protected] http://lists.xwiki.org/mailman/listinfo/notifications
participants (1)
-
Jerome Velociter