}
};
+ // Validates that a drag-n-drop action is allowed
+ $scope.onDrop = function(event, ui) {
+ var sort = ui.item.sortable;
+ // Check if this is a callback for an item dropped into a different container
+ // @see https://github.com/angular-ui/ui-sortable notes on canceling
+ if (!sort.received && sort.source[0] !== sort.droptarget[0]) {
+ var $source = $(sort.source[0]),
+ $target = $(sort.droptarget[0]),
+ $item = $(ui.item[0]);
+ // Fields cannot be dropped outside their own entity
+ if ($item.is('[af-gui-field]') || $item.has('[af-gui-field]').length) {
+ if ($source.closest('[data-entity]').attr('data-entity') !== $target.closest('[data-entity]').attr('data-entity')) {
+ return sort.cancel();
+ }
+ }
+ // Entity-fieldsets cannot be dropped into other entity-fieldsets
+ if (($item.is('[data-entity]') || $item.has('[data-entity]').length) && $target.closest('[data-entity]').length) {
+ return sort.cancel();
+ }
+ }
+ };
+
$scope.tags = {
div: ts('Block'),
fieldset: ts('Fieldset')
</ul>
</div>
</div>
-<div ui-sortable="{handle: '.af-gui-bar', connectWith: '[ui-sortable]', cancel: 'input,textarea,button,select,option,a'}" ng-model="node['#children']" class="af-gui-layout {{ getLayout() }}">
- <div ng-repeat="item in node['#children']" ng-show="block.getNodeType(item)">
+<div ui-sortable="{handle: '.af-gui-bar', update: onDrop, connectWith: '[ui-sortable]', cancel: 'input,textarea,button,select,option,a'}" ng-model="node['#children']" class="af-gui-layout {{ getLayout() }}">
+ <div ng-repeat="item in node['#children']" >
<div ng-switch="block.getNodeType(item)">
<div ng-switch-when="fieldset" af-gui-block="item" class="af-gui-block af-gui-fieldset af-gui-block-type-{{ item['#tag'] }}" ng-class="{'af-entity-selected': isSelectedFieldset(item['af-fieldset'])}" entity-name="item['af-fieldset']" data-entity="{{ item['af-fieldset'] }}" />
<div ng-switch-when="block" af-gui-block="item" class="af-gui-block af-gui-block-type-{{ item['#tag'] }}" entity-name="entityName" />