From 79f223b7f22f1fba3d7e4a617a688bcb3e12e5bd Mon Sep 17 00:00:00 2001 From: neexite Date: Tue, 1 Mar 2016 13:07:27 +0200 Subject: [PATCH 001/133] Group buttons in toolbar - base --- .../scripts/source/top/system/SystemAction.js | 60 ++++--- .../combobutton/ToolBarComboButtonBinding.js | 53 ++++-- .../top/ui/bindings/popups/PopupSetBinding.js | 66 ++++++- .../bindings/system/SystemToolBarBinding.js | 164 +++++++++--------- .../Composite/scripts/source/top/util/Map.js | 38 ++-- Website/Composite/styles/default/buttons.less | 2 +- 6 files changed, 234 insertions(+), 149 deletions(-) diff --git a/Website/Composite/scripts/source/top/system/SystemAction.js b/Website/Composite/scripts/source/top/system/SystemAction.js index 0bacab4373..a51aaf2861 100644 --- a/Website/Composite/scripts/source/top/system/SystemAction.js +++ b/Website/Composite/scripts/source/top/system/SystemAction.js @@ -48,14 +48,14 @@ SystemAction.actionMap = new Map (); * @param {object} arg This can be either a SystemNode or a List of SystemNodes. */ SystemAction.invoke = function ( action, arg ) { - + var node = arg; - + if ( node instanceof SystemNode ) { Application.lock ( SystemAction ); action.logger.debug ( "Execute \"" + action.getLabel () + "\" on \"" + node.getLabel () + "\"." ); setTimeout ( function () { // timeout allow pressed buttons to unpress - TreeService.ExecuteSingleElementAction ( + TreeService.ExecuteSingleElementAction ( node.getData (), action.getHandle (), Application.CONSOLE_ID @@ -66,48 +66,48 @@ SystemAction.invoke = function ( action, arg ) { } else { throw "Multiple actiontargets not supported."; } - + /* * A list of nodehandles. * @type {array} * var nodeHandleList = []; - + MULTIPLE SELECTIONS SETUP! - - ExplorerBinding.getFocusedTreeNodeBindings ().each ( + + ExplorerBinding.getFocusedTreeNodeBindings ().each ( function ( treeNodeBinding ) { var systemNode = treeNodeBinding.node; - nodeHandleList.push ( + nodeHandleList.push ( systemNode.getHandle () ); } ); - + if ( nodeHandleList.length > 0 ) { - + var actionHandle = action.getHandle (); - var serviceResponse = TreeService.ExecuteElementAction ( + var serviceResponse = TreeService.ExecuteElementAction ( nodeHandleList, actionHandle, Application.CONSOLE_ID ); - + MessageQueue.update (); } */ - + /* var systemNode = null; - + var list = ExplorerBinding.getFocusedTreeNodeBindings (); if ( list.hasEntries ()) { var treeNodeBinding = list.getFirst (); var systemNode = treeNodeBinding.node; } - + if ( systemNode ) { - var serviceResponse = TreeService.ExecuteSingleElementAction ( + var serviceResponse = TreeService.ExecuteSingleElementAction ( node.getData (), action.getHandle (), Application.CONSOLE_ID @@ -123,14 +123,14 @@ SystemAction.invoke = function ( action, arg ) { * @param {string} taggedaction */ SystemAction.invokeTagged = function ( taggedaction, taggednode ) { - + action = SystemAction.taggedActions.get ( taggedaction ); node = SystemNode.taggedNodes.get ( taggednode ); SystemAction.invoke ( action, node ); } /** - * Check action category before displaying in GUI. So that we + * Check action category before displaying in GUI. So that we * don't wonder what happens to newly introduced categories. * @param {string} string * @return {boolean} @@ -149,13 +149,13 @@ function SystemAction ( object ) { * @type {SystemLogger} */ this.logger = SystemLogger.getLogger ( "SystemAction" ); - + /** * @type {object} * @private */ this._data = object; - + /* * Register tagged action. */ @@ -171,7 +171,7 @@ function SystemAction ( object ) { * Identifies object. */ SystemAction.prototype.toString = function () { - + return "[SystemAction]"; } @@ -249,7 +249,7 @@ SystemAction.prototype.getCategory = function () { * @return {string} */ SystemAction.prototype.getGroupID = function () { - + return this._data.ActionCategory.GroupId; } @@ -290,6 +290,16 @@ SystemAction.prototype.isInFolder = function () { return this._data.ActionCategory.IsInFolder; } + +/** + * Get Bundle Name + * @return {boolean} + */ +SystemAction.prototype.getBundleName = function () { + + return this._data.ActionCategory.ActionBundle; +} + /** * @return {string} */ @@ -316,7 +326,7 @@ SystemAction.prototype.isDisabled = function () { * @return {boolean} */ SystemAction.prototype.isCheckBox = function () { - + return typeof this._data.CheckboxStatus != Types.UNDEFINED; } @@ -325,7 +335,7 @@ SystemAction.prototype.isCheckBox = function () { * @return {string} */ SystemAction.prototype.getTag = function () { - + var result = null; if ( typeof this._data.TagValue != "undefined" ) { result = this._data.TagValue; @@ -338,7 +348,7 @@ SystemAction.prototype.getTag = function () { * @return {boolean} */ SystemAction.prototype.isChecked = function () { - + var result = null; if ( this.isCheckBox ()) { result = this._data.CheckboxStatus == "Checked"; diff --git a/Website/Composite/scripts/source/top/ui/bindings/buttons/combobutton/ToolBarComboButtonBinding.js b/Website/Composite/scripts/source/top/ui/bindings/buttons/combobutton/ToolBarComboButtonBinding.js index ac7a6b66fb..c66a6ac800 100644 --- a/Website/Composite/scripts/source/top/ui/bindings/buttons/combobutton/ToolBarComboButtonBinding.js +++ b/Website/Composite/scripts/source/top/ui/bindings/buttons/combobutton/ToolBarComboButtonBinding.js @@ -27,6 +27,11 @@ function ToolBarComboButtonBinding() { */ this.isCheckButton = true; + /** + * @type {string} + */ + this.bundleName = null; + /* * Returnable. */ @@ -53,10 +58,12 @@ ToolBarComboButtonBinding.prototype.onBindingAttach = function () { this.comboBoxBinding.attach(); this.attachClassName(ToolBarComboButtonBinding.CLASSNAME_COMBOBUTTON); + + this.bundleName = this.getProperty("bundle") ? this.getProperty("bundle") : this.getProperty("id"); }; /** -* Build popup when perspective changes. If no +* Build popup when perspective changes. If no * views are associated, the button will disable. * @overloads {ToolBarButtonBinding#handleBroadcast} * @param {string} broadcast @@ -87,22 +94,18 @@ ToolBarComboButtonBinding.prototype.setPopup = function (arg) { }; } ); - var activeMenu = null; - var activeMenuId = this.getActiveMenuItemId(); + var activeMenu = menuitems.hasEntries() ? menuitems.getFirst() : null ; + var activeMenuHandle = this.getActiveMenuHandle(); menuitems.reset(); while (menuitems.hasNext()) { var menuitem = menuitems.getNext(); - if (menuitem.getProperty("id") == activeMenuId) { + if (this.getMenuHandle(menuitem) === activeMenuHandle) { activeMenu = menuitem; break; } } - if (activeMenu == null && menuitems.hasEntries()) { - activeMenu = menuitems.getFirst(); - } - if (activeMenu != null) this.setButton(activeMenu); } @@ -133,6 +136,8 @@ ToolBarComboButtonBinding.prototype.setButton = function (menuitem) { this.setImage(this.imageProfile.getDefaultImage()); + this.associatedSystemAction = menuitem.associatedSystemAction; + this.oncommand = function () { Binding.evaluate(hiddenCommand, this); }; @@ -149,7 +154,7 @@ ToolBarComboButtonBinding.prototype.setAndFireButton = function (menuitem) { if (menuitem instanceof MenuItemBinding) { this.setButton(menuitem); - this.setActiveMenuItemId(menuitem.getProperty("id")); + this.setActiveMenuHandle(this.getMenuHandle(menuitem)); this.fireCommand(); } } @@ -161,7 +166,7 @@ ToolBarComboButtonBinding.prototype.setAndFireButton = function (menuitem) { ToolBarComboButtonBinding.prototype.hideActiveItem = function (activeMenuitem) { this.popupBinding.getDescendantBindingsByType(MenuItemBinding).each( function (menuitem) { - if (menuitem == activeMenuitem) { + if (menuitem === activeMenuitem) { Binding.prototype.hide.call(menuitem); } else { Binding.prototype.show.call(menuitem); @@ -172,17 +177,33 @@ ToolBarComboButtonBinding.prototype.hideActiveItem = function (activeMenuitem) { /** -* Set active menuitem id +* Set active menuitem handle * @param {MenuItemBinding} menuitem id */ -ToolBarComboButtonBinding.prototype.setActiveMenuItemId = function (id) { - Cookies.createCookie(this.getProperty("id"), id, 365); +ToolBarComboButtonBinding.prototype.setActiveMenuHandle = function (id) { + + Cookies.createCookie(this.bundleName, id, 365); } /** -* Get active menuitem id +* Get active menuitem handle */ -ToolBarComboButtonBinding.prototype.getActiveMenuItemId = function () { - return Cookies.readCookie(this.getProperty("id")); +ToolBarComboButtonBinding.prototype.getActiveMenuHandle = function () { + return Cookies.readCookie(this.bundleName); +} + +ToolBarComboButtonBinding.prototype.getMenuHandle = function (menuitem) { + + return menuitem.menuHandle ? menuitem.menuHandle : this.getProperty("id"); } +/** + * ToolBarButtonBinding factory. + * @param {DOMDocument} ownerDocument + * @return {ToolBarButtonBinding} + */ +ToolBarComboButtonBinding.newInstance = function (ownerDocument) { + + var element = DOMUtil.createElementNS(Constants.NS_UI, "ui:toolbarbutton", ownerDocument); + return UserInterface.registerBinding(element, ToolBarComboButtonBinding); +} \ No newline at end of file diff --git a/Website/Composite/scripts/source/top/ui/bindings/popups/PopupSetBinding.js b/Website/Composite/scripts/source/top/ui/bindings/popups/PopupSetBinding.js index 792eda8e90..c1769cbad6 100644 --- a/Website/Composite/scripts/source/top/ui/bindings/popups/PopupSetBinding.js +++ b/Website/Composite/scripts/source/top/ui/bindings/popups/PopupSetBinding.js @@ -2,6 +2,28 @@ PopupSetBinding.prototype = new MenuContainerBinding; PopupSetBinding.prototype.constructor = PopupSetBinding; PopupSetBinding.superclass = MenuContainerBinding.prototype; + +PopupSetBinding.getPopupSet = function (ownerDocument, rel) { + + var rootBinding = UserInterface.getBinding(ownerDocument.body); + var result = null; + rootBinding.getDescendantBindingsByType(PopupSetBinding).each(function(popupset) { + if (popupset.getProperty("rel") === rel) { + result = popupset; + return false; + } + return true; + }); + + if (result == null) { + result = rootBinding.addFirst(PopupSetBinding.newInstance(ownerDocument)); + result.setProperty("rel", rel); + result.attach(); + } + + return result; +} + /** * @class */ @@ -11,14 +33,14 @@ function PopupSetBinding () { * @type {SystemLogger} */ this.logger = SystemLogger.getLogger ( "PopupSetBinding" ); - + /** * Block common crawlers. * @type {Map} * @overwrites {Binding#crawlerFilters} */ this.crawlerFilters = new List ([ FlexBoxCrawler.ID, FocusCrawler.ID ]); - + /* * Returnable. */ @@ -33,7 +55,7 @@ PopupSetBinding.prototype.toString = function () { return "[PopupSetBinding]"; } -/** +/** * @overloads {Binding#onBindintAttach} */ PopupSetBinding.prototype.onBindingAttach = function () { @@ -45,6 +67,42 @@ PopupSetBinding.prototype.onBindingAttach = function () { } } +PopupSetBinding.prototype.getPopupByRel = function (rel) { + + var result = null; + + this.getDescendantBindingsByType(PopupBinding).each(function (popup) { + if (popup.getProperty("rel") === rel) { + result = popup; + return false; + } + return true; + }); + + return result; +}; + +PopupSetBinding.prototype.createNewPopupByRel = function (rel) { + + var popupBinding = this.getPopupByRel(rel); + + if (popupBinding) { + popupBinding.empty(); + } else { + popupBinding = this.add( + PopupBinding.newInstance(this.bindingDocument) + ); + popupBinding.add( + MenuBodyBinding.newInstance(this.bindingDocument) + ); + popupBinding.setProperty("rel", rel); + popupBinding.attachRecursive(); + } + + return popupBinding; +} + + /** * PopupSetBinding factory. * @param {DOMDocument} ownerDocument @@ -52,6 +110,6 @@ PopupSetBinding.prototype.onBindingAttach = function () { */ PopupSetBinding.newInstance = function (ownerDocument) { - var element = DOMUtil.createElementNS(Constants.NS_UI, "ui:popup", ownerDocument); + var element = DOMUtil.createElementNS(Constants.NS_UI, "ui:popupset", ownerDocument); return UserInterface.registerBinding(element, PopupSetBinding); } \ No newline at end of file diff --git a/Website/Composite/scripts/source/top/ui/bindings/system/SystemToolBarBinding.js b/Website/Composite/scripts/source/top/ui/bindings/system/SystemToolBarBinding.js index 1ef13de684..fb98145ea3 100644 --- a/Website/Composite/scripts/source/top/ui/bindings/system/SystemToolBarBinding.js +++ b/Website/Composite/scripts/source/top/ui/bindings/system/SystemToolBarBinding.js @@ -12,27 +12,27 @@ function SystemToolBarBinding () { * @type {SystemLogger} */ this.logger = SystemLogger.getLogger ( "SystemToolBarBinding" ); - + /** * @type {string} */ this._currentProfileKey = null; - + /** * @type {HashMap} */ this._actionFolderNames = {}; - + /** * @type {Map>} */ this._actionProfile = null; - + /** * @type {int} */ this._moreActionsWidth = 0; - + /** * Actions that wouldn't fit on the toolbar. * @type {List} @@ -50,11 +50,11 @@ function SystemToolBarBinding () { this._syncHandle = null; /** - * Tree position + * Tree position * @type {int} */ this._activePosition = SystemAction.activePositions.NavigatorTree; - + /* * Returnable. */ @@ -74,9 +74,9 @@ SystemToolBarBinding.prototype.toString = function () { * @overloads {ToolBarBinding#onBindingAttach} */ SystemToolBarBinding.prototype.onBindingAttach = function () { - + SystemToolBarBinding.superclass.onBindingAttach.call ( this ); - + if ( System.hasActivePerspectives ) { this.subscribe ( BroadcastMessages.SYSTEM_ACTIONPROFILE_PUBLISHED ); this.subscribe ( this.bindingWindow.WindowManager.WINDOW_RESIZED_BROADCAST ); @@ -92,20 +92,20 @@ SystemToolBarBinding.prototype.onBindingAttach = function () { } /** - * Do stuff with dimensions on startup (handles too many actions on toolbar). + * Do stuff with dimensions on startup (handles too many actions on toolbar). * @overloads {ToolBarBinding#onBindingInitialize} */ SystemToolBarBinding.prototype.onBindingInitialize = function () { - + // lookup more-actions toolbarbody width - then hide it var moreActionsBody = this.bindingWindow.bindingMap.moreactionstoolbargroup; this._moreActionsWidth = moreActionsBody.boxObject.getDimension ().w; moreActionsBody.hide (); - + // lock toolbar height to fix overflow issues. var height = this.boxObject.getDimension ().h; this.bindingElement.style.height = height + "px"; - + // rigup more-actions button. var self = this; var button = this.bindingWindow.bindingMap.moreactionsbutton; @@ -115,7 +115,7 @@ SystemToolBarBinding.prototype.onBindingInitialize = function () { action.consume (); } }); - + // rigup more-actions popup var popup = this.bindingWindow.bindingMap.moreactionspopup; popup.addActionListener ( MenuItemBinding.ACTION_COMMAND, { @@ -124,12 +124,12 @@ SystemToolBarBinding.prototype.onBindingInitialize = function () { self._handleSystemAction ( item.associatedSystemAction ); } }); - + SystemToolBarBinding.superclass.onBindingInitialize.call ( this ); } /** - * Handle EventBroadcaster transmissions. In particular, watch out for actionprofiles. + * Handle EventBroadcaster transmissions. In particular, watch out for actionprofiles. * @see {SystemTreeBinding#_publishCompiledActionProfile} * @implements {IBroadcastListener} * @param {string} broadcast @@ -204,13 +204,13 @@ SystemToolBarBinding.prototype._getProfileKey = function () { var result = new String ( "" ); this._actionProfile.each ( function ( groupid, list ) { list.each( function (systemAction ) { - result += systemAction.getHandle() + ";" + systemAction.getKey() + ";"; + result += systemAction.getHandle() + ";" + systemAction.getKey() + ";"; //Make different profile key for toolbar with enabled/disabled actions if (systemAction.isDisabled()) result += "isDisabled='true';"; }); }); - + return result; } @@ -223,7 +223,7 @@ SystemToolBarBinding.prototype._getProfileKey = function () { SystemToolBarBinding.prototype.handleAction = function ( action ) { SystemToolBarBinding.superclass.handleAction.call ( this, action ); - + switch ( action.type ) { case ButtonBinding.ACTION_COMMAND : var button = action.target; @@ -237,14 +237,8 @@ SystemToolBarBinding.prototype.handleAction = function ( action ) { * @param (SystemAction} action */ SystemToolBarBinding.prototype._handleSystemAction = function ( action ) { - + if ( action != null ) { - //var list = ExplorerBinding.getFocusedTreeNodeBindings (); - //if ( list.hasEntries ()) { - // var treeNodeBinding = list.getFirst (); - // var systemNode = treeNodeBinding.node; - //} - //SystemAction.invoke ( action, systemNode ); SystemAction.invoke(action, this._node); } } @@ -253,33 +247,57 @@ SystemToolBarBinding.prototype._handleSystemAction = function ( action ) { * Build left-aligned toolbar content based on last published actionProfile. */ SystemToolBarBinding.prototype.buildLeft = function () { - - if ( this.isInitialized && this._actionProfile != null && this._actionProfile.hasEntries ()) { - - var doc = this.bindingDocument; + + if (this.isInitialized && this._actionProfile != null && this._actionProfile.hasEntries()) { + + var doc = this.bindingDocument; var self = this; - + + var popupSetBinding = PopupSetBinding.getPopupSet(doc, "bundlepopup"); + var bundles = new Map(); + this._actionProfile.each ( function ( groupid, list ) { - + var buttons = new List (); - + list.reset (); while ( list.hasNext ()) { var action = list.getNext (); var buttonBinding = null; + if ( action.isInToolBar ()) { - if ( action.isInFolder ()) { - alert ( "IsInFolder not implemented!" ); - //buttonBinding = this.getPossibleButtonBinding ( action ); + var bundleName = action.getBundleName(); + if (bundleName) { + + var popupBinding; + + if (bundles.has(bundleName)) { + popupBinding = popupSetBinding.getPopupByRel(bundleName); + + } else { + buttonBinding = ToolBarComboButtonBinding.newInstance(doc); + buttonBinding.setProperty("bundle", bundleName); + bundles.set(bundleName, buttonBinding); + popupBinding = popupSetBinding.createNewPopupByRel(bundleName); + } + + var item = SystemTreePopupBinding.prototype.getMenuItemBinding.call(this, action); + + popupBinding.add( + item + ); + item.attach(); + item.menuHandle = action.getHandle(); + } else { - buttonBinding = self.getToolBarButtonBinding ( action ); + buttonBinding = self.getToolBarButtonBinding(action); } } if ( buttonBinding != null ) { buttons.add ( buttonBinding ); } } - + if ( buttons.hasEntries ()) { var groupBinding = ToolBarGroupBinding.newInstance ( doc ); buttons.each ( function ( buttonBinding ) { @@ -287,18 +305,22 @@ SystemToolBarBinding.prototype.buildLeft = function () { }); self.addLeft ( groupBinding ); // TODO: BOOLEAN ARGUMENT HERE! } + }, this); + + this.attachRecursive(); + + bundles.each(function(bundle, buttonBinding) { + buttonBinding.setPopup(popupSetBinding.getPopupByRel(bundle)); }); - - this.attachRecursive (); this._containAllButtons (); } } /** - * Contain all buttons. Overflowing buttons are moved to a popup. + * Contain all buttons. Overflowing buttons are moved to a popup. */ SystemToolBarBinding.prototype._containAllButtons = function () { - + var mores = this.bindingWindow.bindingMap.moreactionstoolbargroup; var paddings = CSSComputer.getPadding(this.bindingElement); var avail = this.bindingElement.offsetWidth - paddings.left - paddings.right; @@ -311,7 +333,7 @@ SystemToolBarBinding.prototype._containAllButtons = function () { var total = 0; var hides = new List (); - + var button, buttons = this._toolBarBodyLeft.getDescendantBindingsByLocalName ( "toolbarbutton" ); while (( button = buttons.getNext ()) != null ) { if ( !button.isVisible ) { @@ -324,18 +346,18 @@ SystemToolBarBinding.prototype._containAllButtons = function () { button.hide (); } } - + if ( hides.hasEntries ()) { - + var group = hides.getFirst ().bindingElement.parentNode; UserInterface.getBinding ( group ).setLayout ( ToolBarGroupBinding.LAYOUT_LAST ); - + this._moreActions = new List (); while (( button = hides.getNext ()) != null ) { this._moreActions.add ( button.associatedSystemAction ); } mores.show (); - + } else { this._moreActions = null; mores.hide (); @@ -346,7 +368,7 @@ SystemToolBarBinding.prototype._containAllButtons = function () { * Show more actions. */ SystemToolBarBinding.prototype._showMoreActions = function () { - + if ( this._moreActions != null ) { var popup = this.bindingWindow.bindingMap.moreactionspopup; popup.empty (); @@ -354,7 +376,7 @@ SystemToolBarBinding.prototype._showMoreActions = function () { var item = MenuItemBinding.newInstance ( popup.bindingDocument ); item.setLabel ( action.getLabel ()); item.setToolTip ( action.getToolTip ()); - item.imageProfile = new ImageProfile ({ + item.imageProfile = new ImageProfile ({ image : action.getImage (), imageDisabled : action.getDisabledImage () }); @@ -369,48 +391,20 @@ SystemToolBarBinding.prototype._showMoreActions = function () { } } -/** - * This method is mirrored by the explorer popupmenu - please coordinate changes. - * @see {SystemPopupBinding#getMenuItemBinding} - * @param {SystemAction} action - * @return {ToolBarButtonBinding} - * -SystemToolBarBinding.prototype.getPossibleButtonBinding = function ( action ) { - - this.logger.debug ( "TODO: SystemToolBarBinding.getPossibleButtonBinding" ); - - var result = null; - var binding = ButtonBinding.newInstance ( this.bindingDocument ); - var label = action.getLabel (); - var tooltip = action.getToolTip (); - var image = action.getImage (); - var isDisabled = action.isDisabled (); - var folderName = action.getFolderName (); - - if ( this._actionFolderNames [ folderName ]) { - - } else { - this._actionFolderNames [ folderName ] = SelectorBinding.newInstance ( this.bindingDocument ); - result = this._actionFolderNames [ folderName ]; - } - return result; -} -*/ - /** * This method is mirrored by the explorer popupmenu - please coordinate changes. * @see {SystemPopupBinding#getMenuItemBinding} * @param {SystemAction} action * @return {ToolBarButtonBinding} */ -SystemToolBarBinding.prototype.getToolBarButtonBinding = function ( action ) { +SystemToolBarBinding.prototype.getToolBarButtonBinding = function ( action) { var binding = ToolBarButtonBinding.newInstance ( this.bindingDocument ); var label = action.getLabel (); var tooltip = action.getToolTip (); var image = action.getImage (); var isDisabled = action.isDisabled (); - + if (image) { binding.setImage(image); } @@ -423,29 +417,31 @@ SystemToolBarBinding.prototype.getToolBarButtonBinding = function ( action ) { if ( action.isDisabled ()) { binding.disable (); } - + /* - * Stamp the action as a property on the buttonbinding + * Stamp the action as a property on the buttonbinding * so that we can retrieve it when the button is clicked. */ binding.associatedSystemAction = action; - + return binding; }; + /** - * Invoke default action. Currently, this is the action + * Invoke default action. Currently, this is the action * associated to the first toolbarbutton on display. * @return */ SystemToolBarBinding.prototype._invokeDefaultAction = function () { - + var button = this.getDescendantBindingByLocalName ( "toolbarbutton" ); if ( button != null ) { button.fireCommand (); } }; + /** * get activePosition. * @return {int} diff --git a/Website/Composite/scripts/source/top/util/Map.js b/Website/Composite/scripts/source/top/util/Map.js index 8cd5a73da5..1628346280 100644 --- a/Website/Composite/scripts/source/top/util/Map.js +++ b/Website/Composite/scripts/source/top/util/Map.js @@ -6,9 +6,9 @@ function Map ( map ) { /** * @type {HashMap - */ + */ this._map = {}; - + /* * Populate from optional constructor object. */ @@ -22,12 +22,12 @@ function Map ( map ) { Map.prototype._map = {}; /** - * Get entry. Notice that an invalid key will not be tolerated + * Get entry. Notice that an invalid key will not be tolerated * here. Always use method "has" to check for key existance first. * @param {object} key */ Map.prototype.get = function ( key ) { - + var result = null; if ( this.has ( key )) { result = this._map [ key ]; @@ -49,7 +49,7 @@ Map.prototype.get = function ( key ) { * @param {object} value */ Map.prototype.set = function ( key, value ) { - + this._map [ key ] = value; } @@ -58,7 +58,7 @@ Map.prototype.set = function ( key, value ) { * @param {object} key */ Map.prototype.del = function ( key ) { - + delete this._map [ key ]; } @@ -68,7 +68,7 @@ Map.prototype.del = function ( key ) { * @return {boolean} */ Map.prototype.has = function ( key ) { - + return typeof this._map [ key ] != "undefined"; } @@ -76,11 +76,11 @@ Map.prototype.has = function ( key ) { * Each entry. * @param {function} action */ -Map.prototype.each = function ( action ) { - +Map.prototype.each = function ( action, thisp ) { + for ( var key in this._map ) { - var isContinue = action ( - key, + var isContinue = action.call ( thisp, + key, this._map [ key ] ); if ( isContinue == false ) { @@ -94,7 +94,7 @@ Map.prototype.each = function ( action ) { * @retun {boolean} */ Map.prototype.hasEntries = function () { - + var result = false; for ( var key in this._map ) { result = true; @@ -108,7 +108,7 @@ Map.prototype.hasEntries = function () { * @retun {int} */ Map.prototype.countEntries = function () { - + var result = 0; for ( var key in this._map ) { result ++; @@ -116,12 +116,12 @@ Map.prototype.countEntries = function () { return result; } -/** +/** * Convert to list (listing keys or values). * @param {boolean} isKey */ Map.prototype.toList = function ( isKey ) { - + var list = new List (); for ( var key in this._map ) { list.add ( @@ -136,7 +136,7 @@ Map.prototype.toList = function ( isKey ) { * @return {Map} */ Map.prototype.copy = function () { - + var map = new Map (); for ( var key in this._map ) { map.set ( key, this._map [ key ]); @@ -149,7 +149,7 @@ Map.prototype.copy = function () { * @return {Map} */ Map.prototype.inverse = function () { - + var map = new Map (); for ( var key in this._map ) { map.set ( this._map [ key ], key ); @@ -161,7 +161,7 @@ Map.prototype.inverse = function () { * Empty map. */ Map.prototype.empty = function () { - + for ( var key in this._map ) { delete this._map [ key ]; } @@ -172,7 +172,7 @@ Map.prototype.empty = function () { * TODO: Invoke "dispose" on entries? */ Map.prototype.dispose = function () { - + for ( var key in this._map ) { this._map [ key ] = null; } diff --git a/Website/Composite/styles/default/buttons.less b/Website/Composite/styles/default/buttons.less index 56e40cd97c..e8dcb5a514 100644 --- a/Website/Composite/styles/default/buttons.less +++ b/Website/Composite/styles/default/buttons.less @@ -126,7 +126,7 @@ ui|toolbarbutton { margin: 0; display: block; float: left; - line-height: 28px; + line-height: 30px; font-size: 9px; padding: 0 10px; .user-select(none); From f59dba44d496595ff39300fd280d1fb12cc7236f Mon Sep 17 00:00:00 2001 From: neexite Date: Thu, 3 Mar 2016 13:08:15 +0200 Subject: [PATCH 002/133] UI: Group actions into bundle: contextmenu, behavior for one item in bunde, save latest actionhandle in storage --- .../combobutton/ToolBarComboButtonBinding.js | 31 +++- .../top/ui/bindings/menus/MenuItemBinding.js | 166 ++++++++--------- .../bindings/system/SystemToolBarBinding.js | 8 +- .../bindings/system/SystemTreePopupBinding.js | 170 ++++++++++++------ .../scripts/source/top/util/LocalStorage.js | 19 +- Website/Composite/styles/default/menus.less | 42 +++++ 6 files changed, 277 insertions(+), 159 deletions(-) diff --git a/Website/Composite/scripts/source/top/ui/bindings/buttons/combobutton/ToolBarComboButtonBinding.js b/Website/Composite/scripts/source/top/ui/bindings/buttons/combobutton/ToolBarComboButtonBinding.js index c66a6ac800..22ffca5587 100644 --- a/Website/Composite/scripts/source/top/ui/bindings/buttons/combobutton/ToolBarComboButtonBinding.js +++ b/Website/Composite/scripts/source/top/ui/bindings/buttons/combobutton/ToolBarComboButtonBinding.js @@ -3,6 +3,7 @@ ToolBarComboButtonBinding.prototype.constructor = ToolBarComboButtonBinding; ToolBarComboButtonBinding.superclass = ToolBarButtonBinding.prototype; ToolBarComboButtonBinding.CLASSNAME_COMBOBUTTON = "combobutton"; +ToolBarComboButtonBinding.STORAGE_PREFFIX = "STORAGEBUTTONHANDLE"; /** * @class @@ -72,7 +73,6 @@ ToolBarComboButtonBinding.prototype.onBindingAttach = function () { ToolBarComboButtonBinding.prototype.handleBroadcast = function (broadcast, arg) { ToolBarComboButtonBinding.superclass.handleBroadcast.call(this, broadcast, arg); - } /** @@ -108,6 +108,14 @@ ToolBarComboButtonBinding.prototype.setPopup = function (arg) { if (activeMenu != null) this.setButton(activeMenu); + + if (this.comboBoxBinding) { + if (menuitems.getLength() <= 1) { + this.comboBoxBinding.hide(); + } else { + this.comboBoxBinding.show(); + } + } } /** @@ -146,6 +154,19 @@ ToolBarComboButtonBinding.prototype.setButton = function (menuitem) { } } +ToolBarComboButtonBinding.prototype.getAssociatedSystemActions = function () { + + var result = new List(); + + this.popupBinding.getDescendantBindingsByType(MenuItemBinding).each(function(menuitem) { + if (menuitem.associatedSystemAction) { + result.add(menuitem.associatedSystemAction); + } + }); + + return result; +} + /** * Set and Fire Commmand from MenuItem * @param {MenuItemBinding} menuitem @@ -175,21 +196,19 @@ ToolBarComboButtonBinding.prototype.hideActiveItem = function (activeMenuitem) { ); } - /** * Set active menuitem handle * @param {MenuItemBinding} menuitem id */ -ToolBarComboButtonBinding.prototype.setActiveMenuHandle = function (id) { - - Cookies.createCookie(this.bundleName, id, 365); +ToolBarComboButtonBinding.prototype.setActiveMenuHandle = function (handle) { + LocalStorage.set(ToolBarComboButtonBinding.STORAGE_PREFFIX + this.bundleName, handle); } /** * Get active menuitem handle */ ToolBarComboButtonBinding.prototype.getActiveMenuHandle = function () { - return Cookies.readCookie(this.bundleName); + return LocalStorage.get(ToolBarComboButtonBinding.STORAGE_PREFFIX + this.bundleName); } ToolBarComboButtonBinding.prototype.getMenuHandle = function (menuitem) { diff --git a/Website/Composite/scripts/source/top/ui/bindings/menus/MenuItemBinding.js b/Website/Composite/scripts/source/top/ui/bindings/menus/MenuItemBinding.js index 29d19a8391..737c173a42 100644 --- a/Website/Composite/scripts/source/top/ui/bindings/menus/MenuItemBinding.js +++ b/Website/Composite/scripts/source/top/ui/bindings/menus/MenuItemBinding.js @@ -21,75 +21,80 @@ function MenuItemBinding () { * @type {SystemLogger} */ this.logger = SystemLogger.getLogger ( "MenuItemBinding" ); - + /** * @type {string} */ this.type = null; - + /** - * User can implement this. + * User can implement this. * @type {function} */ this.oncommand = null; - + /** * @type {boolean} */ this.isDisabled = false; - + /** * @type {LabelBinding} */ this.labelBinding = null; - + /** * @type {string} */ this.image = null; - + /** * @type {string} */ this.imageHover = null; - + /** * @type {string} */ this.imageActive = null; - + /** * @type {string} */ this.imageDisabled = null; - + /**setDisabled */ this.imageProfile = null; - + /** * @type {boolean} */ this.isMenuContainer = false; - + + /** + * @type {boolean} + */ + this.hasAction = true; + /** * @type {boolean} */ this.isTypeSet = false; - + /** * @type {boolean} */ this.isChecked = false; - + /** * Flipped by either mouse or keyboard navigation. * @type {boolean} */ this.isFocused = false; - + /** - * The containing menubody handles blur whenever a new item is focused. + * The containing menubody handles blur whenever a new item is focused. * This is done by direct method invokation because of maxed performance. * @type {MenuBodyBinding} */ @@ -100,7 +105,7 @@ function MenuItemBinding () { * Identifies binding. */ MenuItemBinding.prototype.toString = function () { - + return "[MenuItemBinding]"; } @@ -122,26 +127,26 @@ MenuItemBinding.prototype.onBindingRegister = function () { MenuItemBinding.prototype.onBindingAttach = function () { MenuItemBinding.superclass.onBindingAttach.call ( this ); - + /* - * Locate menubody and set a dirty flag. This + * Locate menubody and set a dirty flag. This * will force menubody to reindex menuitems. */ this._containingMenuBodyBinding = this.getAncestorBindingByLocalName ( "menubody" ); this._containingMenuBodyBinding.isDirty = true; - + /* * Build. */ this.parseDOMProperties (); this.buildDOMContent (); this.assignDOMEvents (); - + /** * Intercepted by PopupBinding in order to control overflow. */ this.dispatchAction ( Binding.ACTION_ATTACHED ); - + } @@ -155,7 +160,7 @@ MenuItemBinding.prototype.parseDOMProperties = function () { var imageHover = this.getProperty ( "image-hover" ); var imageActive = this.getProperty ( "image-active" ); var imageDisabled = this.getProperty ( "image-disabled" ); - + if ( !this.image && image ) { this.image = image; } @@ -182,22 +187,24 @@ MenuItemBinding.prototype.buildDOMContent = function () { var image = this.getProperty ( "image" ); var imageHover = this.getProperty ( "image-hover" ); var imageActive = this.getProperty ( "image-active" ); - var imageDisabled = this.getProperty ( "image-disabled" ); + var imageDisabled = this.getProperty("image-disabled"); + var hasAction = this.getProperty("hasaction"); this.labelBinding = LabelBinding.newInstance ( this.bindingDocument ); this.labelBinding.attachClassName ( "menuitemlabel" ); this.add ( this.labelBinding ); - + // assign menupopup var menuPopup = this.getMenuPopupBinding (); if ( menuPopup ) { this.isMenuContainer = true; this.setType ( MenuItemBinding.TYPE_MENUCONTAINER ); + this.hasAction = hasAction === true; } - + // compute image profile if ( !this.imageProfile ) { - + if ( !this.image && image ) { this.image = image; } @@ -214,14 +221,14 @@ MenuItemBinding.prototype.buildDOMContent = function () { this.imageProfile = new ImageProfile ( this ); } } - + if ( this.imageProfile ) { this.setImage ( this.imageProfile.getDefaultImage ()); /*this._containingMenuBodyBinding.invokeImageLayout ();*/ } else { this.setImage ( null ); } - + if ( label != null ) { this.setLabel ( label ); } @@ -239,38 +246,23 @@ MenuItemBinding.prototype.buildDOMContent = function () { if ( disabled == true ) { this.disable (); } - + /* * Setup command */ var oncommand = this.getProperty ( "oncommand" ); if ( oncommand ) { - if ( this.isMenuContainer ) { - throw new Error ( "MenuItemBinding with contained menuitems cannot fire commands." ); - } else { - this.oncommand = function () { - this.bindingWindow.eval ( oncommand ); - } + this.oncommand = function () { + this.bindingWindow.eval ( oncommand ); } } - - /* - * So that scrollbarred menus can be keyboard navigated. - * The tabIndex is set to zero when containing popup opens. - * @see {PopupBinding#show} - * - this.bindingElement.tabIndex = -1; - if ( Client.isExplorer ) { - this.bindingElement.hideFocus = true; - } - */ } /** * Assign DOM events. */ MenuItemBinding.prototype.assignDOMEvents = function () { - + /* * Rebember that menubody handles blur! */ @@ -286,18 +278,18 @@ MenuItemBinding.prototype.assignDOMEvents = function () { MenuItemBinding.prototype.handleEvent = function ( e ) { MenuItemBinding.superclass.handleEvent.call ( this, e ); - + if ( !this.isDisabled && !BindingDragger.isDragging ) { - + switch ( e.type ) { - + case DOMEvents.MOUSEOVER : this.focus ( e ); break; - + case DOMEvents.MOUSEUP : DOMEvents.stopPropagation ( e ); - if ( !this.isMenuContainer ) { + if (this.hasAction) { if ( this.type == MenuItemBinding.TYPE_CHECKBOX ) { this.setChecked ( !this.isChecked ); } else { @@ -306,8 +298,8 @@ MenuItemBinding.prototype.handleEvent = function ( e ) { EventBroadcaster.broadcast( BroadcastMessages.MOUSEEVENT_MOUSEDOWN, this ); - EventBroadcaster.broadcast ( - BroadcastMessages.MOUSEEVENT_MOUSEUP, this + EventBroadcaster.broadcast ( + BroadcastMessages.MOUSEEVENT_MOUSEUP, this ); } break; @@ -319,8 +311,8 @@ MenuItemBinding.prototype.handleEvent = function ( e ) { * Fire command. */ MenuItemBinding.prototype.fireCommand = function () { - - if ( !this.isMenuContainer ) { + + if ( this.hasAction ) { if ( this.oncommand ) { // TODO: Timeout to close first? Animation.DEFAULT_TIMEOUT? this.oncommand (); @@ -339,7 +331,7 @@ MenuItemBinding.prototype.setImage = function ( url ) { url = url ? url : LabelBinding.DEFAULT_IMAGE; this.setProperty ( "image", url ); if ( this.isAttached ) { - this.labelBinding.setImage ( + this.labelBinding.setImage ( url ); } @@ -367,14 +359,14 @@ MenuItemBinding.prototype.setToolTip = function ( tooltip ) { this.setProperty ( "tooltip", tooltip ); if ( this.isAttached ) { - this.labelBinding.setToolTip ( + this.labelBinding.setToolTip ( Resolver.resolve ( tooltip ) ); } } /** - * Reset visual appearance when menus are closed. + * Reset visual appearance when menus are closed. */ MenuItemBinding.prototype.reset = function () { @@ -388,17 +380,17 @@ MenuItemBinding.prototype.reset = function () { * @param {string} type */ MenuItemBinding.prototype.setType = function ( type ) { - + if ( this.isAttached ) { if ( !this.isTypeSet ) { switch ( type ) { case MenuItemBinding.TYPE_CHECKBOX : - - if ( !this.isMenuContainer ) { - + + if ( this.hasAction ) { + // update container appearance this._containingMenuBodyBinding.invokeCheckBoxLayout (); - + // append checkbox symbol var element = this.bindingDocument.createElement ( "div" ); element.className = MenuItemBinding.CLASSNAME_CHECKBOX; @@ -407,14 +399,14 @@ MenuItemBinding.prototype.setType = function ( type ) { label.insertBefore ( element, label.firstChild ); element.style.display = "none"; this.shadowTree.checkBoxIndicator = element; - + } else { throw new Error ( "MenuItemBinding: checkboxes cannot contain menus" ); } break; - + case MenuItemBinding.TYPE_MENUCONTAINER : - + // append arrow symbol var element = this.bindingDocument.createElement ( "div" ); element.className = MenuItemBinding.CLASSNAME_SUBMENU; @@ -423,15 +415,15 @@ MenuItemBinding.prototype.setType = function ( type ) { label.insertBefore ( element, label.firstChild ); break; } - + this.type = type; this.isTypeSet = true; - + } else { throw new Error ( "MenuItemBinding: Cannot set type twice." ); } } - + this.setProperty ( "type", type ); } @@ -484,15 +476,15 @@ MenuItemBinding.prototype.enable = function () { * @param {boolean} bool */ MenuItemBinding.prototype.setDisabled = function ( bool ) { - + this.isDisabled = bool; - + if ( this.isDisabled ) { this.setProperty ( "isdisabled", true ); } else { this.deleteProperty ( "isdisabled" ); - } - + } + if ( this.isAttached ) { if ( this.isDisabled ) { this.labelBinding.detachClassName ( "hover" ); @@ -520,23 +512,23 @@ MenuItemBinding.prototype.setDisabled = function ( bool ) { * @param {MouseEvent} e */ MenuItemBinding.prototype.focus = function ( e ) { - + /* * Notice that only the label gets a classname assigned here! */ this.labelBinding.attachClassName ( MenuItemBinding.CLASSNAME_HOVER ); - + var container = this.getMenuContainerBinding (); if ( container.isOpen () && !container.isOpen ( this )) { container._openElement.hide (); container.setOpenElement ( false ); } - + /* * Open submenu after short timeout (when mouse-navigating). */ if ( this.isMenuContainer && e && e.type == DOMEvents.MOUSEOVER ) { - var container = this.getMenuContainerBinding (); + var container = this.getMenuContainerBinding (); if ( !container.isOpen ( this )) { var self = this; this._showSubMenuTimeout = window.setTimeout ( function () { @@ -545,7 +537,7 @@ MenuItemBinding.prototype.focus = function ( e ) { }, MenuItemBinding.TIMEOUT ); }; } - + /** * When keyboard navigating, this will adjust any visible scrollbar. */ @@ -561,7 +553,7 @@ MenuItemBinding.prototype.focus = function ( e ) { } } } - + this.isFocused = true; this._containingMenuBodyBinding.handleFocusedItem ( this ); } @@ -571,7 +563,7 @@ MenuItemBinding.prototype.focus = function ( e ) { * @param {boolean} isForceBlur */ MenuItemBinding.prototype.blur = function ( isForceBlur ) { - + /* * Clear submenu timeout. */ @@ -579,7 +571,7 @@ MenuItemBinding.prototype.blur = function ( isForceBlur ) { window.clearTimeout ( this._showSubMenuTimeout ); this._showSubMenuTimeout = null; } - + if ( this.isFocused ) { var container = this.getMenuContainerBinding (); if ( !container || !container.isOpen ( this ) || isForceBlur ) { @@ -595,7 +587,7 @@ MenuItemBinding.prototype.blur = function ( isForceBlur ) { * @param {boolean} isPreventCommand */ MenuItemBinding.prototype.check = function ( isPreventCommand ) { - + this.setChecked ( true, isPreventCommand ); } @@ -613,7 +605,7 @@ MenuItemBinding.prototype.uncheck = function ( isPreventCommand ) { * @overloads {MenuContainerBinding#show} */ MenuItemBinding.prototype.show = function () { - + this.menuPopupBinding.position = PopupBinding.POSITION_RIGHT; MenuItemBinding.superclass.show.call ( this ); } @@ -624,13 +616,13 @@ MenuItemBinding.prototype.show = function () { * @param {boolean} isPreventCommand */ MenuItemBinding.prototype.setChecked = function ( isChecked, isPreventCommand ) { - + this.setProperty ( "ischecked", isChecked ); if ( this.isAttached ) { if ( this.type == MenuItemBinding.TYPE_CHECKBOX ) { if ( this.isChecked != isChecked ) { this.isChecked = isChecked; - this.shadowTree.checkBoxIndicator.style.display = + this.shadowTree.checkBoxIndicator.style.display = isChecked ? "block" : "none"; if ( !isPreventCommand ) { this.fireCommand (); diff --git a/Website/Composite/scripts/source/top/ui/bindings/system/SystemToolBarBinding.js b/Website/Composite/scripts/source/top/ui/bindings/system/SystemToolBarBinding.js index fb98145ea3..c94edae49c 100644 --- a/Website/Composite/scripts/source/top/ui/bindings/system/SystemToolBarBinding.js +++ b/Website/Composite/scripts/source/top/ui/bindings/system/SystemToolBarBinding.js @@ -354,7 +354,13 @@ SystemToolBarBinding.prototype._containAllButtons = function () { this._moreActions = new List (); while (( button = hides.getNext ()) != null ) { - this._moreActions.add ( button.associatedSystemAction ); + if (button instanceof ToolBarComboButtonBinding) { + button.getAssociatedSystemActions().each(function(associatedSystemAction) { + this._moreActions.add(associatedSystemAction); + }, this); + } else { + this._moreActions.add(button.associatedSystemAction); + } } mores.show (); diff --git a/Website/Composite/scripts/source/top/ui/bindings/system/SystemTreePopupBinding.js b/Website/Composite/scripts/source/top/ui/bindings/system/SystemTreePopupBinding.js index 4fbc6b00fb..7bb8c2301b 100644 --- a/Website/Composite/scripts/source/top/ui/bindings/system/SystemTreePopupBinding.js +++ b/Website/Composite/scripts/source/top/ui/bindings/system/SystemTreePopupBinding.js @@ -14,7 +14,7 @@ SystemTreePopupBinding.isCutAllowed = false; SystemTreePopupBinding.isRefreshAllowed = true; -/** +/** * @class */ function SystemTreePopupBinding () { @@ -23,12 +23,12 @@ function SystemTreePopupBinding () { * @type {SystemLogger} */ this.logger = SystemLogger.getLogger ( "SystemTreePopupBinding" ); - + /** * @type {string} */ this._currentProfileKey = null; - + /** * @type {object} */ @@ -38,7 +38,7 @@ function SystemTreePopupBinding () { * @type {SystemNode} */ this._node = null; - + /** * @type {TreeNodeBinding} */ @@ -72,7 +72,7 @@ SystemTreePopupBinding.prototype.onBindingAttach = function () { SystemTreePopupBinding.prototype.handleBroadcast = function ( broadcast, arg ) { SystemTreePopupBinding.superclass.handleBroadcast.call ( this, broadcast, arg ); - + switch ( broadcast ) { case BroadcastMessages.SYSTEM_ACTIONPROFILE_PUBLISHED : if (arg != null && arg.actionProfile != null) { @@ -96,21 +96,21 @@ SystemTreePopupBinding.prototype._getProfileKey = SystemToolBarBinding.prototype * @overloads {PopupBinding#show} */ SystemTreePopupBinding.prototype.show = function () { - + /* * Build content */ var key = this._getProfileKey (); - + if ( key != this._currentProfileKey ) { this.disposeContent (); this.constructContent (); this._currentProfileKey = key; } - + this._setupClipboardItems (); this._setupRefreshItem (); - + /* * Show. */ @@ -121,11 +121,11 @@ SystemTreePopupBinding.prototype.show = function () { * Setup clipboard operation menuitems. */ SystemTreePopupBinding.prototype._setupClipboardItems = function () { - + var cut = this.getMenuItemForCommand ( SystemTreePopupBinding.CMD_CUT ); var copy = this.getMenuItemForCommand ( SystemTreePopupBinding.CMD_COPY ); var paste = this.getMenuItemForCommand ( SystemTreePopupBinding.CMD_PASTE ); - + cut.setDisabled ( !SystemTreePopupBinding.isCutAllowed ); copy.setDisabled ( !SystemTreePopupBinding.isCutAllowed ); paste.setDisabled ( SystemTreeBinding.clipboard == null ); @@ -150,20 +150,15 @@ SystemTreePopupBinding.prototype.handleAction = function ( action ) { SystemTreePopupBinding.superclass.handleAction.call ( this, action ) switch ( action.type ) { - + /* * Note to self: The first part is duplicated by SystemToolBarBinding! */ case MenuItemBinding.ACTION_COMMAND : var menuitemBinding = action.target; var systemAction = menuitemBinding.associatedSystemAction; + var bundleName = systemAction.getBundleName(); if ( systemAction ) { - //var list = ExplorerBinding.getFocusedTreeNodeBindings (); - //if ( list.hasEntries ()) { - // var treeNodeBinding = list.getFirst (); - // var systemNode = treeNodeBinding.node; - //} - //SystemAction.invoke ( systemAction, systemNode ); SystemAction.invoke(systemAction, this._node); } else { var cmd = menuitemBinding.getProperty ( "cmd" ); @@ -172,8 +167,12 @@ SystemTreePopupBinding.prototype.handleAction = function ( action ) { } } + if (systemAction && bundleName) { + LocalStorage.set(ToolBarComboButtonBinding.STORAGE_PREFFIX + bundleName, systemAction.getHandle()); + } + // Clean current profile key - this._currentProfileKey = null + this._currentProfileKey = null; break; } } @@ -183,9 +182,9 @@ SystemTreePopupBinding.prototype.handleAction = function ( action ) { * @param {string} cmd */ SystemTreePopupBinding.prototype._handleCommand = function ( cmd ) { - + var broadcast = null; - + switch ( cmd ) { case SystemTreePopupBinding.CMD_CUT : broadcast = BroadcastMessages.SYSTEMTREEBINDING_CUT; @@ -200,7 +199,7 @@ SystemTreePopupBinding.prototype._handleCommand = function ( cmd ) { broadcast = BroadcastMessages.SYSTEMTREEBINDING_REFRESH; break; } - + if ( broadcast ) { // allows the popup to close setTimeout ( function () { EventBroadcaster.broadcast ( broadcast ); @@ -213,9 +212,9 @@ SystemTreePopupBinding.prototype._handleCommand = function ( cmd ) { */ SystemTreePopupBinding.prototype.disposeContent = function () { - var members = new List ( + var members = new List ( DOMUtil.getElementsByTagName ( this.bindingElement, "menugroup" ) - ); + ).reverse(); while ( members.hasNext ()) { var binding = UserInterface.getBinding ( members.getNext ()); if ( !binding.getProperty ( "rel" )) { @@ -228,22 +227,53 @@ SystemTreePopupBinding.prototype.disposeContent = function () { * Construct content. */ SystemTreePopupBinding.prototype.constructContent = function () { - + if ( this._actionProfile != null ) { - + var doc = this.bindingDocument; var groups = new List (); var self = this; - + + var bundles = new Map(); + this._actionProfile.each ( function ( group, list ) { var groupBinding = MenuGroupBinding.newInstance ( doc ); list.each ( function ( action ) { - var menuItemBinding = self.getMenuItemBinding ( action ); - groupBinding.add ( menuItemBinding ); + + var menuItemBinding = self.getMenuItemBinding(action); + + var bundleName = action.getBundleName(); + if (bundleName) { + if (bundles.has(bundleName)) { + + var bundleMenuItemBinding = bundles.get(bundleName); + if (bundleMenuItemBinding.getChildBindingByType(MenuPopupBinding) == null) { + bundleMenuItemBinding.setProperty("hasaction", true); + var popup = MenuPopupBinding.newInstance(doc); + var body = popup.add(MenuBodyBinding.newInstance(doc)); + var group = body.add(MenuGroupBinding.newInstance(doc)); + bundleMenuItemBinding.add(popup); + group.add(self.getMenuItemBinding(bundleMenuItemBinding.associatedSystemAction)); + } + var bundleGroupMenuBinding = bundleMenuItemBinding.getDescendantBindingByType(MenuGroupBinding); + if (bundleGroupMenuBinding) { + bundleGroupMenuBinding.add(menuItemBinding); + } + } else { + groupBinding.add(menuItemBinding); + bundles.set(bundleName, menuItemBinding); + } + + } else { + + groupBinding.add(menuItemBinding); + } + + }); groups.add ( groupBinding ); }); - + /* * Build in reverse order, so that clipboardoperations appear last. * Remember that clipboard menuitems has been hardcoded into menu. @@ -252,7 +282,25 @@ SystemTreePopupBinding.prototype.constructContent = function () { while ( groups.hasNext ()) { this._bodyBinding.addFirst ( groups.getNext ()); } - this._bodyBinding.attachRecursive (); + this._bodyBinding.attachRecursive(); + + bundles.each(function (bundleName, bundleMenuItemBinding) { + if (bundleMenuItemBinding.isMenuContainer) { + var bundleMenuItemsBinding = bundleMenuItemBinding.getDescendantBindingsByType(MenuItemBinding); + var latestBundleMenuItem = bundleMenuItemsBinding.getFirst(); + var latestBundleHandle = LocalStorage.get(ToolBarComboButtonBinding.STORAGE_PREFFIX + bundleName); + bundleMenuItemsBinding.each(function (menuItemBinding) { + if (menuItemBinding.associatedSystemAction && menuItemBinding.associatedSystemAction.getHandle() === latestBundleHandle) { + latestBundleMenuItem = menuItemBinding; + return false; + } + return true; + }); + + this.setSystemAction(bundleMenuItemBinding, latestBundleMenuItem.associatedSystemAction); + Binding.prototype.hide.call(latestBundleMenuItem); + } + }, this); } } @@ -262,43 +310,47 @@ SystemTreePopupBinding.prototype.constructContent = function () { * @return {MenuItemBinding} */ SystemTreePopupBinding.prototype.getMenuItemBinding = function ( action ) { - + var binding = MenuItemBinding.newInstance ( this.bindingDocument ); - var label = action.getLabel (); - var tooltip = action.getToolTip (); - var image = action.getImage (); - var ximage = action.getDisabledImage (); - var isCheckbox = action.isCheckBox (); - - if ( label ) { - binding.setLabel ( label ); + SystemTreePopupBinding.prototype.setSystemAction.call(this, binding, action); + + return binding; +} + +SystemTreePopupBinding.prototype.setSystemAction = function (binding, action) { + var label = action.getLabel(); + var tooltip = action.getToolTip(); + var image = action.getImage(); + var ximage = action.getDisabledImage(); + var isCheckbox = action.isCheckBox(); + + if (label) { + binding.setLabel(label); } - if ( tooltip ) { - binding.setToolTip ( tooltip ); + if (tooltip) { + binding.setToolTip(tooltip); } - if ( image ) { - binding.imageProfile = new ImageProfile ({ - image : image, - imageDisabled : ximage + if (image) { + binding.imageProfile = new ImageProfile({ + image: image, + imageDisabled: ximage }); } - if ( isCheckbox ) { - binding.setType ( MenuItemBinding.TYPE_CHECKBOX ); - if ( action.isChecked ()) { - binding.check ( true ); + if (isCheckbox) { + binding.setType(MenuItemBinding.TYPE_CHECKBOX); + if (action.isChecked()) { + binding.check(true); } } - if ( action.isDisabled ()) { - binding.disable (); + if (action.isDisabled()) { + binding.disable(); } - + /* * Stamp the action as a property on the menuitem * so that we can retrieve it when the item is clicked. */ binding.associatedSystemAction = action; - - return binding; } /** @@ -310,7 +362,7 @@ SystemTreePopupBinding.prototype.snapToMouse = function ( e ) { var node = e.target ? e.target : e.srcElement; var name = DOMUtil.getLocalName ( node ); var binding = null; - + if ( name != "tree" ) { switch ( name ) { case "treenode" : @@ -327,9 +379,9 @@ SystemTreePopupBinding.prototype.snapToMouse = function ( e ) { break; } if ( binding != null && binding.node != null && binding.node.getActionProfile () != null ) { - + /* - * This timeout will allow a right-click to focus the treenode, + * This timeout will allow a right-click to focus the treenode, * triggering a NEW action profile publish, before we show the menu. * OOPS: Internet Explorer looses track of the e argument... what to do? * @@ -338,7 +390,7 @@ SystemTreePopupBinding.prototype.snapToMouse = function ( e ) { SystemTreePopupBinding.superclass.snapToMouse.call ( self, e ); }, 0 ); */ - + SystemTreePopupBinding.superclass.snapToMouse.call ( this, e ); } } diff --git a/Website/Composite/scripts/source/top/util/LocalStorage.js b/Website/Composite/scripts/source/top/util/LocalStorage.js index 4026d02f89..eaafe2167e 100644 --- a/Website/Composite/scripts/source/top/util/LocalStorage.js +++ b/Website/Composite/scripts/source/top/util/LocalStorage.js @@ -5,31 +5,38 @@ function _LocalStorage() { } _LocalStorage.prototype = { - store_data: function (data, key) { + set: function (key, data) { if (!window.localStorage || !window.JSON || !key) { return; } localStorage.setItem(key, JSON.stringify(data)); }, - get_data: function (key) { + get: function (key) { if (!window.localStorage || !window.JSON || !key) { - return; + return undefined; } var item = localStorage.getItem(key); if (!item) { - return; + return undefined; } return JSON.parse(item); }, - remove_data: function (key) { + remove: function (key) { if (!window.localStorage || !window.JSON || !key) { return; } localStorage.removeItem(key); - } + }, + + //Obsolute + store_data: function(data, key) { this.set(key, data) }, + //Obsolute + get_data: function (key) { return this.get(key)}, + //Obsolute + remove_data: function(key) { this.remove(key)} } diff --git a/Website/Composite/styles/default/menus.less b/Website/Composite/styles/default/menus.less index 057e624bc9..d28fc6f240 100644 --- a/Website/Composite/styles/default/menus.less +++ b/Website/Composite/styles/default/menus.less @@ -167,6 +167,48 @@ ui|menuitem { display: none; } + &[type="menucontainer"] { + > .menuitemlabel{ + &:before, &:after { + content: ""; + position: absolute; + width: 0; + height: 0; + border-style: solid; + } + + &:before { + top: 12px; + right: 10px; + border-width: 5px 0 5px 5px; + border-color: transparent transparent transparent @primary-color; + } + + &:after { + top: 13px; + right: 11px; + border-width: 4px 0 4px 4px; + border-color: transparent transparent transparent #fff; + } + + &.hover{ + &:before { + top: 12px; + right: 10px; + border-width: 5px 5px 5px 0; + border-color: transparent #fff transparent transparent; + } + + &:after { + top: 13px; + right: 10px; + border-width: 4px 4px 4px 0; + border-color: transparent @primary-color transparent transparent; + } + } + } + } + ui|menupopup { margin-top: -2px; margin-left: -2px; From 974a0b6051dbb633f81897074d74bebb16ca87d6 Mon Sep 17 00:00:00 2001 From: neexite Date: Fri, 4 Mar 2016 17:00:45 +0200 Subject: [PATCH 003/133] Grouping buttons and menu items into the bundle: behavior for disabled buttons --- .../combobutton/ToolBarComboButtonBinding.js | 76 ++++++++++--------- .../bindings/system/SystemToolBarBinding.js | 14 +--- .../bindings/system/SystemTreePopupBinding.js | 23 +++++- 3 files changed, 65 insertions(+), 48 deletions(-) diff --git a/Website/Composite/scripts/source/top/ui/bindings/buttons/combobutton/ToolBarComboButtonBinding.js b/Website/Composite/scripts/source/top/ui/bindings/buttons/combobutton/ToolBarComboButtonBinding.js index 22ffca5587..c9a81ee245 100644 --- a/Website/Composite/scripts/source/top/ui/bindings/buttons/combobutton/ToolBarComboButtonBinding.js +++ b/Website/Composite/scripts/source/top/ui/bindings/buttons/combobutton/ToolBarComboButtonBinding.js @@ -82,35 +82,45 @@ ToolBarComboButtonBinding.prototype.handleBroadcast = function (broadcast, arg) ToolBarComboButtonBinding.prototype.setPopup = function (arg) { ToolBarComboButtonBinding.superclass.setPopup.call(this, arg); + var self = this; - var menuitems = this.popupBinding.getDescendantBindingsByType(MenuItemBinding); - menuitems.each( - function (menuitem) { - var hiddenCommand = menuitem.getProperty("oncommand"); - menuitem.setProperty("hiddencommand", hiddenCommand); - menuitem.deleteProperty("oncommand"); - menuitem.oncommand = function () { + var menuItemBindings = this.popupBinding.getDescendantBindingsByType(MenuItemBinding); + menuItemBindings.each( + function (menuItemBinding) { + var hiddenCommand = menuItemBinding.getProperty("oncommand"); + menuItemBinding.setProperty("hiddencommand", hiddenCommand); + menuItemBinding.deleteProperty("oncommand"); + menuItemBinding.oncommand = function () { self.setAndFireButton(this); }; - } + }, this ); - var activeMenu = menuitems.hasEntries() ? menuitems.getFirst() : null ; - var activeMenuHandle = this.getActiveMenuHandle(); - - menuitems.reset(); - while (menuitems.hasNext()) { - var menuitem = menuitems.getNext(); - if (this.getMenuHandle(menuitem) === activeMenuHandle) { - activeMenu = menuitem; - break; + var latestMenuItemBinding = null; + var latestMenuItemHandle = this.getActiveMenuHandle(); + + menuItemBindings.each(function (menuItemBinding) { + if (this.getMenuHandle(menuItemBinding) === latestMenuItemHandle && !menuItemBinding.isDisabled) { + latestMenuItemBinding = menuItemBinding; + return false; } + return true; + }, this); + + if (latestMenuItemBinding == null) { + menuItemBindings.each(function (menuItemBinding) { + if (!menuItemBinding.isDisabled) { + latestMenuItemBinding = menuItemBinding; + return false; + } + return true; + }, this); } - if (activeMenu != null) - this.setButton(activeMenu); + if (latestMenuItemBinding != null) + this.setButton(latestMenuItemBinding); if (this.comboBoxBinding) { - if (menuitems.getLength() <= 1) { + if (menuItemBindings.getLength() <= 1) { this.comboBoxBinding.hide(); } else { this.comboBoxBinding.show(); @@ -127,24 +137,20 @@ ToolBarComboButtonBinding.prototype.setButton = function (menuitem) { if (menuitem instanceof MenuItemBinding) { var label = menuitem.getProperty("label"); var image = menuitem.getProperty("image"); - var imageHover = menuitem.getProperty("image-hover"); - var imageActive = menuitem.getProperty("image-active"); - var imageDisabled = menuitem.getProperty("image-disabled"); var hiddenCommand = menuitem.getProperty("hiddencommand"); - this.setLabel(label ? label : ""); - this.image = image; - this.imageHover = image; - this.imageActive = imageActive; - this.imageDisabled = imageDisabled; - this.imageProfile = new ImageProfile(this); - this._stateManager.imageProfile = this.imageProfile; - - this.setImage(this.imageProfile.getDefaultImage()); + this.setImage(image); + if (!this.isDisabled && menuitem.isDisabled) { + this.setDisabled(true); + } else if (this.isDisabled && !menuitem.isDisabled) { + this.setDisabled(false); + } - this.associatedSystemAction = menuitem.associatedSystemAction; + if (menuitem.associatedSystemAction) { + this.associatedSystemAction = menuitem.associatedSystemAction; + } this.oncommand = function () { Binding.evaluate(hiddenCommand, this); @@ -175,7 +181,7 @@ ToolBarComboButtonBinding.prototype.setAndFireButton = function (menuitem) { if (menuitem instanceof MenuItemBinding) { this.setButton(menuitem); - this.setActiveMenuHandle(this.getMenuHandle(menuitem)); + this.saveActiveMenuHandle(this.getMenuHandle(menuitem)); this.fireCommand(); } } @@ -200,7 +206,7 @@ ToolBarComboButtonBinding.prototype.hideActiveItem = function (activeMenuitem) { * Set active menuitem handle * @param {MenuItemBinding} menuitem id */ -ToolBarComboButtonBinding.prototype.setActiveMenuHandle = function (handle) { +ToolBarComboButtonBinding.prototype.saveActiveMenuHandle = function (handle) { LocalStorage.set(ToolBarComboButtonBinding.STORAGE_PREFFIX + this.bundleName, handle); } diff --git a/Website/Composite/scripts/source/top/ui/bindings/system/SystemToolBarBinding.js b/Website/Composite/scripts/source/top/ui/bindings/system/SystemToolBarBinding.js index c94edae49c..d546562865 100644 --- a/Website/Composite/scripts/source/top/ui/bindings/system/SystemToolBarBinding.js +++ b/Website/Composite/scripts/source/top/ui/bindings/system/SystemToolBarBinding.js @@ -379,17 +379,9 @@ SystemToolBarBinding.prototype._showMoreActions = function () { var popup = this.bindingWindow.bindingMap.moreactionspopup; popup.empty (); while (( action = this._moreActions.getNext ()) != null ) { - var item = MenuItemBinding.newInstance ( popup.bindingDocument ); - item.setLabel ( action.getLabel ()); - item.setToolTip ( action.getToolTip ()); - item.imageProfile = new ImageProfile ({ - image : action.getImage (), - imageDisabled : action.getDisabledImage () - }); - if ( action.isDisabled ()) { - item.disable (); - } - item.associatedSystemAction = action; + var item = MenuItemBinding.newInstance(popup.bindingDocument); + + SystemTreePopupBinding.prototype.setSystemAction.call(this, item, action); popup.add ( item ); } popup.attachRecursive (); diff --git a/Website/Composite/scripts/source/top/ui/bindings/system/SystemTreePopupBinding.js b/Website/Composite/scripts/source/top/ui/bindings/system/SystemTreePopupBinding.js index 7bb8c2301b..21ead1d91a 100644 --- a/Website/Composite/scripts/source/top/ui/bindings/system/SystemTreePopupBinding.js +++ b/Website/Composite/scripts/source/top/ui/bindings/system/SystemTreePopupBinding.js @@ -287,16 +287,31 @@ SystemTreePopupBinding.prototype.constructContent = function () { bundles.each(function (bundleName, bundleMenuItemBinding) { if (bundleMenuItemBinding.isMenuContainer) { var bundleMenuItemsBinding = bundleMenuItemBinding.getDescendantBindingsByType(MenuItemBinding); - var latestBundleMenuItem = bundleMenuItemsBinding.getFirst(); + var latestBundleMenuItem = null; + var latestBundleHandle = LocalStorage.get(ToolBarComboButtonBinding.STORAGE_PREFFIX + bundleName); bundleMenuItemsBinding.each(function (menuItemBinding) { - if (menuItemBinding.associatedSystemAction && menuItemBinding.associatedSystemAction.getHandle() === latestBundleHandle) { + if (menuItemBinding.associatedSystemAction && menuItemBinding.associatedSystemAction.getHandle() === latestBundleHandle && !menuItemBinding.isDisabled) { latestBundleMenuItem = menuItemBinding; return false; } return true; }); + if (latestBundleMenuItem == null) { + bundleMenuItemsBinding.each(function(menuItemBinding) { + if (!menuItemBinding.isDisabled) { + latestBundleMenuItem = menuItemBinding; + return false; + } + return true; + }); + } + + if (latestBundleMenuItem == null) { + latestBundleMenuItem = bundleMenuItemsBinding.getFirst(); + } + this.setSystemAction(bundleMenuItemBinding, latestBundleMenuItem.associatedSystemAction); Binding.prototype.hide.call(latestBundleMenuItem); } @@ -340,10 +355,14 @@ SystemTreePopupBinding.prototype.setSystemAction = function (binding, action) { binding.setType(MenuItemBinding.TYPE_CHECKBOX); if (action.isChecked()) { binding.check(true); + } else { + binding.check(false); } } if (action.isDisabled()) { binding.disable(); + } else if(binding.isDisabled) { + binding.enable(); } /* From 79cb361c87089e40a542ebb71e393dd871c5d217 Mon Sep 17 00:00:00 2001 From: Dmitry Dzygin Date: Tue, 8 Mar 2016 14:53:50 +0100 Subject: [PATCH 004/133] Fixing exception handling in workflow related code --- .../Workflow/FilePersistenceService.cs | 461 +++++++++--------- 1 file changed, 234 insertions(+), 227 deletions(-) diff --git a/Composite/C1Console/Workflow/FilePersistenceService.cs b/Composite/C1Console/Workflow/FilePersistenceService.cs index cb35e1cc3c..91b52a3e6a 100644 --- a/Composite/C1Console/Workflow/FilePersistenceService.cs +++ b/Composite/C1Console/Workflow/FilePersistenceService.cs @@ -1,227 +1,234 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Runtime.Serialization; -using System.Runtime.Serialization.Formatters.Binary; -using System.Workflow.ComponentModel; -using System.Workflow.ComponentModel.Serialization; -using System.Workflow.Runtime.Hosting; -using Composite.Core; -using Composite.Core.IO; -using Composite.Core.Logging; -using Composite.Core.Types; - - -namespace Composite.C1Console.Workflow -{ - internal class FileWorkflowPersistenceService : WorkflowPersistenceService - { - private static readonly string LogTitle = "Workflow File Persisting Service"; - private readonly string _baseDirectory; - private Guid[] _abortedWorkflows; - private readonly object _syncRoot = new object(); - - - public FileWorkflowPersistenceService(string baseDirectory) - { - _baseDirectory = baseDirectory; - this.PersistAll = false; - } - - - - public bool PersistAll { get; set; } - - public IEnumerable GetAbortedWorkflows() - { - return _abortedWorkflows ?? new Guid[0]; - } - - public IEnumerable GetPersistedWorkflows() - { - foreach (string filePath in C1Directory.GetFiles(_baseDirectory, "*.bin")) - { - string guidString = Path.GetFileNameWithoutExtension(filePath); - - Guid guid = Guid.Empty; - try - { - guid = new Guid(guidString); - } - catch { } - - if (guid != Guid.Empty) - { - yield return guid; - } - } - } - - - - public bool RemovePersistedWorkflow(Guid instanceId) - { - string filename = GetFileName(instanceId); - - if (C1File.Exists(filename)) - { - try - { - C1File.Delete(filename); - - Log.LogVerbose(LogTitle, $"Workflow persisted state deleted. Id = {instanceId}"); - } - catch - { - return false; - } - } - - return true; - } - - - - protected override Activity LoadCompletedContextActivity(Guid scopeId, Activity outerActivity) - { - object obj = DeserializeActivity(outerActivity, scopeId); - return (Activity)obj; - } - - - - protected override Activity LoadWorkflowInstanceState(Guid instanceId) - { - string filename = GetFileName(instanceId); - bool deleteFile = false; - - if (C1File.Exists(filename)) - { - try - { - object obj = DeserializeActivity(null, instanceId); - return (Activity)obj; - } - catch (Exception ex) - { - LoggingService.LogCritical(LogTitle, ex); - deleteFile = true; - } - } - - if (deleteFile) - { - Log.LogWarning(LogTitle, $"Failed to load workflow with id '{filename}'. Deleting file."); - C1File.Delete(filename); - - MarkWorkflowAsAborted(instanceId); - } - - return null; - } - - - - protected override void SaveCompletedContextActivity(Activity activity) - { - Guid contextGuid = (Guid)activity.GetValue(Activity.ActivityContextGuidProperty); - SerializeActivity(activity, contextGuid); - } - - - - protected override void SaveWorkflowInstanceState(Activity rootActivity, bool unlock) - { - Guid contextGuid = (Guid)rootActivity.GetValue(Activity.ActivityContextGuidProperty); - SerializeActivity(rootActivity, contextGuid); - } - - - protected override bool UnloadOnIdle(Activity activity) - { - return GetPersistingType(activity) == WorkflowPersistingType.Idle; - } - - - - protected override void UnlockWorkflowInstanceState(Activity rootActivity) - { - //empty - } - - private bool ActivityIsSerializable(Activity activity) - { - return PersistAll || GetPersistingType(activity) != WorkflowPersistingType.Never; - } - - private WorkflowPersistingType GetPersistingType(Activity activity) - { - List attributes = activity.GetType().GetCustomAttributesRecursively().ToList(); - - if (attributes.Count == 0) return WorkflowPersistingType.Never; - - return attributes[0].WorkflowPersistingType; - } - - private void SerializeActivity(Activity rootActivity, Guid id) - { - if (!ActivityIsSerializable(rootActivity)) - { - Log.LogVerbose(LogTitle, - $"The workflow does not support persiting. Id = {id}, Type = {rootActivity.GetType()}"); - return; - } - - string filename = GetFileName(id); - - IFormatter formatter = new BinaryFormatter(); - formatter.SurrogateSelector = ActivitySurrogateSelector.Default; - - using (C1FileStream stream = new C1FileStream(filename, FileMode.OpenOrCreate)) - { - rootActivity.Save(stream, formatter); - stream.Close(); - } - - // Log.LogVerbose(LogTitle, $"Workflow persisted. Id = {id}, Type = {rootActivity.GetType()}"); - } - - - - private object DeserializeActivity(Activity rootActivity, Guid id) - { - string filename = GetFileName(id); - object result; - - IFormatter formatter = new BinaryFormatter(); - formatter.SurrogateSelector = ActivitySurrogateSelector.Default; - - using (C1FileStream stream = new C1FileStream(filename, FileMode.Open)) - { - result = Activity.Load(stream, rootActivity, formatter); - stream.Close(); - } - - // Log.LogVerbose(LogTitle, $"Workflow loaded. Id = {id}, Type = {result.GetType()}"); - - return result; - } - - private void MarkWorkflowAsAborted(Guid id) - { - lock (_syncRoot) - { - List newList = new List(_abortedWorkflows ?? new Guid[0]); - newList.Add(id); - - _abortedWorkflows = newList.ToArray(); - } - } - - private string GetFileName(Guid id) - { - return Path.Combine(this._baseDirectory, id.ToString() + ".bin"); - } - } -} +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Runtime.Serialization; +using System.Runtime.Serialization.Formatters.Binary; +using System.Workflow.ComponentModel; +using System.Workflow.ComponentModel.Serialization; +using System.Workflow.Runtime.Hosting; +using Composite.Core; +using Composite.Core.IO; +using Composite.Core.Logging; +using Composite.Core.Types; + + +namespace Composite.C1Console.Workflow +{ + internal class FileWorkflowPersistenceService : WorkflowPersistenceService + { + private static readonly string LogTitle = "Workflow File Persisting Service"; + private readonly string _baseDirectory; + private Guid[] _abortedWorkflows; + private readonly object _syncRoot = new object(); + + + public FileWorkflowPersistenceService(string baseDirectory) + { + _baseDirectory = baseDirectory; + this.PersistAll = false; + } + + + + public bool PersistAll { get; set; } + + public IEnumerable GetAbortedWorkflows() + { + return _abortedWorkflows ?? new Guid[0]; + } + + public IEnumerable GetPersistedWorkflows() + { + foreach (string filePath in C1Directory.GetFiles(_baseDirectory, "*.bin")) + { + string guidString = Path.GetFileNameWithoutExtension(filePath); + + Guid guid = Guid.Empty; + try + { + guid = new Guid(guidString); + } + catch { } + + if (guid != Guid.Empty) + { + yield return guid; + } + } + } + + + + public bool RemovePersistedWorkflow(Guid instanceId) + { + string filename = GetFileName(instanceId); + + if (C1File.Exists(filename)) + { + try + { + C1File.Delete(filename); + + Log.LogVerbose(LogTitle, $"Workflow persisted state deleted. Id = {instanceId}"); + } + catch + { + return false; + } + } + + return true; + } + + + + protected override Activity LoadCompletedContextActivity(Guid scopeId, Activity outerActivity) + { + object obj = DeserializeActivity(outerActivity, scopeId); + return (Activity)obj; + } + + + + protected override Activity LoadWorkflowInstanceState(Guid instanceId) + { + string filename = GetFileName(instanceId); + bool deleteFile = false; + + if (C1File.Exists(filename)) + { + try + { + object obj = DeserializeActivity(null, instanceId); + return (Activity)obj; + } + catch (Exception ex) + { + LoggingService.LogCritical(LogTitle, ex); + deleteFile = true; + } + } + + if (deleteFile) + { + Log.LogWarning(LogTitle, $"Failed to load workflow with id '{filename}'. Deleting file."); + C1File.Delete(filename); + + MarkWorkflowAsAborted(instanceId); + } + + return null; + } + + + + protected override void SaveCompletedContextActivity(Activity activity) + { + Guid contextGuid = (Guid)activity.GetValue(Activity.ActivityContextGuidProperty); + SerializeActivity(activity, contextGuid); + } + + + + protected override void SaveWorkflowInstanceState(Activity rootActivity, bool unlock) + { + Guid contextGuid = (Guid)rootActivity.GetValue(Activity.ActivityContextGuidProperty); + SerializeActivity(rootActivity, contextGuid); + } + + + protected override bool UnloadOnIdle(Activity activity) + { + return GetPersistingType(activity) == WorkflowPersistingType.Idle; + } + + + + protected override void UnlockWorkflowInstanceState(Activity rootActivity) + { + //empty + } + + private bool ActivityIsSerializable(Activity activity) + { + return PersistAll || GetPersistingType(activity) != WorkflowPersistingType.Never; + } + + private WorkflowPersistingType GetPersistingType(Activity activity) + { + List attributes = activity.GetType().GetCustomAttributesRecursively().ToList(); + + if (attributes.Count == 0) return WorkflowPersistingType.Never; + + return attributes[0].WorkflowPersistingType; + } + + private void SerializeActivity(Activity rootActivity, Guid id) + { + if (!ActivityIsSerializable(rootActivity)) + { + Log.LogVerbose(LogTitle, + $"The workflow does not support persiting. Id = {id}, Type = {rootActivity.GetType()}"); + return; + } + + string filename = GetFileName(id); + + IFormatter formatter = new BinaryFormatter(); + formatter.SurrogateSelector = ActivitySurrogateSelector.Default; + + using (var stream = new C1FileStream(filename, FileMode.OpenOrCreate)) + { + try + { + rootActivity.Save(stream, formatter); + stream.Close(); + } + catch (SerializationException ex) + { + Log.LogError(LogTitle, ex); + } + } + + // Log.LogVerbose(LogTitle, $"Workflow persisted. Id = {id}, Type = {rootActivity.GetType()}"); + } + + + + private object DeserializeActivity(Activity rootActivity, Guid id) + { + string filename = GetFileName(id); + object result; + + IFormatter formatter = new BinaryFormatter(); + formatter.SurrogateSelector = ActivitySurrogateSelector.Default; + + using (C1FileStream stream = new C1FileStream(filename, FileMode.Open)) + { + result = Activity.Load(stream, rootActivity, formatter); + stream.Close(); + } + + // Log.LogVerbose(LogTitle, $"Workflow loaded. Id = {id}, Type = {result.GetType()}"); + + return result; + } + + private void MarkWorkflowAsAborted(Guid id) + { + lock (_syncRoot) + { + List newList = new List(_abortedWorkflows ?? new Guid[0]); + newList.Add(id); + + _abortedWorkflows = newList.ToArray(); + } + } + + private string GetFileName(Guid id) + { + return Path.Combine(this._baseDirectory, id.ToString() + ".bin"); + } + } +} From 82e3c267d6c122460065a8839272d8a15c55fe35 Mon Sep 17 00:00:00 2001 From: Marcus Wendt Date: Tue, 8 Mar 2016 15:29:13 +0100 Subject: [PATCH 005/133] Fix #130 - HttpException not always bubbled (wold require prettifyRenderFunctionExceptions=false in config). With this fix it will always bubble which makes sense. --- Composite/Functions/FunctionContextContainer.cs | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/Composite/Functions/FunctionContextContainer.cs b/Composite/Functions/FunctionContextContainer.cs index 7a3476ec19..17f4e5d502 100644 --- a/Composite/Functions/FunctionContextContainer.cs +++ b/Composite/Functions/FunctionContextContainer.cs @@ -1,13 +1,12 @@ -using System.Collections.Generic; using System; +using System.Collections.Generic; using System.Threading; +using System.Web; using System.Web.UI; +using System.Xml.Linq; using Composite.Core; using Composite.Core.Types; -using System.Xml.Linq; using Composite.Core.Xml; -using Composite.Plugins.PageTemplates.MasterPages.Controls.Functions; - namespace Composite.Functions { @@ -134,7 +133,8 @@ public bool ProcessException(string functionName, Exception exception, string lo || exception is ThreadAbortException || exception is ThreadInterruptedException || exception is AppDomainUnloadedException - || exception is OutOfMemoryException) + || exception is OutOfMemoryException + || IsHttpException(exception)) { errorBoxHtml = null; return false; @@ -146,5 +146,10 @@ public bool ProcessException(string functionName, Exception exception, string lo return true; } + + private bool IsHttpException(Exception exception) + { + return exception is HttpException || (exception.InnerException != null && IsHttpException(exception.InnerException)); + } } } From d1c3f326ea6c325ba4dd84e75b385de4816c142f Mon Sep 17 00:00:00 2001 From: Morteza Kasravi Date: Wed, 9 Mar 2016 10:23:38 +0100 Subject: [PATCH 006/133] added functionality for handling page types in add actions --- .../PageElementProvider/AddNewPageWorkflow.cs | 18 ++--- .../Data/DataActionTokenRegisterHandler.cs | 14 ++-- .../Actions/Data/DataActionTokenResolver.cs | 8 +- .../Data/DataActionTokenResolverFacade.cs | 8 +- Composite/Composite.csproj | 2 + ...enericPublishProcessDynamicActionTokens.cs | 10 +-- ...atedDataTypesElementDynamicActionTokens.cs | 4 +- .../PageAddActionExecuter.cs | 30 +++++++ .../PageElementProvider/PageAddActionToken.cs | 55 +++++++++++++ .../PageElementDynamicActionTokens.cs | 10 +-- .../PageElementProvider.cs | 79 ++++++++++++------- .../forms/Administrative/AddNewPageStep1.xml | 18 ++--- ...site.Plugins.PageElementProvider.en-us.xml | 6 +- 13 files changed, 179 insertions(+), 83 deletions(-) create mode 100644 Composite/Plugins/Elements/ElementProviders/PageElementProvider/PageAddActionExecuter.cs create mode 100644 Composite/Plugins/Elements/ElementProviders/PageElementProvider/PageAddActionToken.cs diff --git a/Composite.Workflows/Plugins/Elements/ElementProviders/PageElementProvider/AddNewPageWorkflow.cs b/Composite.Workflows/Plugins/Elements/ElementProviders/PageElementProvider/AddNewPageWorkflow.cs index bb17992d79..c7a64a73c5 100644 --- a/Composite.Workflows/Plugins/Elements/ElementProviders/PageElementProvider/AddNewPageWorkflow.cs +++ b/Composite.Workflows/Plugins/Elements/ElementProviders/PageElementProvider/AddNewPageWorkflow.cs @@ -18,7 +18,7 @@ using Composite.C1Console.Users; using Composite.C1Console.Trees; using Composite.C1Console.Workflow; - +using Composite.Core.Serialization; using Microsoft.Practices.EnterpriseLibrary.Validation; @@ -86,6 +86,10 @@ private List GetSelectablePageTypes() private Guid? GetDefaultPageTypeId(IEnumerable selectablePageTypes) { + if (!string.IsNullOrEmpty(Payload)) + { + return ((IPage)SerializerHandlerFacade.Deserialize(Payload)).PageTypeId; + } if (!(this.EntityToken is PageElementProviderEntityToken)) { IPage parentPage = this.GetDataItemFromEntityToken(); @@ -259,15 +263,7 @@ private void stepInitialize_codeActivity_ExecuteCode(object sender, EventArgs e) Dictionary bindings = new Dictionary(); - - - List> pageTypeOptions = - selectablePageTypes. - Select(f => new KeyValuePair(f.Id, f.Name)). - ToList(); - - bindings.Add("PageTypeOptions", pageTypeOptions); - + string pageType = selectablePageTypes.First(f => f.Id == pageTypeId).Name; IPage newPage = DataFacade.BuildNew(); newPage.Id = Guid.NewGuid(); @@ -281,6 +277,8 @@ private void stepInitialize_codeActivity_ExecuteCode(object sender, EventArgs e) bindings.Add("NewPage", newPage); + bindings.Add("Title", string.Format(GetText("AddNewPageStep1.DialogLabel"), pageType)); + bindings.Add("UrlTitleIsRequired", true /* ThereAreOtherPages()*/); int existingPagesCount = PageServices.GetChildrenCount(parentId); diff --git a/Composite/C1Console/Actions/Data/DataActionTokenRegisterHandler.cs b/Composite/C1Console/Actions/Data/DataActionTokenRegisterHandler.cs index 63000c99ce..7d5cbb6ca9 100644 --- a/Composite/C1Console/Actions/Data/DataActionTokenRegisterHandler.cs +++ b/Composite/C1Console/Actions/Data/DataActionTokenRegisterHandler.cs @@ -6,31 +6,31 @@ namespace Composite.C1Console.Actions.Data { abstract class DataActionTokenRegisterHandler { - public abstract ActionToken GetActionToken(); + public abstract ActionToken GetActionToken(IData data); public abstract bool Check(Type type,IData data, ActionIdentifier actionIdentifier); } class DataActionTokenRegisterHandler : DataActionTokenRegisterHandler where T : IData { - private readonly ActionToken _actionToken; + private readonly Func _actionTokenFunc; private readonly ActionIdentifier _actionIdentifier; private readonly Func _actionValidPredicate; - public DataActionTokenRegisterHandler(ActionIdentifier actionIdentifier, ActionToken dataActionToken) + public DataActionTokenRegisterHandler(ActionIdentifier actionIdentifier, Func dataActionToken) { - _actionToken = dataActionToken; + _actionTokenFunc = dataActionToken; _actionIdentifier = actionIdentifier; } - public DataActionTokenRegisterHandler(ActionIdentifier actionIdentifier, ActionToken dataActionToken, Func actionValidPredicate) : this(actionIdentifier, dataActionToken) + public DataActionTokenRegisterHandler(ActionIdentifier actionIdentifier, Func dataActionToken, Func actionValidPredicate) : this(actionIdentifier, dataActionToken) { _actionValidPredicate = actionValidPredicate; } - public override ActionToken GetActionToken() + public override ActionToken GetActionToken(IData data) { - return _actionToken; + return _actionTokenFunc((T)data); } public override bool Check(Type type, IData data, ActionIdentifier actionIdentifier) diff --git a/Composite/C1Console/Actions/Data/DataActionTokenResolver.cs b/Composite/C1Console/Actions/Data/DataActionTokenResolver.cs index 811ec91ea6..3bb2258039 100644 --- a/Composite/C1Console/Actions/Data/DataActionTokenResolver.cs +++ b/Composite/C1Console/Actions/Data/DataActionTokenResolver.cs @@ -18,7 +18,7 @@ public class DataActionTokenResolver /// /// /// - public void RegisterDefault(ActionIdentifier actionIdentifier, ActionToken dataActionToken) where T : IData + public void RegisterDefault(ActionIdentifier actionIdentifier, Func dataActionToken) where T : IData { Verify.ArgumentNotNull(actionIdentifier, nameof(actionIdentifier)); Verify.ArgumentNotNull(dataActionToken, nameof(dataActionToken)); @@ -37,7 +37,7 @@ public void RegisterDefault(ActionIdentifier actionIdentifier, ActionToken da /// /// /// - public void RegisterConditional(ActionIdentifier actionIdentifier, Func actionValidPredicate, ActionToken dataActionToken) where T : IData + public void RegisterConditional(ActionIdentifier actionIdentifier, Func actionValidPredicate, Func dataActionToken) where T : IData { Verify.ArgumentNotNull(actionIdentifier, nameof(actionIdentifier)); Verify.ArgumentNotNull(actionValidPredicate, nameof(actionValidPredicate)); @@ -61,7 +61,7 @@ public ActionToken Resolve(IData data, ActionIdentifier actionIdentifier) var conditionalAction = _conditionalActions?.FirstOrDefault(f => f.Check(type, data, actionIdentifier)); if (conditionalAction != null) { - return conditionalAction.GetActionToken(); + return conditionalAction.GetActionToken(data); } } @@ -70,7 +70,7 @@ public ActionToken Resolve(IData data, ActionIdentifier actionIdentifier) var defaultAction = _defaultActions?.LastOrDefault(f => f.Check(type, data, actionIdentifier)); if (defaultAction != null) { - return defaultAction.GetActionToken(); + return defaultAction.GetActionToken(data); } } return null; diff --git a/Composite/C1Console/Actions/Data/DataActionTokenResolverFacade.cs b/Composite/C1Console/Actions/Data/DataActionTokenResolverFacade.cs index 65b4df5d81..328f739af3 100644 --- a/Composite/C1Console/Actions/Data/DataActionTokenResolverFacade.cs +++ b/Composite/C1Console/Actions/Data/DataActionTokenResolverFacade.cs @@ -1,8 +1,4 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using Composite.C1Console.Security; using Composite.Core.Application; using Composite.Data; @@ -26,7 +22,7 @@ public static ActionToken Resolve(IData data, ActionIdentifier actionIdentifier) /// /// /// - public static void RegisterDefault(ActionIdentifier actionIdentifier, ActionToken dataActionToken) where T : IData + public static void RegisterDefault(ActionIdentifier actionIdentifier, Func dataActionToken) where T : IData { GetDataActionTokenResolverService().RegisterDefault(actionIdentifier, dataActionToken); } @@ -37,7 +33,7 @@ public static void RegisterDefault(ActionIdentifier actionIdentifier, ActionT /// /// /// - public static void RegisterConditional(ActionIdentifier actionIdentifier, Func actionValidPredicate, ActionToken dataActionToken) where T : IData + public static void RegisterConditional(ActionIdentifier actionIdentifier, Func actionValidPredicate, Func dataActionToken) where T : IData { GetDataActionTokenResolverService().RegisterConditional(actionIdentifier, actionValidPredicate, dataActionToken); } diff --git a/Composite/Composite.csproj b/Composite/Composite.csproj index fc26d61094..de1127cfc7 100644 --- a/Composite/Composite.csproj +++ b/Composite/Composite.csproj @@ -164,6 +164,8 @@ + + diff --git a/Composite/Data/ProcessControlled/ProcessControllers/GenericPublishProcessController/GenericPublishProcessDynamicActionTokens.cs b/Composite/Data/ProcessControlled/ProcessControllers/GenericPublishProcessController/GenericPublishProcessDynamicActionTokens.cs index 8d6cf8ed58..295fcfc15d 100644 --- a/Composite/Data/ProcessControlled/ProcessControllers/GenericPublishProcessController/GenericPublishProcessDynamicActionTokens.cs +++ b/Composite/Data/ProcessControlled/ProcessControllers/GenericPublishProcessController/GenericPublishProcessDynamicActionTokens.cs @@ -8,11 +8,11 @@ class GenericPublishProcessDynamicActionTokens { public static void OnBeforeInitialize() { - DataActionTokenResolverFacade.RegisterDefault(ActionIdentifier.SendForPublication, new GenericPublishProcessController.AwaitingPublicationActionToken()); - DataActionTokenResolverFacade.RegisterDefault(ActionIdentifier.Publish,new GenericPublishProcessController.PublishActionToken()); - DataActionTokenResolverFacade.RegisterDefault(ActionIdentifier.SendForApproval, new GenericPublishProcessController.AwaitingApprovalActionToken()); - DataActionTokenResolverFacade.RegisterDefault(ActionIdentifier.SendToDraft, new GenericPublishProcessController.DraftActionToken()); - DataActionTokenResolverFacade.RegisterDefault(ActionIdentifier.Unpublish, new GenericPublishProcessController.UnpublishActionToken()); + DataActionTokenResolverFacade.RegisterDefault(ActionIdentifier.SendForPublication, f => new GenericPublishProcessController.AwaitingPublicationActionToken()); + DataActionTokenResolverFacade.RegisterDefault(ActionIdentifier.Publish, f => new GenericPublishProcessController.PublishActionToken()); + DataActionTokenResolverFacade.RegisterDefault(ActionIdentifier.SendForApproval, f => new GenericPublishProcessController.AwaitingApprovalActionToken()); + DataActionTokenResolverFacade.RegisterDefault(ActionIdentifier.SendToDraft, f => new GenericPublishProcessController.DraftActionToken()); + DataActionTokenResolverFacade.RegisterDefault(ActionIdentifier.Unpublish, f => new GenericPublishProcessController.UnpublishActionToken()); } public static void OnInitialized() diff --git a/Composite/Plugins/Elements/ElementProviders/GeneratedDataTypesElementProvider/GeneratedDataTypesElementDynamicActionTokens.cs b/Composite/Plugins/Elements/ElementProviders/GeneratedDataTypesElementProvider/GeneratedDataTypesElementDynamicActionTokens.cs index e25425feb0..ff80aaaffd 100644 --- a/Composite/Plugins/Elements/ElementProviders/GeneratedDataTypesElementProvider/GeneratedDataTypesElementDynamicActionTokens.cs +++ b/Composite/Plugins/Elements/ElementProviders/GeneratedDataTypesElementProvider/GeneratedDataTypesElementDynamicActionTokens.cs @@ -15,8 +15,8 @@ public static class GeneratedDataTypesElementDynamicActionTokens /// public static void OnBeforeInitialize() { - DataActionTokenResolverFacade.RegisterDefault(ActionIdentifier.Edit, new WorkflowActionToken(WorkflowFacade.GetWorkflowType("Composite.Plugins.Elements.ElementProviders.GeneratedDataTypesElementProvider.EditDataWorkflow"))); - DataActionTokenResolverFacade.RegisterDefault(ActionIdentifier.Delete, new WorkflowActionToken(WorkflowFacade.GetWorkflowType("Composite.Plugins.Elements.ElementProviders.GeneratedDataTypesElementProvider.DeleteDataWorkflow"))); + DataActionTokenResolverFacade.RegisterDefault(ActionIdentifier.Edit, f => new WorkflowActionToken(WorkflowFacade.GetWorkflowType("Composite.Plugins.Elements.ElementProviders.GeneratedDataTypesElementProvider.EditDataWorkflow"))); + DataActionTokenResolverFacade.RegisterDefault(ActionIdentifier.Delete, f => new WorkflowActionToken(WorkflowFacade.GetWorkflowType("Composite.Plugins.Elements.ElementProviders.GeneratedDataTypesElementProvider.DeleteDataWorkflow"))); } /// public static void OnInitialized() diff --git a/Composite/Plugins/Elements/ElementProviders/PageElementProvider/PageAddActionExecuter.cs b/Composite/Plugins/Elements/ElementProviders/PageElementProvider/PageAddActionExecuter.cs new file mode 100644 index 0000000000..4e7433e685 --- /dev/null +++ b/Composite/Plugins/Elements/ElementProviders/PageElementProvider/PageAddActionExecuter.cs @@ -0,0 +1,30 @@ +using Composite.C1Console.Actions; +using Composite.C1Console.Actions.Data; +using Composite.C1Console.Security; +using Composite.Data; +using Composite.Data.Types; + +namespace Composite.Plugins.Elements.ElementProviders.PageElementProvider +{ + /// + public class PageAddActionExecuter : IActionExecutorSerializedParameters + { + /// + public FlowToken Execute(EntityToken entityToken, ActionToken actionToken, FlowControllerServicesContainer flowControllerServicesContainer) + { + return Execute(EntityTokenSerializer.Serialize(entityToken), ActionTokenSerializer.Serialize(actionToken), actionToken, flowControllerServicesContainer); + } + /// + public FlowToken Execute(string serializedEntityToken, string serializedActionToken, ActionToken actionToken, FlowControllerServicesContainer flowControllerServicesContainer) + { + PageAddActionToken pageAddActionToken = (PageAddActionToken)actionToken; + + var newPage = DataFacade.BuildNew(); + newPage.PageTypeId = pageAddActionToken.PageTypeId; + + var action = DataActionTokenResolverFacade.Resolve(newPage, ((PageAddActionToken)actionToken).ActionIdentifier); + + return ActionExecutorFacade.Execute(EntityTokenSerializer.Deserialize(serializedEntityToken), action, flowControllerServicesContainer); + } + } +} diff --git a/Composite/Plugins/Elements/ElementProviders/PageElementProvider/PageAddActionToken.cs b/Composite/Plugins/Elements/ElementProviders/PageElementProvider/PageAddActionToken.cs new file mode 100644 index 0000000000..874d82e6fa --- /dev/null +++ b/Composite/Plugins/Elements/ElementProviders/PageElementProvider/PageAddActionToken.cs @@ -0,0 +1,55 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Composite.C1Console.Actions; +using Composite.C1Console.Actions.Data; +using Composite.C1Console.Security; +using Composite.Core.Serialization; + +namespace Composite.Plugins.Elements.ElementProviders.PageElementProvider +{ + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + [ActionExecutor(typeof(PageAddActionExecuter))] + class PageAddActionToken : ProxyDataActionToken + { + private readonly Guid _pageTypeId; + /// + public PageAddActionToken(Guid pageTypeId, ActionIdentifier actionIdentifier) : base(actionIdentifier) + { + _pageTypeId = pageTypeId; + } + /// + public PageAddActionToken(Guid pageTypeId, ActionIdentifier actionIdentifier, IEnumerable permissionTypes) : base(actionIdentifier,permissionTypes) + { + _pageTypeId = pageTypeId; + } + /// + public Guid PageTypeId => _pageTypeId; + + public override bool IgnoreEntityTokenLocking => true; + + public override string Serialize() + { + StringBuilder stringBuilder = new StringBuilder(base.Serialize()); + + StringConversionServices.SerializeKeyValuePair(stringBuilder, "_PageTypeId_", _pageTypeId); + + return stringBuilder.ToString(); + } + /// + public new static ActionToken Deserialize(string serializedData) + { + Dictionary dic = StringConversionServices.ParseKeyValueCollection(serializedData); + + Guid pageTypeId = StringConversionServices.DeserializeValueGuid(dic["_PageTypeId_"]); + + var baseProxyDataActionToken = (ProxyDataActionToken)ProxyDataActionToken.Deserialize(serializedData); + + var result = new PageAddActionToken(pageTypeId, baseProxyDataActionToken.ActionIdentifier, baseProxyDataActionToken.PermissionTypes); + + return result; + } + } +} + + diff --git a/Composite/Plugins/Elements/ElementProviders/PageElementProvider/PageElementDynamicActionTokens.cs b/Composite/Plugins/Elements/ElementProviders/PageElementProvider/PageElementDynamicActionTokens.cs index 8ce7f877db..63fbba270d 100644 --- a/Composite/Plugins/Elements/ElementProviders/PageElementProvider/PageElementDynamicActionTokens.cs +++ b/Composite/Plugins/Elements/ElementProviders/PageElementProvider/PageElementDynamicActionTokens.cs @@ -1,9 +1,7 @@ -using Composite.C1Console.Actions; using Composite.C1Console.Actions.Data; -using Composite.C1Console.Events; using Composite.C1Console.Workflow; using Composite.Core.Application; -using Composite.Data; +using Composite.Core.Serialization; using Composite.Data.Types; namespace Composite.Plugins.Elements.ElementProviders.PageElementProvider @@ -17,9 +15,9 @@ public static class PageElementDynamicActionTokens /// public static void OnBeforeInitialize() { - DataActionTokenResolverFacade.RegisterDefault(ActionIdentifier.Add, new WorkflowActionToken(WorkflowFacade.GetWorkflowType("Composite.Plugins.Elements.ElementProviders.PageElementProvider.AddNewPageWorkflow")) { DoIgnoreEntityTokenLocking = true }); - DataActionTokenResolverFacade.RegisterDefault(ActionIdentifier.Edit, new WorkflowActionToken(WorkflowFacade.GetWorkflowType("Composite.Plugins.Elements.ElementProviders.PageElementProvider.EditPageWorkflow"))); - DataActionTokenResolverFacade.RegisterDefault(ActionIdentifier.Delete, new WorkflowActionToken(WorkflowFacade.GetWorkflowType("Composite.Plugins.Elements.ElementProviders.PageElementProvider.DeletePageWorkflow"))); + DataActionTokenResolverFacade.RegisterDefault(ActionIdentifier.Add, f => new WorkflowActionToken(WorkflowFacade.GetWorkflowType("Composite.Plugins.Elements.ElementProviders.PageElementProvider.AddNewPageWorkflow")) { DoIgnoreEntityTokenLocking = true, Payload = SerializerHandlerFacade.Serialize(f) }); + DataActionTokenResolverFacade.RegisterDefault(ActionIdentifier.Edit, f => new WorkflowActionToken(WorkflowFacade.GetWorkflowType("Composite.Plugins.Elements.ElementProviders.PageElementProvider.EditPageWorkflow"))); + DataActionTokenResolverFacade.RegisterDefault(ActionIdentifier.Delete, f => new WorkflowActionToken(WorkflowFacade.GetWorkflowType("Composite.Plugins.Elements.ElementProviders.PageElementProvider.DeletePageWorkflow"))); } /// diff --git a/Composite/Plugins/Elements/ElementProviders/PageElementProvider/PageElementProvider.cs b/Composite/Plugins/Elements/ElementProviders/PageElementProvider/PageElementProvider.cs index 2d9ddf8ef2..1e4fcb9a0a 100644 --- a/Composite/Plugins/Elements/ElementProviders/PageElementProvider/PageElementProvider.cs +++ b/Composite/Plugins/Elements/ElementProviders/PageElementProvider/PageElementProvider.cs @@ -132,23 +132,38 @@ public IEnumerable GetRoots(SearchToken searchToken) } }; - element.AddAction(new ElementAction(new ActionHandle(new WorkflowActionToken(WorkflowFacade.GetWorkflowType("Composite.Plugins.Elements.ElementProviders.PageElementProvider.AddNewPageWorkflow"), AddWebsitePermissionTypes) { DoIgnoreEntityTokenLocking = true })) + var allPageTypes = DataFacade.GetData(); + + foreach ( + var pageType in + allPageTypes.Where(f => f.HomepageRelation == PageTypeHomepageRelation.OnlyHomePages.ToPageTypeHomepageRelationString()) + .OrderByDescending(f=>f.Id)) { - VisualData = new ActionVisualizedData - { - Label = StringResourceSystemFacade.GetString("Composite.Plugins.PageElementProvider", "PageElementProvider.AddPageAtRoot"), - ToolTip = StringResourceSystemFacade.GetString("Composite.Plugins.PageElementProvider", "PageElementProvider.AddPageAtRootToolTip"), - Icon = PageElementProvider.AddPage, - Disabled = false, - ActionLocation = new ActionLocation + element.AddAction( + new ElementAction( + new ActionHandle(new PageAddActionToken(pageType.Id, ActionIdentifier.Add, AddPermissionTypes) {} )) { - ActionType = ActionType.Add, - IsInFolder = false, - IsInToolbar = true, - ActionGroup = PrimaryActionGroup - } - } - }); + VisualData = new ActionVisualizedData + { + Label = string.Format(StringResourceSystemFacade.GetString("Composite.Plugins.PageElementProvider", + "PageElementProvider.AddPageAtRoot"), pageType.Name), + ToolTip = + StringResourceSystemFacade.GetString("Composite.Plugins.PageElementProvider", + "PageElementProvider.AddPageAtRootToolTip"), + Icon = PageElementProvider.AddPage, + Disabled = false, + ActionLocation = new ActionLocation + { + ActionType = ActionType.Add, + IsInFolder = false, + IsInToolbar = true, + ActionGroup = PrimaryActionGroup, + ActionBundle = "AddWebsite" + } + } + + }); + } element.AddAction(new ElementAction(new ActionHandle(new ViewUnpublishedItemsActionToken())) @@ -654,6 +669,7 @@ private List GetElements(List> pag } var elements = new Element[pages.Count]; + var allPageTypes = DataFacade.GetData(); ParallelFacade.For("PageElementProvider. Getting elements", 0, pages.Count, i => { @@ -693,23 +709,30 @@ private List GetElements(List> pag } }); - element.AddAction(new ElementAction(new ActionHandle(new ProxyDataActionToken(ActionIdentifier.Add,AddPermissionTypes))) + IPageType parentPageType = allPageTypes.First(f => f.Id == page.PageTypeId); + + foreach (var pageType in page.GetChildPageSelectablePageTypes().OrderByDescending(pt => pt.Id == parentPageType.DefaultChildPageType)) { - VisualData = new ActionVisualizedData + element.AddAction(new ElementAction(new ActionHandle(new PageAddActionToken(pageType.Id,ActionIdentifier.Add, AddPermissionTypes))) { - Label = addNewPageLabel, - ToolTip = addNewPageToolTip, - Icon = PageElementProvider.AddPage, - Disabled = false, - ActionLocation = new ActionLocation + VisualData = new ActionVisualizedData { - ActionType = ActionType.Add, - IsInFolder = false, - IsInToolbar = true, - ActionGroup = PrimaryActionGroup + Label = string.Format(addNewPageLabel, pageType.Name), + ToolTip = pageType.Description, + Icon = PageElementProvider.AddPage, + Disabled = false, + ActionLocation = new ActionLocation + { + ActionType = ActionType.Add, + IsInFolder = false, + IsInToolbar = true, + ActionGroup = PrimaryActionGroup, + ActionBundle = "AddPage" + } } - } - }); + }); + } + element.AddAction(new ElementAction(new ActionHandle(new ProxyDataActionToken(ActionIdentifier.Delete,DeletePermissionTypes))) { diff --git a/Website/Composite/content/forms/Administrative/AddNewPageStep1.xml b/Website/Composite/content/forms/Administrative/AddNewPageStep1.xml index b49f892d54..3ba46a99dd 100644 --- a/Website/Composite/content/forms/Administrative/AddNewPageStep1.xml +++ b/Website/Composite/content/forms/Administrative/AddNewPageStep1.xml @@ -5,8 +5,13 @@ + + - + + + + @@ -19,17 +24,6 @@ - - - - - - - - - diff --git a/Website/Composite/localization/Composite.Plugins.PageElementProvider.en-us.xml b/Website/Composite/localization/Composite.Plugins.PageElementProvider.en-us.xml index a058791ca6..1cf0d8763a 100644 --- a/Website/Composite/localization/Composite.Plugins.PageElementProvider.en-us.xml +++ b/Website/Composite/localization/Composite.Plugins.PageElementProvider.en-us.xml @@ -1,6 +1,6 @@  - + @@ -62,7 +62,7 @@ - + @@ -74,7 +74,7 @@ - + From 2f92f3e541e0fa22ff789875f9d0c2a242ce48b9 Mon Sep 17 00:00:00 2001 From: neexite Date: Wed, 9 Mar 2016 15:40:24 +0200 Subject: [PATCH 007/133] HierarchicalSelector: selectable, required, pined, height, parent selection fix bundle fix browser js refenrece(404) --- .../HierarchicalSelectorUiControl.cs | 9 +- .../content/views/browser/browser.aspx | 1 - .../Selectors/HierarchicalSelector.ascx | 18 +- .../data/radiocheck/CheckTreeBinding.js | 4 +- .../data/radiocheck/CheckTreeNodeBinding.js | 71 ++++-- .../selectors/HierarchicalSelectorBinding.js | 101 ++++++-- .../bindings/system/SystemTreePopupBinding.js | 11 +- .../top/ui/bindings/trees/TreeNodeBinding.js | 234 +++++++++--------- .../styles/default/fields/fields-base.less | 5 +- .../styles/default/fields/selectors.less | 36 ++- .../styles/default/trees/trees-base.less | 14 ++ 11 files changed, 332 insertions(+), 172 deletions(-) diff --git a/Composite/C1Console/Forms/CoreUiControls/HierarchicalSelectorUiControl.cs b/Composite/C1Console/Forms/CoreUiControls/HierarchicalSelectorUiControl.cs index 1ed47bf21e..d3d9849696 100644 --- a/Composite/C1Console/Forms/CoreUiControls/HierarchicalSelectorUiControl.cs +++ b/Composite/C1Console/Forms/CoreUiControls/HierarchicalSelectorUiControl.cs @@ -31,9 +31,16 @@ public sealed class SelectionTreeNode /// public string Label { get; set; } - /// + /// + /// Determines whether a tree element should feature a checkbox. + /// public bool Selectable { get; set; } + /// + /// Determines whether the tree element's checkbox is readonly. + /// + public bool Readonly { get; set; } + /// public string Icon { get; set; } diff --git a/Website/Composite/content/views/browser/browser.aspx b/Website/Composite/content/views/browser/browser.aspx index 668f6959f2..314038126b 100644 --- a/Website/Composite/content/views/browser/browser.aspx +++ b/Website/Composite/content/views/browser/browser.aspx @@ -10,7 +10,6 @@ - diff --git a/Website/Composite/controls/FormsControls/FormUiControlTemplates/Selectors/HierarchicalSelector.ascx b/Website/Composite/controls/FormsControls/FormUiControlTemplates/Selectors/HierarchicalSelector.ascx index 0ffdaaf93b..fde3c75690 100644 --- a/Website/Composite/controls/FormsControls/FormUiControlTemplates/Selectors/HierarchicalSelector.ascx +++ b/Website/Composite/controls/FormsControls/FormUiControlTemplates/Selectors/HierarchicalSelector.ascx @@ -1,5 +1,6 @@ <%@ Control Language="C#" Inherits="Composite.Plugins.Forms.WebChannel.UiControlFactories.HierarchicalSelectorTemplateUserControlBase" %> <%@ Import Namespace="Composite.C1Console.Forms.CoreUiControls" %> +<%@ Import Namespace="Composite.Core.Extensions" %> <%@ Import Namespace="Composite.Core.Types" %> <%@ Import Namespace="Composite.Plugins.Forms.WebChannel.UiControlFactories" %> @@ -19,7 +20,6 @@ { result.AddRange(postedValue.Split(',')); } - this.SelectedKeys = result; @@ -57,6 +57,20 @@ sb.AppendFormat(" selected=\"true\""); } + if (treeNode.Selectable) + { + sb.AppendFormat(" selectable=\"true\""); + } + } + + if (!treeNode.Icon.IsNullOrEmpty()) + { + sb.AppendFormat(" image=\"{0}\"", treeNode.Icon); + } + + if (treeNode.Readonly) + { + sb.AppendFormat(" readonly=\"true\""); } if (treeNode.Children == null || !treeNode.Children.Any()) @@ -78,6 +92,6 @@ -"> +" autoselectchildren="true"> <%= _treeXhml %> diff --git a/Website/Composite/scripts/source/top/ui/bindings/data/radiocheck/CheckTreeBinding.js b/Website/Composite/scripts/source/top/ui/bindings/data/radiocheck/CheckTreeBinding.js index 0877daafd8..7eeb0b45af 100644 --- a/Website/Composite/scripts/source/top/ui/bindings/data/radiocheck/CheckTreeBinding.js +++ b/Website/Composite/scripts/source/top/ui/bindings/data/radiocheck/CheckTreeBinding.js @@ -61,7 +61,9 @@ CheckTreeBinding.prototype.handleBroadcast = function (broadcast, arg) { if (focused.hasEntries()) { var node = focused.getFirst(); if (node instanceof CheckTreeNodeBinding) { - node.invoke(); + if (!node.isReadOnly) { + node.invoke(); + } } } break; diff --git a/Website/Composite/scripts/source/top/ui/bindings/data/radiocheck/CheckTreeNodeBinding.js b/Website/Composite/scripts/source/top/ui/bindings/data/radiocheck/CheckTreeNodeBinding.js index 6ba513ebec..ba0849131b 100644 --- a/Website/Composite/scripts/source/top/ui/bindings/data/radiocheck/CheckTreeNodeBinding.js +++ b/Website/Composite/scripts/source/top/ui/bindings/data/radiocheck/CheckTreeNodeBinding.js @@ -26,6 +26,16 @@ function CheckTreeNodeBinding() { */ this.selectionValue = null; + /** + * @type {boolean} + */ + this.isSelectable = true; + + /** + * @type {boolean} + */ + this.isReadOnly = false; + return this; } @@ -53,47 +63,76 @@ CheckTreeNodeBinding.prototype.onBindingAttach = function () { CheckTreeNodeBinding.superclass.onBindingAttach.call(this); + this._parseDOMProperties(); this._buildCheckButtonBinding(); + + if (this.isReadOnly) { + this.labelBinding.attachClassName(LabelBinding.CLASSNAME_GRAYTEXT); + } } +/** + * Parse DOM properties, instantiating editation and selectation. + */ +CheckTreeNodeBinding.prototype._parseDOMProperties = function () { + + this.isSelectable = this.isSelectable ? true : this.getProperty("selectable"); +} /** * Build button. */ CheckTreeNodeBinding.prototype._buildCheckButtonBinding = function () { - this._buttonBinding = this.add( - CheckButtonBinding.newInstance(this.bindingDocument) - ); - if (this.getProperty("selected") === true) { - this._buttonBinding.check(true); - } - - var self = this; - this._buttonBinding.addActionListener( + if (this.isSelectable) { + this._buttonBinding = this.add( + CheckButtonBinding.newInstance(this.bindingDocument) + ); + if (this.getProperty("selected") === true) { + this._buttonBinding.check(true); + } + if (this.isReadOnly) { + this._buttonBinding.setDisabled(true); + } + + var self = this; + this._buttonBinding.addActionListener( ButtonBinding.ACTION_COMMAND, { - handleAction: function (action) { + handleAction: function(action) { action.consume(); self.dispatchAction( - CheckTreeNodeBinding.ACTION_COMMAND + CheckTreeNodeBinding.ACTION_COMMAND ); } } - ); + ); - this._buttonBinding.attach(); + this._buttonBinding.attach(); - this.attachClassName(CheckTreeNodeBinding.CLASS_NAME); + this.attachClassName(CheckTreeNodeBinding.CLASS_NAME); + } } CheckTreeNodeBinding.prototype.isChecked = function () { - return this._buttonBinding.isChecked; + if (this.isSelectable) { + return this._buttonBinding.isChecked; + } + return undefined; +} + +CheckTreeNodeBinding.prototype.setChecked = function (isChecked, isDisableCommand) { + + if (this.isSelectable) { + this._buttonBinding.setChecked(isChecked, isDisableCommand); + } } CheckTreeNodeBinding.prototype.invoke = function () { - this._buttonBinding.invoke(); + if (this.isSelectable) { + this._buttonBinding.invoke(); + } } /** diff --git a/Website/Composite/scripts/source/top/ui/bindings/data/selectors/HierarchicalSelectorBinding.js b/Website/Composite/scripts/source/top/ui/bindings/data/selectors/HierarchicalSelectorBinding.js index b561b6ec8f..b6a3da083b 100644 --- a/Website/Composite/scripts/source/top/ui/bindings/data/selectors/HierarchicalSelectorBinding.js +++ b/Website/Composite/scripts/source/top/ui/bindings/data/selectors/HierarchicalSelectorBinding.js @@ -23,7 +23,22 @@ function HierarchicalSelectorBinding () { * @overwrites {Binding#crawlerFilters} * @type {List} */ - this.crawlerFilters = new List ([ DocumentCrawler.ID, FocusCrawler.ID ]); + this.crawlerFilters = new List([DocumentCrawler.ID, FocusCrawler.ID]); + + /** + * @type {boolean} + */ + this.autoSelectChildren = false; + + /** + * @type {boolean} + */ + this.autoSelectParents = true; + + /** + * @type {boolean} + */ + this.isRequired = false; } /** @@ -46,6 +61,7 @@ HierarchicalSelectorBinding.prototype.onBindingAttach = function () { this._buildDOMContent (); this._parseDOMProperties (); this._populate(); + } /** @@ -72,6 +88,8 @@ HierarchicalSelectorBinding.prototype._buildDOMContent = function () { */ HierarchicalSelectorBinding.prototype._parseDOMProperties = function () { + this.autoSelectChildren = this.getProperty("autoselectchildren") === true; + this.isRequired = this.getProperty("required") === true; } HierarchicalSelectorBinding.prototype._populate = function () { @@ -80,40 +98,33 @@ HierarchicalSelectorBinding.prototype._populate = function () { this.shadowTree.box.appendChild(this.shadowTree.tree.bindingElement); this._populateFromSelections(this.shadowTree.tree, this.bindingElement); this.shadowTree.tree.attachRecursive(); -} - -HierarchicalSelectorBinding.prototype._getTreeNode = function (selection) { - - - return treenode; -} - -HierarchicalSelectorBinding.prototype._getTreeNodes = function (selections) { - - var list = new List (); - selections.each(function(selection) { - list.add(this._getTreeNode(selection)); - }, this); - return list; } HierarchicalSelectorBinding.prototype._populateFromSelections = function (treeNodeContainer, selectionContainer) { var hasSelected = false; - DOMUtil.getChildElementsByLocalName(selectionContainer, "selection").each(function (selection) { + var selections = DOMUtil.getChildElementsByLocalName(selectionContainer, "selection"); + var treenode = null;; + + selections.each(function (selection) { - var treenode = CheckTreeNodeBinding.newInstance(this.bindingDocument); + treenode = CheckTreeNodeBinding.newInstance(this.bindingDocument); var label = selection.getAttribute("label"); var value = selection.getAttribute("value"); var isSelected = selection.getAttribute("selected") === "true"; var image = selection.getAttribute("image"); + var isSelectable = selection.getAttribute("selectable") === "true"; + var isReadonly = selection.getAttribute("readonly") === "true"; treenode.setLabel(label); - treenode.setImage(image); + treenode.setImage(image ? image : "blank"); treenode.setProperty("selected", isSelected); treenode.selectionElement = selection; treenode.selectionValue = value; + treenode.isSelectable = isSelectable; + treenode.isReadOnly = isReadonly; + treeNodeContainer.add(treenode); if (this._populateFromSelections(treenode, treenode.selectionElement)) { @@ -125,6 +136,11 @@ HierarchicalSelectorBinding.prototype._populateFromSelections = function (treeNo }, this); + if (treeNodeContainer instanceof CheckTreeBinding && selections.getLength() === 1) { + treenode.setProperty("open", true); + treenode.setProperty("pin", true); + } + return hasSelected; } @@ -144,7 +160,33 @@ HierarchicalSelectorBinding.prototype.handleAction = function ( action ) { switch ( action.type ) { case CheckTreeNodeBinding.ACTION_COMMAND: - this.dirty (); + + this.dirty(); + + var checkTreeNode = action.target; + var isChecked = checkTreeNode.isChecked(); + + if (this.autoSelectChildren) { + checkTreeNode.getDescendantBindingsByType(CheckTreeNodeBinding).each(function (child) { + if (child.isSelectable && !child.isReadOnly) { + child.setChecked(isChecked, true); + } + }); + } + + if (this.autoSelectParents && isChecked) { + var parent = checkTreeNode; + while (((parent = UserInterface.getBinding(parent.bindingElement.parentNode)) && parent instanceof CheckTreeNodeBinding)) { + if (parent.isSelectable && !parent.isReadOnly) { + parent.setChecked(isChecked, true); + } + } + } + + if (this.hasClassName(DataBinding.CLASSNAME_INVALID)) { + this.detachClassName(DataBinding.CLASSNAME_INVALID); + } + action.consume (); break; } @@ -158,8 +200,23 @@ HierarchicalSelectorBinding.prototype.handleAction = function ( action ) { * @return {boolean} */ HierarchicalSelectorBinding.prototype.validate = function () { + var isValid = true; + if (this.isRequired) { + isValid = false; + this.getDescendantBindingsByType(CheckTreeNodeBinding).each(function(treenode) { + if (treenode.isSelectable && treenode.isChecked()) { + isValid = true; + return false; + } + return true; + }); - return true; + if (isValid === false) { + this.attachClassName(DataBinding.CLASSNAME_INVALID); + } + + } + return isValid; } /** @@ -184,7 +241,7 @@ HierarchicalSelectorBinding.prototype.manifest = function() { * Build inputs for selected selections. */ this.getDescendantBindingsByType(CheckTreeNodeBinding).each(function(treenode) { - if (treenode.isChecked()) { + if (treenode.isSelectable && treenode.isChecked()) { var input = DOMUtil.createElementNS(Constants.NS_XHTML, "input", this.bindingDocument); input.name = this._name; input.value = treenode.selectionValue; diff --git a/Website/Composite/scripts/source/top/ui/bindings/system/SystemTreePopupBinding.js b/Website/Composite/scripts/source/top/ui/bindings/system/SystemTreePopupBinding.js index 21ead1d91a..3f4f246aa2 100644 --- a/Website/Composite/scripts/source/top/ui/bindings/system/SystemTreePopupBinding.js +++ b/Website/Composite/scripts/source/top/ui/bindings/system/SystemTreePopupBinding.js @@ -157,9 +157,14 @@ SystemTreePopupBinding.prototype.handleAction = function ( action ) { case MenuItemBinding.ACTION_COMMAND : var menuitemBinding = action.target; var systemAction = menuitemBinding.associatedSystemAction; - var bundleName = systemAction.getBundleName(); + if ( systemAction ) { SystemAction.invoke(systemAction, this._node); + + var bundleName = systemAction.getBundleName(); + if (bundleName != null) { + LocalStorage.set(ToolBarComboButtonBinding.STORAGE_PREFFIX + bundleName, systemAction.getHandle()); + } } else { var cmd = menuitemBinding.getProperty ( "cmd" ); if ( cmd ) { @@ -167,10 +172,6 @@ SystemTreePopupBinding.prototype.handleAction = function ( action ) { } } - if (systemAction && bundleName) { - LocalStorage.set(ToolBarComboButtonBinding.STORAGE_PREFFIX + bundleName, systemAction.getHandle()); - } - // Clean current profile key this._currentProfileKey = null; break; diff --git a/Website/Composite/scripts/source/top/ui/bindings/trees/TreeNodeBinding.js b/Website/Composite/scripts/source/top/ui/bindings/trees/TreeNodeBinding.js index c7abd8cbe7..299c17d3ef 100644 --- a/Website/Composite/scripts/source/top/ui/bindings/trees/TreeNodeBinding.js +++ b/Website/Composite/scripts/source/top/ui/bindings/trees/TreeNodeBinding.js @@ -32,63 +32,68 @@ function TreeNodeBinding () { * @type {SystemLogger} */ this.logger = SystemLogger.getLogger ( "TreeNodeBinding" ); - + /** * @type {boolean} */ this.hasBeenOpened = false; - + /** * @type {boolean} */ this.isDisabled = false; - + /** * @type {boolean} */ this.isFocused = false; - + /** * @type {boolean} */ this.isOpen = false; - + + /** + * @type {boolean} + */ + this.isPinned = false; + /** * @type {boolean} */ this.isContainer = false; - + /** * @type {ImageProfile} */ this.imageProfile = null; - + /** * @type {string} */ this.image = null; - + /** * @type {string} */ this.imageHover = null; - + /** * @type {string} */ this.imageActive = null; - + /** * @type {string} */ this.imageDisabled = null; - + /** * The ancestor TreeBinding. * @type {TreeBinding} */ this.containingTreeBinding = null; - + /* * Return this. */ @@ -110,10 +115,10 @@ TreeNodeBinding.prototype.serialize = function () { var result = TreeNodeBinding.superclass.serialize.call ( this ); if ( result ) { - + result.label = this.getLabel (); result.image = this.getImage (); - + var handle = this.getHandle (); if ( handle && handle != this.key ) { result.handle = handle; @@ -138,9 +143,9 @@ TreeNodeBinding.prototype.serialize = function () { * @overloads {Binding#onBindingRegister} */ TreeNodeBinding.prototype.onBindingRegister = function () { - + TreeNodeBinding.superclass.onBindingRegister.call ( this ); - + this.propertyMethodMap [ "label" ] = this.setLabel; this.propertyMethodMap [ "image" ] = this.setImage; this.propertyMethodMap [ "tooltip" ] = this.setToolTip; @@ -154,8 +159,9 @@ TreeNodeBinding.prototype.onBindingRegister = function () { TreeNodeBinding.prototype.onBindingAttach = function () { TreeBinding.superclass.onBindingAttach.call ( this ); - + this.isOpen = this.isOpen ? true : this.getProperty ( "open" ); + this.isPinned = this.isPinned ? true : this.getProperty("pin"); if ( !this.isContainer ) { this.isContainer = this.hasChildren (); } @@ -166,13 +172,13 @@ TreeNodeBinding.prototype.onBindingAttach = function () { } this.addActionListener ( TreeNodeBinding.ACTION_FOCUSED ); this.addEventListener ( UpdateManager.EVENT_AFTERUPDATE ); - + /* * We do this last so that the tree may at this point change label etc. */ this._registerWithAncestorTreeBinding (); } - + /** * Overloads {Binding#onBindingDispose} */ @@ -194,10 +200,10 @@ TreeNodeBinding.prototype.onBindingDispose = function () { } /** - * Register with containing {@link TreeBinding}. - * To conserve computations, a pointer to the tree - * is copied from the nearest parent tree member. - * We cannot simply target the parent element + * Register with containing {@link TreeBinding}. + * To conserve computations, a pointer to the tree + * is copied from the nearest parent tree member. + * We cannot simply target the parent element * since this could be a {@link UpdatePanelBinding}. */ TreeNodeBinding.prototype._registerWithAncestorTreeBinding = function () { @@ -218,12 +224,12 @@ TreeNodeBinding.prototype._registerWithAncestorTreeBinding = function () { } /** - * The treenode will get registered by this index. + * The treenode will get registered by this index. * Subclasses can overwrite this method for added pleasure. * @return {string} */ TreeNodeBinding.prototype.getHandle = function () { - + var result = this.key; var handle = this.getProperty ( "handle" ); if ( handle ) { @@ -237,7 +243,7 @@ TreeNodeBinding.prototype.getHandle = function () { * @param {string} handle */ TreeNodeBinding.prototype.setHandle = function ( handle ) { - + this.setProperty ( "handle", handle ); } @@ -245,7 +251,7 @@ TreeNodeBinding.prototype.setHandle = function ( handle ) { * Build DOM content. */ TreeNodeBinding.prototype.buildDOMContent = function () { - + var url = this.getProperty ( "url" ); var label = this.getProperty ( "label" ); var tooltip = this.getProperty ( "tooltip" ); @@ -254,7 +260,7 @@ TreeNodeBinding.prototype.buildDOMContent = function () { var onblur = this.getProperty ( "onbindingblur" ); var focused = this.getProperty ( "focused" ); var callbackid = this.getProperty ( "callbackid" ); - + /* * Build URL */ @@ -264,7 +270,7 @@ TreeNodeBinding.prototype.buildDOMContent = function () { this.bindingElement.appendChild ( link ); this.shadowTree.link = link; } - + /* * Build label */ @@ -275,25 +281,25 @@ TreeNodeBinding.prototype.buildDOMContent = function () { this.addFirst ( this.labelBinding ); } this.shadowTree.label = this.labelBinding; // in order to exclude from serialization! - + if ( this.dragger != null ) { // have to transfer listeners to make the setup work! - + this.removeEventListener ( DOMEvents.MOUSEDOWN, this.dragger ); this.removeEventListener ( DOMEvents.MOUSEMOVE, this.dragger ); this.removeEventListener ( DOMEvents.MOUSEUP, this.dragger ); - + this.labelBinding.addEventListener ( DOMEvents.MOUSEDOWN, this.dragger ); this.labelBinding.addEventListener ( DOMEvents.MOUSEMOVE, this.dragger ); this.labelBinding.addEventListener ( DOMEvents.MOUSEUP, this.dragger ); - + } - + // TEMP!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // Binding.prototype._initializeBindingDragAndDropFeatures overload??? DRAGREJECT! if ( this.isContainer && !this.dragAccept ) { this.acceptor = new BindingAcceptor ( this ); } - + if ( label != null ) { this.setLabel ( label ); } @@ -303,15 +309,15 @@ TreeNodeBinding.prototype.buildDOMContent = function () { if ( !this.imageProfile ) { this._computeImageProfile (); } - this.setImage ( + this.setImage ( this.computeImage () ); if ( this.isContainer ) { this.updateClassNames (); } - + var manager = this.bindingWindow.WindowManager; - + if ( oncommand != null ) { this.oncommand = function () { Binding.evaluate ( oncommand, this ); @@ -327,13 +333,13 @@ TreeNodeBinding.prototype.buildDOMContent = function () { Binding.evaluate ( onblur, this ); }; } - + if ( focused == true ) { this.focus (); } - + /* - * Setup ASP.NET callback. One can only wonder why we need a + * Setup ASP.NET callback. One can only wonder why we need a * hidden field in order to communicate with the server... */ if ( callbackid != null ) { @@ -347,13 +353,13 @@ TreeNodeBinding.prototype.buildDOMContent = function () { * @param {Action} action */ TreeNodeBinding.prototype.handleAction = function ( action ) { - + TreeNodeBinding.superclass.handleAction.call ( this, action ); - + switch ( action.type ) { - + /* - * Make sure that a focused treenode is always + * Make sure that a focused treenode is always * visible by opening ancestor treenodes. */ case TreeNodeBinding.ACTION_FOCUSED : @@ -367,13 +373,13 @@ TreeNodeBinding.prototype.handleAction = function ( action ) { } /** - * Enable dragging. Special setup, adding event listeners to + * Enable dragging. Special setup, adding event listeners to * label, because treenodes consume the onmousedown event. * @overwrites {Binding#enableDragging} */ TreeNodeBinding.prototype.enableDragging = function () { - - /* + + /* * DISABLED! * this.isDraggable = true; @@ -398,22 +404,22 @@ TreeNodeBinding.prototype.disableDragging = function () { } /** - * Accept dragged binding. + * Accept dragged binding. * @implements {IAcceptable} * @param {Binding} binding * @param @optional {int} index * @return {boolean} */ TreeNodeBinding.prototype.accept = function ( binding, index ) { - + var isAccept = true; - + if ( binding instanceof TreeNodeBinding ) { - + var isAncestor = false; var element = this.bindingElement; var treeElement = this.containingTreeBinding.bindingElement; - + while ( !isAncestor && element != treeElement ) { if ( element == binding.getBindingElement ()) { isAncestor = true; @@ -421,7 +427,7 @@ TreeNodeBinding.prototype.accept = function ( binding, index ) { element = element.parentNode; } } - + if ( isAncestor ) { Dialog.error ( "Not Allowed", "You cannot move a folder into itself." ); isAccept = false; @@ -431,32 +437,32 @@ TreeNodeBinding.prototype.accept = function ( binding, index ) { } else { isAccept = false; } - + return isAccept; } /** - * Accept treenode.If properties get lost in transfer, remember + * Accept treenode.If properties get lost in transfer, remember * to update the {@link TreeNodeBinding#serialize} method. * @param {Binding} binding * @param @optional {int} */ TreeNodeBinding.prototype.acceptTreeNodeBinding = function ( binding, index ) { - + var serial = binding.serializeToString (); var parser = new BindingParser ( this.bindingDocument ); var element = parser.parseFromString ( serial ).getFirst (); - + index = index ? index : this.containingTreeBinding.getDropIndex (); var children = this.getChildElementsByLocalName ( "treenode" ); this.bindingElement.insertBefore ( element, children.get ( index )); - this.bindingWindow.DocumentManager.attachBindings ( - this.bindingElement + this.bindingWindow.DocumentManager.attachBindings ( + this.bindingElement ); - + /* * This part does not work because the "image" attribute - * has been set on bindingElement opon binding attach. + * has been set on bindingElement opon binding attach. * Fortunately we don't need it just now. * if ( !this.isContainer ) { @@ -465,12 +471,12 @@ TreeNodeBinding.prototype.acceptTreeNodeBinding = function ( binding, index ) { this.updateClassNames (); this._computeImageProfile (); alert ( this.imageProfile.getDefaultImage ()); - this.setImage ( + this.setImage ( this.computeImage () ); } */ - + binding.dispose (); } @@ -479,7 +485,7 @@ TreeNodeBinding.prototype.acceptTreeNodeBinding = function ( binding, index ) { * @implements {IAcceptable} */ TreeNodeBinding.prototype.showAcceptance = function () { - + this.containingTreeBinding.enablePositionIndicator ( this ); } @@ -488,7 +494,7 @@ TreeNodeBinding.prototype.showAcceptance = function () { * @implements {IAcceptable} */ TreeNodeBinding.prototype.hideAcceptance = function () { - + this.containingTreeBinding.disablePositionIndicator (); } @@ -500,18 +506,18 @@ TreeNodeBinding.prototype._computeImageProfile = function () { var image = this.getProperty ( "image" ); var imageActive = this.getProperty ( "image-active" ); var imageDisabled = this.getProperty ( "image-disabled" ); - - imageActive = imageActive ? imageActive : this.isContainer ? - image ? image : TreeNodeBinding.DEFAULT_FOLDER_OPEN : + + imageActive = imageActive ? imageActive : this.isContainer ? + image ? image : TreeNodeBinding.DEFAULT_FOLDER_OPEN : image ? image : TreeNodeBinding.DEFAULT_ITEM; - - imageDisabled = imageDisabled ? imageDisabled : this.isContainer ? - image ? image : TreeNodeBinding.DEFAULT_FOLDER_DISABLED : + + imageDisabled = imageDisabled ? imageDisabled : this.isContainer ? + image ? image : TreeNodeBinding.DEFAULT_FOLDER_DISABLED : image ? image : TreeNodeBinding.DEFAULT_ITEM_DISABLED; - - image = image ? image : this.isContainer ? + + image = image ? image : this.isContainer ? TreeNodeBinding.DEFAULT_FOLDER_CLOSED : TreeNodeBinding.DEFAULT_ITEM; - + this.imageProfile = new ImageProfile ({ image : image, imageHover : null, @@ -605,11 +611,11 @@ TreeNodeBinding.prototype.getToolTip = function () { * @return {string} */ TreeNodeBinding.prototype.computeImage = function () { - + var defaultImage = this.imageProfile.getDefaultImage (); var activeImage = this.imageProfile.getActiveImage (); activeImage = activeImage ? activeImage : defaultImage; - + return this.isOpen ? activeImage : defaultImage; } @@ -619,19 +625,19 @@ TreeNodeBinding.prototype.computeImage = function () { * @param {MouseEvent} e */ TreeNodeBinding.prototype.handleEvent = function ( e ) { - + TreeNodeBinding.superclass.handleEvent.call ( this, e ); - + var target = DOMEvents.getTarget ( e ); var label = this.labelBinding.bindingElement; var labelBody = this.labelBinding.shadowTree.labelBody; var labelText = this.labelBinding.shadowTree.labelText; - + /* * Tree navigation. */ switch ( e.type ) { - + case DOMEvents.MOUSEDOWN : if (target == label) { this._onAction(e); @@ -645,11 +651,11 @@ TreeNodeBinding.prototype.handleEvent = function ( e ) { case DOMEvents.DOUBLECLICK : this._onAction ( e ); break; - + case UpdateManager.EVENT_AFTERUPDATE : - + /* - * Hack a glitch where UpdateManager would + * Hack a glitch where UpdateManager would * insert treenodes before our label. */ if ( target.parentNode == this.bindingElement && target.__updateType == Update.TYPE_INSERT ) { @@ -663,14 +669,14 @@ TreeNodeBinding.prototype.handleEvent = function ( e ) { } break; } - + /* * Drag session timeouts. */ if ( BindingDragger.isDragging && this.isContainer && !this.isOpen ) { switch ( e.type ) { case DOMEvents.MOUSEOVER : - case DOMEvents.MOUSEOUT : + case DOMEvents.MOUSEOUT : switch ( target ) { case label : case labelBody : @@ -684,12 +690,12 @@ TreeNodeBinding.prototype.handleEvent = function ( e ) { } /** - * When dragging over a closed folder, the folder should open. + * When dragging over a closed folder, the folder should open. * Let's do it by setting and clearing a timeout. * @param {MouseEvent} e */ TreeNodeBinding.prototype._folderDragOverTimeout = function ( e ) { - + var self = this; switch ( e.type ) { case DOMEvents.MOUSEOVER : @@ -709,9 +715,9 @@ TreeNodeBinding.prototype._folderDragOverTimeout = function ( e ) { * @private */ TreeNodeBinding.prototype._onAction = function ( e ) { - + var isAction = true; - + if ( e.type == "mousedown" ) { var isLeftButton = e.button == ( e.target ? 0 : 1 ); if ( !isLeftButton ) { @@ -743,8 +749,8 @@ TreeNodeBinding.prototype.fireCommand = function () { } /** - * This will dispatch an event to the containing TreeBinding - * which in turn will invoke the focus method below. + * This will dispatch an event to the containing TreeBinding + * which in turn will invoke the focus method below. * @param {MouseEvent} */ TreeNodeBinding.prototype._onFocus = function ( e ) { @@ -753,9 +759,9 @@ TreeNodeBinding.prototype._onFocus = function ( e ) { if ( e != null ) { isMultiSelection = e.shiftKey; } - this.dispatchAction ( isMultiSelection ? - TreeNodeBinding.ACTION_ONMULTIFOCUS : - TreeNodeBinding.ACTION_ONFOCUS + this.dispatchAction ( isMultiSelection ? + TreeNodeBinding.ACTION_ONMULTIFOCUS : + TreeNodeBinding.ACTION_ONFOCUS ); if ( e != null ) { this.stopPropagation ( e ); @@ -771,14 +777,14 @@ TreeNodeBinding.prototype._onFocus = function ( e ) { } /** - * Call the server. This must be done whenever the client is - * setting the focus; it should not be done when the server + * Call the server. This must be done whenever the client is + * setting the focus; it should not be done when the server * is setting the focus. Also invoked by the TreeBinding! * @see {TreeBinding#_focusDefault} * @returns */ TreeNodeBinding.prototype.callback = function () { - + if ( this.hasCallBackID ()) { var self = this; setTimeout ( function () { // minimize freezing sensation @@ -791,7 +797,7 @@ TreeNodeBinding.prototype.callback = function () { * Focus the treenode managed. This method should only be invoked by the {@link TreeBinding}. */ TreeNodeBinding.prototype.invokeManagedFocus = function () { - + if ( !this.isFocused ) { this.isFocused = true; this.setProperty ( "focused", true ); @@ -804,7 +810,7 @@ TreeNodeBinding.prototype.invokeManagedFocus = function () { * Focus the treenode (public access point). */ TreeNodeBinding.prototype.focus = function () { - + this.setProperty ( "focused", true ); if ( this.isAttached ) { this._onFocus (); @@ -828,7 +834,7 @@ TreeNodeBinding.prototype.blur = function () { } /** - * Preventing event propagation internally in the tree + * Preventing event propagation internally in the tree * while still broadcasting a global mousedown event. * @param {MouseEvent} e * @private @@ -862,7 +868,7 @@ TreeNodeBinding.prototype.open = function () { */ TreeNodeBinding.prototype.close = function () { - if ( this.isContainer && this.isOpen ) { + if ( this.isContainer && this.isOpen && !this.isPinned) { this.isOpen = false; this.setProperty ( "open", false ); this.dispatchAction ( TreeNodeBinding.ACTION_CLOSE ); @@ -875,7 +881,7 @@ TreeNodeBinding.prototype.close = function () { * Updates treenode classnames when a container type node is handled. */ TreeNodeBinding.prototype.updateClassNames = function () { - + if ( this.isContainer ) { if ( !this.hasClassName ( "container" )) { this.attachClassName ( "container" ); @@ -905,7 +911,7 @@ TreeNodeBinding.prototype.updateClassNames = function () { * Dispose descendant treenodes. */ TreeNodeBinding.prototype.empty = function () { - + var descendants = this.getDescendantBindingsByLocalName ( "treenode" ); descendants.each ( function ( treenode ) { treenode.dispose (); @@ -917,7 +923,7 @@ TreeNodeBinding.prototype.empty = function () { * TODO: implement some interface around here! */ TreeNodeBinding.prototype.showDrag = function () { - + this.attachClassName ( TreeNodeBinding.CLASSNAME_DRAGGED ); } @@ -926,7 +932,7 @@ TreeNodeBinding.prototype.showDrag = function () { * TODO: implement some interface around here! */ TreeNodeBinding.prototype.hideDrag = function () { - + this.detachClassName ( TreeNodeBinding.CLASSNAME_DRAGGED ); } @@ -935,7 +941,7 @@ TreeNodeBinding.prototype.hideDrag = function () { * @return {boolean} */ TreeNodeBinding.prototype.hasChildren = function () { - + return this.bindingElement.hasChildNodes (); } @@ -945,13 +951,13 @@ TreeNodeBinding.prototype.hasChildren = function () { * @param {Element} element */ TreeNodeBinding.prototype.handleElement = function ( element ) { - + /* - * The problem here is that the server may move focus to - * this treenode in one postback response, but if the - * next response KEEPS he focus there are no CHANGES - * to the response. This way, user may be allowed to - * change focus in second attempt. Always nice to have + * The problem here is that the server may move focus to + * this treenode in one postback response, but if the + * next response KEEPS he focus there are no CHANGES + * to the response. This way, user may be allowed to + * change focus in second attempt. Always nice to have * the UI state on both the client and the server... */ var focused = element.getAttribute ( "focused" ); @@ -960,7 +966,7 @@ TreeNodeBinding.prototype.handleElement = function ( element ) { this.focus (); } } - + return false; // continue updates as normally! } diff --git a/Website/Composite/styles/default/fields/fields-base.less b/Website/Composite/styles/default/fields/fields-base.less index 185cd079f8..9789b278b8 100644 --- a/Website/Composite/styles/default/fields/fields-base.less +++ b/Website/Composite/styles/default/fields/fields-base.less @@ -278,7 +278,8 @@ ui|multiselector, ui|datadialog, ui|postbackdialog, ui|htmldatadialog, -ui|editortextbox { +ui|editortextbox, +ui|hierarchicalselector { padding: 2px; input { @@ -312,7 +313,7 @@ ui|editortextbox { } &.focused{ - ui|box, + ui|box, ui|clickbutton ui|labelbox { border: 1px solid @primary-color; } diff --git a/Website/Composite/styles/default/fields/selectors.less b/Website/Composite/styles/default/fields/selectors.less index a7417a150c..1b5d1f38f0 100644 --- a/Website/Composite/styles/default/fields/selectors.less +++ b/Website/Composite/styles/default/fields/selectors.less @@ -170,30 +170,50 @@ ui|field.fieldhelp ui|fielddata ui|urlinputdialog input { /* Hierarchical Selector */ -ui|hierarchicalselector{ - ui|treenode{ - &.checkbox{ +ui|hierarchicalselector { + ui|treenode { + &.checkbox { - ui|labelbox{ + > ui|labelbox { padding-left: 30px; } - ui|checkbutton{ + > ui|checkbutton { position: absolute; float: none; top: 2px; left: 18px; + height: 20px; } } ui|treenode { - &.checkbox{ - ui|checkbutton{ + &.checkbox { + ui|checkbutton { left: 40px; } } } } - > input{ + > input { display: none; } + + ui|box { + height: auto; + } + + &.invalid { + ui|labeltext { + font-weight: inherit; + } + } +} + +ui|wizardpage, +ui|dialogpage { + ui|hierarchicalselector{ + ui|box { + height: 600px; + } + } } \ No newline at end of file diff --git a/Website/Composite/styles/default/trees/trees-base.less b/Website/Composite/styles/default/trees/trees-base.less index e5e3569a9b..1bb5eea4b6 100644 --- a/Website/Composite/styles/default/trees/trees-base.less +++ b/Website/Composite/styles/default/trees/trees-base.less @@ -151,6 +151,20 @@ ui|treenode { display: none; } } + + &[pin='true'] { + > ui|labelbox { + &.open{ + &:before { + display: none; + } + + &:after { + display: none; + } + } + } + } } ui|tree > ui|treebody > ui|treenode.open { From ecd84c92a065686ba8cceba825b8be877572970f Mon Sep 17 00:00:00 2001 From: Morteza Kasravi Date: Wed, 9 Mar 2016 15:31:01 +0100 Subject: [PATCH 008/133] Adding Ignore Entity Token Locking feature which was ditched by mistake. remove IgnoreEntityTokenLocking Attribute. --- .../Actions/Data/ProxyDataActionToken.cs | 21 ++++++------ Composite/C1Console/Security/ActionToken.cs | 14 ++------ .../Security/IgnoreEntityTokenLocking.cs | 15 --------- Composite/Composite.csproj | 1 - .../GenericPublishProcessController.cs | 32 +++++++++---------- .../DisplayLocalOrderingActionToken.cs | 2 +- .../PageElementProvider/PageAddActionToken.cs | 4 +-- .../PageElementProvider.cs | 4 +-- 8 files changed, 34 insertions(+), 59 deletions(-) delete mode 100644 Composite/C1Console/Security/IgnoreEntityTokenLocking.cs diff --git a/Composite/C1Console/Actions/Data/ProxyDataActionToken.cs b/Composite/C1Console/Actions/Data/ProxyDataActionToken.cs index 16c80f1b43..f877056503 100644 --- a/Composite/C1Console/Actions/Data/ProxyDataActionToken.cs +++ b/Composite/C1Console/Actions/Data/ProxyDataActionToken.cs @@ -21,19 +21,19 @@ public ProxyDataActionToken( ActionIdentifier actionIdentifier) /// public ProxyDataActionToken(ActionIdentifier actionIdentifier, IEnumerable permissionTypes) : this(actionIdentifier) { - this._permissionTypes = permissionTypes; + _permissionTypes = permissionTypes; } /// public ActionIdentifier ActionIdentifier => _actionIdentifier; /// - public override IEnumerable PermissionTypes - { - get - { - return _permissionTypes ?? _actionIdentifier.Permissions(); - } - } + public bool DoIgnoreEntityTokenLocking { get; set;} + + /// + public override bool IgnoreEntityTokenLocking => DoIgnoreEntityTokenLocking; + + /// + public override IEnumerable PermissionTypes => _permissionTypes ?? _actionIdentifier.Permissions(); /// public override string Serialize() @@ -42,6 +42,7 @@ public override string Serialize() StringConversionServices.SerializeKeyValuePair(stringBuilder, "_ActionIdentifier_", ActionIdentifier.Serialize()); StringConversionServices.SerializeKeyValuePair(stringBuilder, "_PermissionTypes_", PermissionTypes.SerializePermissionTypes()); + StringConversionServices.SerializeKeyValuePair(stringBuilder, "_DoIgnoreEntityTokenLocking_", DoIgnoreEntityTokenLocking); return stringBuilder.ToString(); } @@ -59,7 +60,9 @@ public static ActionToken Deserialize(string serializedData) string permissionTypesString = StringConversionServices.DeserializeValueString(dic["_PermissionTypes_"]); - var result = new ProxyDataActionToken(ActionIdentifier.Deserialize(serializedType), permissionTypesString.DesrializePermissionTypes()); + bool doIgnoreEntityTokenLocking = StringConversionServices.DeserializeValueBool(dic["_DoIgnoreEntityTokenLocking_"]); + + var result = new ProxyDataActionToken(ActionIdentifier.Deserialize(serializedType), permissionTypesString.DesrializePermissionTypes()) {DoIgnoreEntityTokenLocking = doIgnoreEntityTokenLocking}; return result; } diff --git a/Composite/C1Console/Security/ActionToken.cs b/Composite/C1Console/Security/ActionToken.cs index cf4370d15f..7fd93149cf 100644 --- a/Composite/C1Console/Security/ActionToken.cs +++ b/Composite/C1Console/Security/ActionToken.cs @@ -31,21 +31,11 @@ internal static class ActionTokenExtensionMethods public static bool IsIgnoreEntityTokenLocking(this ActionToken actionToken) { - if (actionToken == null) throw new ArgumentNullException("actionToken"); + if (actionToken == null) throw new ArgumentNullException(nameof(actionToken)); - Type type = actionToken.GetType(); - lock (_lock) { - bool ignoreLocking; - if (_ignoreEntityTokenLockingCache.TryGetValue(type, out ignoreLocking) == false) - { - ignoreLocking = type.GetCustomAttributesRecursively().Any() ; - - _ignoreEntityTokenLockingCache.Add(type, ignoreLocking); - } - - return ignoreLocking | actionToken.IgnoreEntityTokenLocking; + return actionToken.IgnoreEntityTokenLocking; } } } diff --git a/Composite/C1Console/Security/IgnoreEntityTokenLocking.cs b/Composite/C1Console/Security/IgnoreEntityTokenLocking.cs deleted file mode 100644 index 92a25a858a..0000000000 --- a/Composite/C1Console/Security/IgnoreEntityTokenLocking.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; - - -namespace Composite.C1Console.Security -{ - /// - /// If this attribute is specified on an ActionToken, then the action will ignore EntityToken locking - /// - /// - [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] - [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)] - public sealed class IgnoreEntityTokenLocking : Attribute - { - } -} diff --git a/Composite/Composite.csproj b/Composite/Composite.csproj index de1127cfc7..9f57eb32aa 100644 --- a/Composite/Composite.csproj +++ b/Composite/Composite.csproj @@ -1627,7 +1627,6 @@ - diff --git a/Composite/Data/ProcessControlled/ProcessControllers/GenericPublishProcessController/GenericPublishProcessController.cs b/Composite/Data/ProcessControlled/ProcessControllers/GenericPublishProcessController/GenericPublishProcessController.cs index cec9cb8e4b..b74d3770b8 100644 --- a/Composite/Data/ProcessControlled/ProcessControllers/GenericPublishProcessController/GenericPublishProcessController.cs +++ b/Composite/Data/ProcessControlled/ProcessControllers/GenericPublishProcessController/GenericPublishProcessController.cs @@ -113,7 +113,7 @@ public GenericPublishProcessController() {Published, "Published"} }; - Func sendBackToDraftAction = () => new ElementAction(new ActionHandle(new ProxyDataActionToken(ActionIdentifier.SendToDraft))) + Func sendBackToDraftAction = () => new ElementAction(new ActionHandle(new ProxyDataActionToken(ActionIdentifier.SendToDraft) { DoIgnoreEntityTokenLocking = true })) { VisualData = new ActionVisualizedData { @@ -132,7 +132,7 @@ public GenericPublishProcessController() }; - Func sendForwardToAwaitingApprovalAction = () => new ElementAction(new ActionHandle(new ProxyDataActionToken(ActionIdentifier.SendForApproval))) + Func sendForwardToAwaitingApprovalAction = () => new ElementAction(new ActionHandle(new ProxyDataActionToken(ActionIdentifier.SendForApproval) { DoIgnoreEntityTokenLocking = true })) { VisualData = new ActionVisualizedData { @@ -151,7 +151,7 @@ public GenericPublishProcessController() }; - Func sendForwardToAwaitingPublicationAction = () => new ElementAction(new ActionHandle(new ProxyDataActionToken(ActionIdentifier.SendForPublication))) + Func sendForwardToAwaitingPublicationAction = () => new ElementAction(new ActionHandle(new ProxyDataActionToken(ActionIdentifier.SendForPublication) { DoIgnoreEntityTokenLocking = true })) { VisualData = new ActionVisualizedData { @@ -170,7 +170,7 @@ public GenericPublishProcessController() }; - Func publishAction = () => new ElementAction(new ActionHandle(new ProxyDataActionToken(ActionIdentifier.Publish))) + Func publishAction = () => new ElementAction(new ActionHandle(new ProxyDataActionToken(ActionIdentifier.Publish) {DoIgnoreEntityTokenLocking = true})) { VisualData = new ActionVisualizedData { @@ -190,7 +190,7 @@ public GenericPublishProcessController() // "arrow pointing left when state change is going backwards" actions - Func sendBackToAwaitingApprovalAction = () => new ElementAction(new ActionHandle(new ProxyDataActionToken(ActionIdentifier.SendForApproval))) + Func sendBackToAwaitingApprovalAction = () => new ElementAction(new ActionHandle(new ProxyDataActionToken(ActionIdentifier.SendForApproval) { DoIgnoreEntityTokenLocking = true })) { VisualData = new ActionVisualizedData { @@ -209,7 +209,7 @@ public GenericPublishProcessController() }; - Func sendBackToAwaitingPublicationAction = () => new ElementAction(new ActionHandle(new ProxyDataActionToken(ActionIdentifier.SendForPublication))) + Func sendBackToAwaitingPublicationAction = () => new ElementAction(new ActionHandle(new ProxyDataActionToken(ActionIdentifier.SendForPublication) { DoIgnoreEntityTokenLocking = true })) { VisualData = new ActionVisualizedData { @@ -229,7 +229,7 @@ public GenericPublishProcessController() // disabled actions - Func draftActionDisabled = () => new ElementAction(new ActionHandle(new ProxyDataActionToken(ActionIdentifier.SendToDraft))) + Func draftActionDisabled = () => new ElementAction(new ActionHandle(new ProxyDataActionToken(ActionIdentifier.SendToDraft) { DoIgnoreEntityTokenLocking = true })) { VisualData = new ActionVisualizedData { @@ -248,7 +248,7 @@ public GenericPublishProcessController() }; - Func awaitingApprovalActionDisabled = () => new ElementAction(new ActionHandle(new ProxyDataActionToken(ActionIdentifier.SendForApproval))) + Func awaitingApprovalActionDisabled = () => new ElementAction(new ActionHandle(new ProxyDataActionToken(ActionIdentifier.SendForApproval) { DoIgnoreEntityTokenLocking = true })) { VisualData = new ActionVisualizedData { @@ -267,7 +267,7 @@ public GenericPublishProcessController() }; - Func awaitingPublicationActionDisabled = () => new ElementAction(new ActionHandle(new ProxyDataActionToken(ActionIdentifier.SendForPublication))) + Func awaitingPublicationActionDisabled = () => new ElementAction(new ActionHandle(new ProxyDataActionToken(ActionIdentifier.SendForPublication) { DoIgnoreEntityTokenLocking = true })) { VisualData = new ActionVisualizedData { @@ -347,7 +347,7 @@ public List GetActions(IData data, Type elementProviderType) IData publicData = DataFacade.GetDataFromOtherScope(data, DataScopeIdentifier.Public, true).FirstOrDefault(); if (publicData != null) { - var unpublishAction = new ElementAction(new ActionHandle(new ProxyDataActionToken(ActionIdentifier.Unpublish))) + var unpublishAction = new ElementAction(new ActionHandle(new ProxyDataActionToken(ActionIdentifier.Unpublish) { DoIgnoreEntityTokenLocking = true })) { VisualData = new ActionVisualizedData() { @@ -651,7 +651,6 @@ public static ActionToken Deserialize(string serializedData) } - [IgnoreEntityTokenLocking()] [ActionExecutor(typeof(PublishActionExecutor))] internal sealed class PublishActionToken : ActionToken { @@ -662,6 +661,7 @@ public override IEnumerable PermissionTypes get { return _permissionTypes; } } + public override bool IgnoreEntityTokenLocking => true; public override string Serialize() { @@ -676,7 +676,6 @@ public static ActionToken Deserialize(string serializedData) } - [IgnoreEntityTokenLocking()] [ActionExecutor(typeof(PublishActionExecutor))] internal sealed class UnpublishActionToken : ActionToken { @@ -687,6 +686,7 @@ public override IEnumerable PermissionTypes get { return _permissionTypes; } } + public override bool IgnoreEntityTokenLocking => true; public override string Serialize() { @@ -701,7 +701,6 @@ public static ActionToken Deserialize(string serializedData) } - [IgnoreEntityTokenLocking()] [ActionExecutor(typeof(PublishActionExecutor))] internal sealed class UndoPublishedChangesActionToken : ActionToken { @@ -712,6 +711,7 @@ public override IEnumerable PermissionTypes get { return _permissionTypes; } } + public override bool IgnoreEntityTokenLocking => true; public override string Serialize() { @@ -726,7 +726,6 @@ public static ActionToken Deserialize(string serializedData) } - [IgnoreEntityTokenLocking()] [ActionExecutor(typeof(PublishActionExecutor))] internal sealed class DraftActionToken : ActionToken { @@ -737,6 +736,7 @@ public override IEnumerable PermissionTypes get { return _permissionTypes; } } + public override bool IgnoreEntityTokenLocking => true; public override string Serialize() { @@ -751,7 +751,6 @@ public static ActionToken Deserialize(string serializedData) } - [IgnoreEntityTokenLocking()] [ActionExecutor(typeof(PublishActionExecutor))] internal sealed class AwaitingApprovalActionToken : ActionToken { @@ -762,6 +761,7 @@ public override IEnumerable PermissionTypes get { return _permissionTypes; } } + public override bool IgnoreEntityTokenLocking => true; public override string Serialize() { @@ -776,7 +776,6 @@ public static Composite.C1Console.Security.ActionToken Deserialize(string serial } - [IgnoreEntityTokenLocking()] [ActionExecutor(typeof(PublishActionExecutor))] internal sealed class AwaitingPublicationActionToken : ActionToken { @@ -787,6 +786,7 @@ public override IEnumerable PermissionTypes get { return _permissionTypes; } } + public override bool IgnoreEntityTokenLocking => true; public override string Serialize() { diff --git a/Composite/Plugins/Elements/ElementProviders/PageElementProvider/LocalOrdering/DisplayLocalOrderingActionToken.cs b/Composite/Plugins/Elements/ElementProviders/PageElementProvider/LocalOrdering/DisplayLocalOrderingActionToken.cs index 206424eb86..e681fa9646 100644 --- a/Composite/Plugins/Elements/ElementProviders/PageElementProvider/LocalOrdering/DisplayLocalOrderingActionToken.cs +++ b/Composite/Plugins/Elements/ElementProviders/PageElementProvider/LocalOrdering/DisplayLocalOrderingActionToken.cs @@ -6,7 +6,6 @@ namespace Composite.Plugins.Elements.ElementProviders.PageElementProvider.LocalOrdering { - [IgnoreEntityTokenLocking()] [ActionExecutor(typeof(DisplayLocalOrderingActionExecutor))] internal sealed class DisplayLocalOrderingActionToken : ActionToken { @@ -25,6 +24,7 @@ public Guid ParentPageId private set; } + public override bool IgnoreEntityTokenLocking => true; public override IEnumerable PermissionTypes { diff --git a/Composite/Plugins/Elements/ElementProviders/PageElementProvider/PageAddActionToken.cs b/Composite/Plugins/Elements/ElementProviders/PageElementProvider/PageAddActionToken.cs index 874d82e6fa..18c9c29062 100644 --- a/Composite/Plugins/Elements/ElementProviders/PageElementProvider/PageAddActionToken.cs +++ b/Composite/Plugins/Elements/ElementProviders/PageElementProvider/PageAddActionToken.cs @@ -26,8 +26,6 @@ public PageAddActionToken(Guid pageTypeId, ActionIdentifier actionIdentifier, IE /// public Guid PageTypeId => _pageTypeId; - public override bool IgnoreEntityTokenLocking => true; - public override string Serialize() { StringBuilder stringBuilder = new StringBuilder(base.Serialize()); @@ -45,7 +43,7 @@ public override string Serialize() var baseProxyDataActionToken = (ProxyDataActionToken)ProxyDataActionToken.Deserialize(serializedData); - var result = new PageAddActionToken(pageTypeId, baseProxyDataActionToken.ActionIdentifier, baseProxyDataActionToken.PermissionTypes); + var result = new PageAddActionToken(pageTypeId, baseProxyDataActionToken.ActionIdentifier, baseProxyDataActionToken.PermissionTypes) { DoIgnoreEntityTokenLocking = baseProxyDataActionToken.IgnoreEntityTokenLocking }; return result; } diff --git a/Composite/Plugins/Elements/ElementProviders/PageElementProvider/PageElementProvider.cs b/Composite/Plugins/Elements/ElementProviders/PageElementProvider/PageElementProvider.cs index 1e4fcb9a0a..88b3515fcd 100644 --- a/Composite/Plugins/Elements/ElementProviders/PageElementProvider/PageElementProvider.cs +++ b/Composite/Plugins/Elements/ElementProviders/PageElementProvider/PageElementProvider.cs @@ -141,7 +141,7 @@ var pageType in { element.AddAction( new ElementAction( - new ActionHandle(new PageAddActionToken(pageType.Id, ActionIdentifier.Add, AddPermissionTypes) {} )) + new ActionHandle(new PageAddActionToken(pageType.Id, ActionIdentifier.Add, AddPermissionTypes) {DoIgnoreEntityTokenLocking = true} )) { VisualData = new ActionVisualizedData { @@ -713,7 +713,7 @@ private List GetElements(List> pag foreach (var pageType in page.GetChildPageSelectablePageTypes().OrderByDescending(pt => pt.Id == parentPageType.DefaultChildPageType)) { - element.AddAction(new ElementAction(new ActionHandle(new PageAddActionToken(pageType.Id,ActionIdentifier.Add, AddPermissionTypes))) + element.AddAction(new ElementAction(new ActionHandle(new PageAddActionToken(pageType.Id,ActionIdentifier.Add, AddPermissionTypes) { DoIgnoreEntityTokenLocking = true })) { VisualData = new ActionVisualizedData { From 91cccf874cd1d686567ebc5e0ca4e1d0becaab3e Mon Sep 17 00:00:00 2001 From: neexite Date: Wed, 9 Mar 2016 16:52:23 +0200 Subject: [PATCH 009/133] HierarchicalSelector: +"Required" property require at least one selected not readonly item +Do not update tree on persist request --- .../selectors/HierarchicalSelectorBinding.js | 23 ++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/Website/Composite/scripts/source/top/ui/bindings/data/selectors/HierarchicalSelectorBinding.js b/Website/Composite/scripts/source/top/ui/bindings/data/selectors/HierarchicalSelectorBinding.js index b6a3da083b..1fc6c6a307 100644 --- a/Website/Composite/scripts/source/top/ui/bindings/data/selectors/HierarchicalSelectorBinding.js +++ b/Website/Composite/scripts/source/top/ui/bindings/data/selectors/HierarchicalSelectorBinding.js @@ -192,6 +192,27 @@ HierarchicalSelectorBinding.prototype.handleAction = function ( action ) { } } +/** + * @implements {IUpdateHandler} + * @overwrites {Binding#handleElement} + * @param {Element} element + */ +HierarchicalSelectorBinding.prototype.handleElement = function (element) { + + return true; // do handle element update +} + +/** + * @implements {IUpdateHandler} + * @overwrites {Binding#updateElement} + * @param {Element} element + */ +HierarchicalSelectorBinding.prototype.updateElement = function (element) { + + return true; // stop crawling descendants +} + + // IMPLEMENT IDATA ........................................................... /** @@ -204,7 +225,7 @@ HierarchicalSelectorBinding.prototype.validate = function () { if (this.isRequired) { isValid = false; this.getDescendantBindingsByType(CheckTreeNodeBinding).each(function(treenode) { - if (treenode.isSelectable && treenode.isChecked()) { + if (treenode.isSelectable && !treenode.isReadOnly && treenode.isChecked()) { isValid = true; return false; } From 0028c873620369937618778764988a78e356723c Mon Sep 17 00:00:00 2001 From: Morteza Kasravi Date: Wed, 9 Mar 2016 15:59:58 +0100 Subject: [PATCH 010/133] Changes to ease translation process --- .../PageElementProvider/AddNewPageWorkflow.cs | 2 +- Composite/C1Console/Security/ActionToken.cs | 8 +------- .../PageElementProvider/PageElementProvider.cs | 2 +- .../Composite.Plugins.PageElementProvider.en-us.xml | 6 ++++-- 4 files changed, 7 insertions(+), 11 deletions(-) diff --git a/Composite.Workflows/Plugins/Elements/ElementProviders/PageElementProvider/AddNewPageWorkflow.cs b/Composite.Workflows/Plugins/Elements/ElementProviders/PageElementProvider/AddNewPageWorkflow.cs index c7a64a73c5..5358452bc0 100644 --- a/Composite.Workflows/Plugins/Elements/ElementProviders/PageElementProvider/AddNewPageWorkflow.cs +++ b/Composite.Workflows/Plugins/Elements/ElementProviders/PageElementProvider/AddNewPageWorkflow.cs @@ -277,7 +277,7 @@ private void stepInitialize_codeActivity_ExecuteCode(object sender, EventArgs e) bindings.Add("NewPage", newPage); - bindings.Add("Title", string.Format(GetText("AddNewPageStep1.DialogLabel"), pageType)); + bindings.Add("Title", string.Format(GetText("AddNewPageStep1.DialogLabelFormat"), pageType)); bindings.Add("UrlTitleIsRequired", true /* ThereAreOtherPages()*/); diff --git a/Composite/C1Console/Security/ActionToken.cs b/Composite/C1Console/Security/ActionToken.cs index 7fd93149cf..e9aa229930 100644 --- a/Composite/C1Console/Security/ActionToken.cs +++ b/Composite/C1Console/Security/ActionToken.cs @@ -26,17 +26,11 @@ public abstract class ActionToken internal static class ActionTokenExtensionMethods { - private static Dictionary _ignoreEntityTokenLockingCache = new Dictionary(); - private static readonly object _lock = new object(); - public static bool IsIgnoreEntityTokenLocking(this ActionToken actionToken) { if (actionToken == null) throw new ArgumentNullException(nameof(actionToken)); - lock (_lock) - { - return actionToken.IgnoreEntityTokenLocking; - } + return actionToken.IgnoreEntityTokenLocking; } } } diff --git a/Composite/Plugins/Elements/ElementProviders/PageElementProvider/PageElementProvider.cs b/Composite/Plugins/Elements/ElementProviders/PageElementProvider/PageElementProvider.cs index 88b3515fcd..0976f24596 100644 --- a/Composite/Plugins/Elements/ElementProviders/PageElementProvider/PageElementProvider.cs +++ b/Composite/Plugins/Elements/ElementProviders/PageElementProvider/PageElementProvider.cs @@ -146,7 +146,7 @@ var pageType in VisualData = new ActionVisualizedData { Label = string.Format(StringResourceSystemFacade.GetString("Composite.Plugins.PageElementProvider", - "PageElementProvider.AddPageAtRoot"), pageType.Name), + "PageElementProvider.AddPageAtRootFormat"), pageType.Name), ToolTip = StringResourceSystemFacade.GetString("Composite.Plugins.PageElementProvider", "PageElementProvider.AddPageAtRootToolTip"), diff --git a/Website/Composite/localization/Composite.Plugins.PageElementProvider.en-us.xml b/Website/Composite/localization/Composite.Plugins.PageElementProvider.en-us.xml index 1cf0d8763a..14f47e0840 100644 --- a/Website/Composite/localization/Composite.Plugins.PageElementProvider.en-us.xml +++ b/Website/Composite/localization/Composite.Plugins.PageElementProvider.en-us.xml @@ -1,6 +1,7 @@  - + + @@ -62,7 +63,8 @@ - + + From 631467fb6f9ba4622813ce790133ad790ed13d1b Mon Sep 17 00:00:00 2001 From: Dmitry Dzygin Date: Wed, 9 Mar 2016 17:33:37 +0100 Subject: [PATCH 011/133] HierarchicalSelector - removing MultiSelection property, adding AutoSelectChildren --- .../Forms/CoreUiControls/HierarchicalSelectorUiControl.cs | 2 +- .../TemplatedHierarchicalSelectorUiControlFactory.cs | 4 ++-- .../Selectors/HierarchicalSelector.ascx | 4 +++- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/Composite/C1Console/Forms/CoreUiControls/HierarchicalSelectorUiControl.cs b/Composite/C1Console/Forms/CoreUiControls/HierarchicalSelectorUiControl.cs index d3d9849696..20f34b9ade 100644 --- a/Composite/C1Console/Forms/CoreUiControls/HierarchicalSelectorUiControl.cs +++ b/Composite/C1Console/Forms/CoreUiControls/HierarchicalSelectorUiControl.cs @@ -15,7 +15,7 @@ internal abstract class HierarchicalSelectorUiControl : UiControl public IEnumerable TreeNodes { get; set; } [FormsProperty] - public bool MultiSelection { get; set; } + public bool AutoSelectChildren { get; set; } [FormsProperty] public bool Required { get; set; } diff --git a/Composite/Plugins/Forms/WebChannel/UiControlFactories/TemplatedHierarchicalSelectorUiControlFactory.cs b/Composite/Plugins/Forms/WebChannel/UiControlFactories/TemplatedHierarchicalSelectorUiControlFactory.cs index 7901a352b9..e1ec466fb2 100644 --- a/Composite/Plugins/Forms/WebChannel/UiControlFactories/TemplatedHierarchicalSelectorUiControlFactory.cs +++ b/Composite/Plugins/Forms/WebChannel/UiControlFactories/TemplatedHierarchicalSelectorUiControlFactory.cs @@ -46,7 +46,7 @@ internal void InitializeWebViewState() public IEnumerable TreeNodes { get; set; } /// - public bool MultiSelection { get; set; } + public bool AutoSelectChildren { get; set; } /// public bool Required { get; set; } @@ -83,7 +83,7 @@ public Control BuildWebControl() _userControl.SelectedKeys = this.SelectedKeys; _userControl.TreeNodes = this.TreeNodes; - _userControl.MultiSelection = this.MultiSelection; + _userControl.AutoSelectChildren = this.AutoSelectChildren; _userControl.Required = this.Required; return _userControl; diff --git a/Website/Composite/controls/FormsControls/FormUiControlTemplates/Selectors/HierarchicalSelector.ascx b/Website/Composite/controls/FormsControls/FormUiControlTemplates/Selectors/HierarchicalSelector.ascx index fde3c75690..fdd0b7e16c 100644 --- a/Website/Composite/controls/FormsControls/FormUiControlTemplates/Selectors/HierarchicalSelector.ascx +++ b/Website/Composite/controls/FormsControls/FormUiControlTemplates/Selectors/HierarchicalSelector.ascx @@ -92,6 +92,8 @@ -" autoselectchildren="true"> +" + autoselectchildren="<%= AutoSelectChildren ? "true" : "false" %>"> <%= _treeXhml %> From 6ab114d422b3a6b01eb065456f7d928916aeefe5 Mon Sep 17 00:00:00 2001 From: neexite Date: Thu, 10 Mar 2016 14:45:18 +0200 Subject: [PATCH 012/133] Fix #124 Long values in the function parameter field box makes it wider and overlapping --- Website/Composite/styles/default/dialogs/dialogs.less | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Website/Composite/styles/default/dialogs/dialogs.less b/Website/Composite/styles/default/dialogs/dialogs.less index fcc946117c..609e786660 100644 --- a/Website/Composite/styles/default/dialogs/dialogs.less +++ b/Website/Composite/styles/default/dialogs/dialogs.less @@ -168,6 +168,17 @@ ui|dialogpage.functionview-basic { display: inline-block; } /* IE 10, 11 */ + + + ui|fielddata { + width: @functionsbasic-column-width; + } + + &.fieldhelp { + ui|fielddata { + width: @functionsbasic-column-width - 30px; + } + } } From d97896b7d8fcb11582bf33c83665455abf272eca Mon Sep 17 00:00:00 2001 From: Marcus Wendt Date: Thu, 10 Mar 2016 13:45:33 +0100 Subject: [PATCH 013/133] Fixing #138, removing dead field from Page Type edit view --- .../content/forms/Administrative/PageTypeEditPageType.xml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Website/Composite/content/forms/Administrative/PageTypeEditPageType.xml b/Website/Composite/content/forms/Administrative/PageTypeEditPageType.xml index c455b5570e..983cc46641 100644 --- a/Website/Composite/content/forms/Administrative/PageTypeEditPageType.xml +++ b/Website/Composite/content/forms/Administrative/PageTypeEditPageType.xml @@ -34,10 +34,6 @@ - - - -