U4-7179: add layout selector to list view
This commit is contained in:
@@ -0,0 +1,105 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
function LayoutSelectorDirective() {
|
||||
|
||||
function link(scope, el, attr, ctrl) {
|
||||
|
||||
scope.layoutDropDownIsOpen = false;
|
||||
scope.showLayoutSelector = true;
|
||||
|
||||
function activate() {
|
||||
|
||||
setVisibility();
|
||||
|
||||
setActiveLayout(scope.layouts);
|
||||
|
||||
}
|
||||
|
||||
function setVisibility() {
|
||||
|
||||
var numberOfAllowedLayouts = getNumberOfAllowedLayouts(scope.layouts);
|
||||
|
||||
if(numberOfAllowedLayouts === 1) {
|
||||
scope.showLayoutSelector = false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function getNumberOfAllowedLayouts(layouts) {
|
||||
|
||||
var allowedLayouts = 0;
|
||||
|
||||
for (var i = 0; layouts.length > i; i++) {
|
||||
|
||||
var layout = layouts[i];
|
||||
|
||||
if(layout.selected === true) {
|
||||
allowedLayouts++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return allowedLayouts;
|
||||
}
|
||||
|
||||
function setActiveLayout(layouts) {
|
||||
|
||||
for (var i = 0; layouts.length > i; i++) {
|
||||
|
||||
var layout = layouts[i];
|
||||
|
||||
if(layout.name === scope.activeLayout.name && layout.path === scope.activeLayout.path) {
|
||||
layout.active = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
scope.pickLayout = function(selectedLayout) {
|
||||
|
||||
for (var i = 0; scope.layouts.length > i; i++) {
|
||||
|
||||
var layout = scope.layouts[i];
|
||||
|
||||
layout.active = false;
|
||||
}
|
||||
|
||||
selectedLayout.active = true;
|
||||
|
||||
scope.activeLayout = selectedLayout;
|
||||
|
||||
scope.layoutDropDownIsOpen = false;
|
||||
|
||||
};
|
||||
|
||||
scope.toggleLayoutDropdown = function() {
|
||||
scope.layoutDropDownIsOpen = !scope.layoutDropDownIsOpen;
|
||||
};
|
||||
|
||||
scope.closeLayoutDropdown = function() {
|
||||
scope.layoutDropDownIsOpen = false;
|
||||
};
|
||||
|
||||
activate();
|
||||
|
||||
}
|
||||
|
||||
var directive = {
|
||||
restrict: 'E',
|
||||
replace: true,
|
||||
templateUrl: 'views/components/umb-layout-selector.html',
|
||||
scope: {
|
||||
layouts: '=',
|
||||
activeLayout: '='
|
||||
},
|
||||
link: link
|
||||
};
|
||||
|
||||
return directive;
|
||||
}
|
||||
|
||||
angular.module('umbraco.directives').directive('umbLayoutSelector', LayoutSelectorDirective);
|
||||
|
||||
})();
|
||||
@@ -95,6 +95,7 @@
|
||||
@import "components/umb-tabs.less";
|
||||
@import "components/umb-load-indicator.less";
|
||||
@import "components/umb-breadcrumbs.less";
|
||||
@import "components/umb-layout-selector.less";
|
||||
@import "components/overlays/umb-overlay-backdrop.less";
|
||||
|
||||
@import "components/buttons/umb-button.less";
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
.umb-layout-selector {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.umb-layout-selector__active-layout {
|
||||
box-sizing: border-box;
|
||||
border: 1px solid transparent;
|
||||
cursor: pointer;
|
||||
height: 30px;
|
||||
width: 30px;
|
||||
margin: 0 8px;
|
||||
font-size: 20px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.umb-layout-selector__active-layout:hover {
|
||||
border-color: @grayLight;
|
||||
}
|
||||
|
||||
.umb-layout-selector__dropdown {
|
||||
position: absolute;
|
||||
padding: 5px;
|
||||
background: #333;
|
||||
z-index: 999;
|
||||
display: flex;
|
||||
background: #fff;
|
||||
flex-wrap: wrap;
|
||||
flex-direction: column;
|
||||
transform: translate(-50%,0);
|
||||
left: 50%;
|
||||
}
|
||||
|
||||
.umb-layout-selector__dropdown-item {
|
||||
padding: 5px;
|
||||
margin: 3px 5px;
|
||||
display: flex;
|
||||
align-content: center;
|
||||
justify-content: center;
|
||||
border: 1px solid transparent;
|
||||
flex-direction: column;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.umb-layout-selector__dropdown-item:hover {
|
||||
border: 1px solid @grayLight;
|
||||
}
|
||||
|
||||
.umb-layout-selector__dropdown-item.-active {
|
||||
border: 1px solid @blue;
|
||||
}
|
||||
|
||||
.umb-layout-selector__dropdown-item-icon {
|
||||
font-size: 20px;
|
||||
color: @gray;
|
||||
text-align: center;
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
<div class="umb-layout-selector" ng-show="showLayoutSelector">
|
||||
|
||||
<div class="umb-layout-selector__active-layout" ng-click="toggleLayoutDropdown()">
|
||||
<i class="{{ activeLayout.icon }}"></i>
|
||||
</div>
|
||||
|
||||
<div ng-if="layoutDropDownIsOpen" class="umb-layout-selector__dropdown shadow-depth-3 animated -half-second fadeIn" on-outside-click="closeLayoutDropdown()">
|
||||
|
||||
<div ng-repeat="layout in layouts | filter:{selected:true}" class="umb-layout-selector__dropdown-item" ng-click="pickLayout(layout)" ng-class="{'-active': layout.active }">
|
||||
<i class="{{ layout.icon }} umb-layout-selector__dropdown-item-icon"></i>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,83 @@
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<td style="width: 35px">
|
||||
<input type="checkbox" ng-click="selectAll($event)" ng-checked="isSelectedAll()">
|
||||
</td>
|
||||
<td>
|
||||
<a href="#" ng-click="sort('Name', true)" prevent-default class="sortable">
|
||||
<localize key="general_name">Name</localize>
|
||||
<i class="icon" ng-class="{'icon-navigation-up': isSortDirection('Name', 'asc'), 'icon-navigation-down': isSortDirection('Name', 'desc')}"></i>
|
||||
</a>
|
||||
</td>
|
||||
|
||||
<td ng-repeat="column in options.includeProperties">
|
||||
<a href="#" ng-click="sort(column.alias, column.allowSorting)" ng-class="{'sortable':column.allowSorting}" prevent-default>
|
||||
<span ng-bind="column.header"></span>
|
||||
<i class="icon" ng-class="{'icon-navigation-up': isSortDirection(column.alias, 'asc'), 'icon-navigation-down': isSortDirection(column.alias, 'desc')}"></i>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody ng-show="listViewResultSet.totalItems === 0">
|
||||
<tr>
|
||||
<td colspan="{{options.includeProperties.length + 2}}">
|
||||
<p><localize key="content_listViewNoItems">There are no items show in the list.</localize></p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
||||
<tbody ng-show="listViewResultSet.totalItems > 0">
|
||||
<tr ng-repeat="result in listViewResultSet.items"
|
||||
ng-class="{selected:result.selected}">
|
||||
|
||||
<td>
|
||||
<i class="icon {{result.icon}}" ng-class="getIcon(result)"></i>
|
||||
<input type="checkbox" ng-model="result.selected" no-dirty-check>
|
||||
</td>
|
||||
<td>
|
||||
<a ng-class="{inactive: (entityType === 'content' && !result.published) || isTrashed}"
|
||||
href="#{{result.editPath}}"
|
||||
ng-bind="result.name"></a>
|
||||
</td>
|
||||
|
||||
<td ng-repeat="column in options.includeProperties">
|
||||
<span>{{result[column.alias]}}</span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
||||
<tfoot ng-show="pagination.length > 1">
|
||||
<tr>
|
||||
<th colspan="{{options.includeProperties.length + 2}}">
|
||||
<div class="pull-left">
|
||||
</div>
|
||||
<div class="pagination pagination-right">
|
||||
<ul>
|
||||
<li ng-class="{disabled:options.pageNumber <= 1}">
|
||||
<a href="#" ng-click="prev()" prevent-default>
|
||||
<localize key="general_previous">Previous</localize>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li ng-repeat="pgn in pagination"
|
||||
ng-class="{active:pgn.isActive}">
|
||||
|
||||
<a href="#" ng-click="goToPage(pgn.val - 1)" prevent-default
|
||||
ng-bind="pgn.name ? pgn.name : pgn.val"
|
||||
ng-if="pgn.val != '...'"></a>
|
||||
<span ng-bind="pgn.val" ng-if="pgn.val == '...'"></span>
|
||||
</li>
|
||||
|
||||
<li ng-class="{disabled:options.pageNumber >= listViewResultSet.totalPages}">
|
||||
<a href="#" ng-click="next()" prevent-default>
|
||||
<localize key="general_next">Next</localize>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</th>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
@@ -51,6 +51,8 @@ function listViewController($rootScope, $scope, $routeParams, $injector, notific
|
||||
$scope.pagination = [];
|
||||
$scope.isNew = false;
|
||||
$scope.actionInProgress = false;
|
||||
$scope.layout = {};
|
||||
$scope.layout.activeLayout = {};
|
||||
$scope.listViewResultSet = {
|
||||
totalPages: 0,
|
||||
items: []
|
||||
@@ -71,6 +73,9 @@ function listViewController($rootScope, $scope, $routeParams, $injector, notific
|
||||
allowBulkDelete: true,
|
||||
};
|
||||
|
||||
// set active layout
|
||||
$scope.layout.activeLayout = getFirstAllowedLayout($scope.model.config.layouts);
|
||||
|
||||
//update all of the system includeProperties to enable sorting
|
||||
_.each($scope.options.includeProperties, function(e, i) {
|
||||
|
||||
@@ -91,6 +96,24 @@ function listViewController($rootScope, $scope, $routeParams, $injector, notific
|
||||
}
|
||||
});
|
||||
|
||||
function getFirstAllowedLayout(layouts) {
|
||||
|
||||
var firstAllowedLayout = {};
|
||||
|
||||
for (var i = 0; layouts.length > i; i++) {
|
||||
|
||||
var layout = layouts[i];
|
||||
|
||||
if (layout.selected === true) {
|
||||
firstAllowedLayout = layout;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return firstAllowedLayout;
|
||||
}
|
||||
|
||||
function showNotificationsAndReset(err, reload, successMsg) {
|
||||
|
||||
//check if response is ysod
|
||||
|
||||
@@ -44,96 +44,26 @@
|
||||
|
||||
<span ng-bind="bulkStatus" ng-show="isAnythingSelected()" class="pull-right"></span>
|
||||
|
||||
<form class="form-search pull-right" novalidate ng-show="!actionInProgress">
|
||||
<div class="inner-addon left-addon">
|
||||
<i class="icon icon-search" ng-click="enterSearch($event)"></i>
|
||||
<input type="text" class="form-control" localize="placeholder" placeholder="@general_typeToSearch" ng-model="options.filter" prevent-enter-submit no-dirty-check>
|
||||
</div>
|
||||
</form>
|
||||
<div class="pull-right">
|
||||
|
||||
<form class="form-search pull-right" novalidate ng-show="!actionInProgress">
|
||||
<div class="inner-addon left-addon">
|
||||
<i class="icon icon-search" ng-click="enterSearch($event)"></i>
|
||||
<input type="text" class="form-control" localize="placeholder" placeholder="@general_typeToSearch" ng-model="options.filter" prevent-enter-submit no-dirty-check>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<umb-layout-selector
|
||||
ng-if="model.config.layouts"
|
||||
layouts="model.config.layouts"
|
||||
active-layout="layout.activeLayout">
|
||||
</umb-layout-selector>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<td style="width: 35px">
|
||||
<input type="checkbox" ng-click="selectAll($event)" ng-checked="isSelectedAll()">
|
||||
</td>
|
||||
<td>
|
||||
<a href="#" ng-click="sort('Name', true)" prevent-default class="sortable">
|
||||
<localize key="general_name">Name</localize>
|
||||
<i class="icon" ng-class="{'icon-navigation-up': isSortDirection('Name', 'asc'), 'icon-navigation-down': isSortDirection('Name', 'desc')}"></i>
|
||||
</a>
|
||||
</td>
|
||||
<div ng-include="layout.activeLayout.path"></div>
|
||||
|
||||
<td ng-repeat="column in options.includeProperties">
|
||||
<a href="#" ng-click="sort(column.alias, column.allowSorting)" ng-class="{'sortable':column.allowSorting}" prevent-default>
|
||||
<span ng-bind="column.header"></span>
|
||||
<i class="icon" ng-class="{'icon-navigation-up': isSortDirection(column.alias, 'asc'), 'icon-navigation-down': isSortDirection(column.alias, 'desc')}"></i>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody ng-show="listViewResultSet.totalItems === 0">
|
||||
<tr>
|
||||
<td colspan="{{options.includeProperties.length + 2}}">
|
||||
<p><localize key="content_listViewNoItems">There are no items show in the list.</localize></p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
||||
<tbody ng-show="listViewResultSet.totalItems > 0">
|
||||
<tr ng-repeat="result in listViewResultSet.items"
|
||||
ng-class="{selected:result.selected}">
|
||||
|
||||
<td>
|
||||
<i class="icon {{result.icon}}" ng-class="getIcon(result)"></i>
|
||||
<input type="checkbox" ng-model="result.selected" no-dirty-check>
|
||||
</td>
|
||||
<td>
|
||||
<a ng-class="{inactive: (entityType === 'content' && !result.published) || isTrashed}"
|
||||
href="#{{result.editPath}}"
|
||||
ng-bind="result.name"></a>
|
||||
</td>
|
||||
|
||||
<td ng-repeat="column in options.includeProperties">
|
||||
<span>{{result[column.alias]}}</span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
||||
<tfoot ng-show="pagination.length > 1">
|
||||
<tr>
|
||||
<th colspan="{{options.includeProperties.length + 2}}">
|
||||
<div class="pull-left">
|
||||
</div>
|
||||
<div class="pagination pagination-right">
|
||||
<ul>
|
||||
<li ng-class="{disabled:options.pageNumber <= 1}">
|
||||
<a href="#" ng-click="prev()" prevent-default>
|
||||
<localize key="general_previous">Previous</localize>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li ng-repeat="pgn in pagination"
|
||||
ng-class="{active:pgn.isActive}">
|
||||
|
||||
<a href="#" ng-click="goToPage(pgn.val - 1)" prevent-default
|
||||
ng-bind="pgn.name ? pgn.name : pgn.val"
|
||||
ng-if="pgn.val != '...'"></a>
|
||||
<span ng-bind="pgn.val" ng-if="pgn.val == '...'"></span>
|
||||
</li>
|
||||
|
||||
<li ng-class="{disabled:options.pageNumber >= listViewResultSet.totalPages}">
|
||||
<a href="#" ng-click="next()" prevent-default>
|
||||
<localize key="general_next">Next</localize>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</th>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user