(js) Improve search toolbar in Calendar module

- new distinct search toolbar
- restored filtering options
- honor user's settings
pull/91/head
Francis Lachapelle 2015-07-08 14:46:07 -04:00
parent 4d4458a183
commit 9514103031
7 changed files with 175 additions and 42 deletions

View File

@ -8,9 +8,9 @@
xmlns:label="OGo:label"
className="UIxPageFrame"
title="title"
const:userDefaultsKeys="SOGoRefreshViewCheck, SOGoCalendarCategoriesColors, SOGoDefaultCalendar"
const:userDefaultsKeys="SOGoRefreshViewCheck, SOGoCalendarCategoriesColors, SOGoDefaultCalendar, SOGoTimeFormat"
const:userSettingsKeys="Calendar, ShowCompletedTasks"
const:jsFiles="Scheduler.app.js, Scheduler.js, Common.js, Contacts.js">
const:jsFiles="Scheduler.app.js, Scheduler.js, Common.js, Contacts.js, Mailer.js, Preferences.js">
<script type="text/javascript">
var firstDayOfWeek = <var:string value="firstDayOfWeek"/>;
var dayStartHour = <var:string value="dayStartHour"/>;
@ -314,7 +314,7 @@
ng-controller="CalendarListController as list">
<md-toolbar layout="column" layout-align="space-between start" class="md-tall toolbar-main">
<div class="md-toolbar-tools md-toolbar-tools-top sg-padded" layout="row" layout-align="space-between start">
<var:component className="UIxTopnavToolbarTemplate" />
<!-- <var:component className="UIxTopnavToolbarTemplate" /> -->
<div class="sg-toolbar-group-2">
<md-button class="sg-icon-button" label:aria-label="Search">
<md-icon>search</md-icon>
@ -322,19 +322,103 @@
</div>
</div><!-- .md-toolbar-tools -->
<div class="md-toolbar-tools md-toolbar-tools-bottom" layout="row" layout-align="space-between center">
<div class="view-list sg-padded" layout="row" layout-align="space-between center"
sg-search="list.component.$filter(list.componentType, { value: searchText, search: searchField })">
<md-input-container class="sg-search-field-container">
<label style="color: white"><md-icon>search</md-icon><var:string label:value="Search"/></label>
<input name="folderSearch" type="search" style="color: white"/>
</md-input-container>
<!-- filter mode -->
<div class="view-list sg-padded--right" layout="row" layout-align="space-between center"
ng-hide="list.mode.search">
<div class="sg-toolbar-group">
<md-select>
<md-option value="title_Category_Location"><var:string label:value="Title, category or location"/></md-option>
<md-option value="entireContent"><var:string label:value="Entire content"/></md-option>
</md-select>
<md-button class="sg-icon-button" label:aria-label="Search"
ng-click="list.mode.search = true">
<md-icon>search</md-icon>
</md-button>
</div>
<div class="sg-toolbar-group-last">
<md-menu>
<md-button class="sg-icon-button" label:aria-label="Search"
ng-click="$mdOpenMenu()">
<md-icon>filter_list</md-icon>
</md-button>
<md-menu-content>
<md-menu-item>
<md-button ng-click="list.filter('view_all')">
<md-icon ng-class="{ 'icon-check': list.component.$query.filterpopup == 'view_all' }">
<!-- selected --></md-icon> <var:string label:value="view_all"/>
</md-button>
</md-menu-item>
<md-menu-item>
<md-button ng-click="list.filter('view_today')">
<md-icon ng-class="{ 'icon-check': list.component.$query.filterpopup == 'view_today' }">
<!-- selected --></md-icon> <var:string label:value="view_today"/>
</md-button>
</md-menu-item>
<md-menu-item>
<md-button ng-click="list.filter('view_next7')">
<md-icon ng-class="{ 'icon-check': list.component.$query.filterpopup == 'view_next7' }">
<!-- selected --></md-icon> <var:string label:value="view_next7"/>
</md-button>
</md-menu-item>
<md-menu-item>
<md-button ng-click="list.filter('view_next14')">
<md-icon ng-class="{ 'icon-check': list.component.$query.filterpopup == 'view_next14' }">
<!-- selected --></md-icon> <var:string label:value="view_next14"/>
</md-button>
</md-menu-item>
<md-menu-item>
<md-button ng-click="list.filter('view_next31')">
<md-icon ng-class="{ 'icon-check': list.component.$query.filterpopup == 'view_next31' }">
<!-- selected --></md-icon><var:string label:value="view_next31"/>
</md-button>
</md-menu-item>
<md-menu-item>
<md-button ng-click="list.filter('view_thismonth')">
<md-icon ng-class="{ 'icon-check': list.component.$query.filterpopup == 'view_thismonth' }">
<!-- selected --></md-icon><var:string label:value="view_thismonth"/>
</md-button>
</md-menu-item>
<md-menu-item>
<md-button ng-click="list.filter('view_future')">
<md-icon ng-class="{ 'icon-check': list.component.$query.filterpopup == 'view_future' }">
<!-- selected --></md-icon> <var:string label:value="view_future"/>
</md-button>
</md-menu-item>
<md-menu-item>
<md-button ng-click="list.filter('view_selectedday')">
<md-icon ng-class="{ 'icon-check': list.component.$query.filterpopup == 'view_selectedday' }">
<!-- selected --></md-icon><var:string label:value="view_selectedday"/>
</md-button>
</md-menu-item>
<md-menu-divider ng-if="list.componentType == 'tasks'"><!-- divider --></md-menu-divider>
<md-menu-item ng-if="list.componentType == 'tasks'">
<md-button ng-click="list.filter()">
<md-checkbox
ng-model="list.component.$query['show-completed']"
ng-true-value="1"
ng-false-value="0"><var:string label:value="Show completed tasks"/></md-checkbox>
</md-button>
</md-menu-item>
</md-menu-content>
</md-menu>
</div>
</div>
<!-- search mode -->
<div class="view-list sg-padded--right sg-toolbar-search" layout="row" layout-align="space-between center"
ng-show="list.mode.search"
sg-search="list.component.$filter(list.componentType, { value: searchText, search: searchField })">
<md-button class="sg-icon-button"
sg-search-cancel="list.cancelSearch()"
label:aria-label="Back">
<md-icon>arrow_back</md-icon>
</md-button>
<md-input-container>
<input name="folderSearch" type="search" />
</md-input-container>
<md-input-container>
<md-select>
<md-option value="title_Category_Location" selected="selected"><var:string label:value="Title, category or location"/></md-option>
<md-option value="entireContent"><var:string label:value="Entire content"/></md-option>
</md-select>
</md-input-container>
</div>
<!-- day/week/month views -->
<div class="sg-padded">
<a class="sg-icon-button md-button"
label:aria-label="Day"

View File

@ -5,8 +5,10 @@
'use strict';
angular.module('SOGo.ContactsUI', []);
angular.module('SOGo.MailerUI', []);
angular.module('SOGo.PreferencesUI', []);
angular.module('SOGo.SchedulerUI', ['ngSanitize', 'ui.router', 'ct.ui.router.extras.sticky', 'ct.ui.router.extras.previous', 'vs-repeat', 'SOGo.Common', 'SOGo.ContactsUI'])
angular.module('SOGo.SchedulerUI', ['ngSanitize', 'ui.router', 'ct.ui.router.extras.sticky', 'ct.ui.router.extras.previous', 'vs-repeat', 'SOGo.Common', 'SOGo.ContactsUI', 'SOGo.MailerUI', 'SOGo.PreferencesUI'])
.constant('sgSettings', {
baseURL: ApplicationBaseURL,

View File

@ -6,18 +6,28 @@
/**
* @ngInject
*/
CalendarListController.$inject = ['$scope', '$rootScope', '$timeout', '$state', 'sgFocus', 'encodeUriFilter', 'Dialog', 'sgSettings', 'Calendar', 'Component', '$mdSidenav'];
function CalendarListController($scope, $rootScope, $timeout, $state, focus, encodeUriFilter, Dialog, Settings, Calendar, Component, $mdSidenav) {
CalendarListController.$inject = ['$scope', '$rootScope', '$timeout', '$state', 'sgFocus', 'encodeUriFilter', 'Dialog', 'sgSettings', 'Preferences', 'Calendar', 'Component', '$mdSidenav'];
function CalendarListController($scope, $rootScope, $timeout, $state, focus, encodeUriFilter, Dialog, Settings, Preferences, Calendar, Component, $mdSidenav) {
var vm = this;
vm.component = Component;
vm.componentType = null;
vm.componentType = 'events';
vm.selectedList = 0;
vm.selectComponentType = selectComponentType;
vm.newComponent = newComponent;
// TODO: should reflect last state userSettings -> Calendar -> SelectedList
vm.selectedList = 0;
vm.selectComponentType('tasks');
vm.selectComponentType('events');
vm.filter = filter;
vm.cancelSearch = cancelSearch;
vm.mode = { search: false };
// Select list based on user's settings
Preferences.ready().then(function() {
var type = 'events';
if (Preferences.settings.Calendar.SelectedList == 'tasksListView') {
vm.selectedList = 1;
type = 'tasks';
}
vm.selectComponentType(type, { reload: true });
});
// Switch between components tabs
function selectComponentType(type, options) {
@ -38,6 +48,18 @@
$state.go('calendars.newComponent', { calendarId: 'personal', componentType: type });
}
function filter(filterpopup) {
if (filterpopup)
Component.$query.filterpopup = filterpopup;
Component.$filter(vm.componentType, { value: '' });
}
function cancelSearch() {
vm.mode.search = false;
filter();
}
// Refresh current list when the list of calendars is modified
$scope.$on('calendars:list', function() {
Component.$filter(vm.componentType);

View File

@ -31,15 +31,20 @@
* @desc The factory we'll use to register with Angular
* @returns the Component constructor
*/
Component.$factory = ['$q', '$timeout', '$log', 'sgSettings', 'Resource', function($q, $timeout, $log, Settings, Resource) {
Component.$factory = ['$q', '$timeout', '$log', 'sgSettings', 'Preferences', 'Resource', function($q, $timeout, $log, Settings, Preferences, Resource) {
angular.extend(Component, {
$q: $q,
$timeout: $timeout,
$log: $log,
$Preferences: Preferences,
$$resource: new Resource(Settings.baseURL, Settings.activeUser),
$categories: window.UserDefaults.SOGoCalendarCategoriesColors
$categories: window.UserDefaults.SOGoCalendarCategoriesColors,
$query: { search: 'title_Category_Location' }
});
Preferences.ready().then(function() {
Component.$query.filterpopup = Preferences.settings.CalendarDefaultFilter;
Component.$query['show-completed'] = parseInt(Preferences.settings.ShowCompletedTasks);
});
if (window.UserDefaults && window.UserDefaults.SOGoTimeFormat)
Component.timeFormat = window.UserDefaults.SOGoTimeFormat;
else
@ -70,19 +75,32 @@
month = now.getMonth() + 1,
year = now.getFullYear(),
defaultParams = {
search: 'title_Category_Location',
day: '' + year + (month < 10?'0':'') + month + (day < 10?'0':'') + day,
filterpopup: 'view_thismonth'
};
if (angular.isUndefined(this.$filterOptions))
this.$filterOptions = defaultParams;
if (options)
angular.extend(this.$filterOptions, options);
return this.$Preferences.ready().then(function() {
var futureComponentData, dirty = false, otherType;
var futureComponentData = this.$$resource.fetch(null, type + 'list', this.$filterOptions);
angular.extend(_this.$query, defaultParams);
if (options) {
_.find(_.allKeys(options), function(key) {
dirty = (options[key] != Component.$query[key]);
return dirty;
})
angular.extend(_this.$query, options);
}
return this.$unwrapCollection(type, futureComponentData);
futureComponentData = _this.$$resource.fetch(null, type + 'list', _this.$query);
// Invalidate cached results of other type if $query has changed
otherType = (type == 'tasks')? '$events' : '$tasks';
if (dirty) {
delete Component[otherType];
Component.$log.debug('force reload of ' + otherType);
}
return _this.$unwrapCollection(type, futureComponentData);
});
};
/**
@ -206,11 +224,10 @@
*/
Component.$unwrapCollection = function(type, futureComponentData) {
var _this = this,
deferred = Component.$q.defer(),
components = [];
futureComponentData.then(function(data) {
Component.$timeout(function() {
return futureComponentData.then(function(data) {
return Component.$timeout(function() {
var fields = _.invoke(data.fields, 'toLowerCase');
// Instanciate Component objects
@ -225,13 +242,9 @@
// Save the list of components to the object model
Component['$' + type] = components;
deferred.resolve(components);
return components;
});
}, function(data) {
deferred.reject();
});
return deferred.promise;
};
/**

View File

@ -49,6 +49,9 @@ md-icon {
// Define CSS styles to use ng-class with md-icon
md-icon {
&.icon-check:before {
content: "\e5ca";
}
// &.icon_public:before {
// content: "\e80b";
// }

View File

@ -64,7 +64,7 @@ hgroup {
.sg-toolbar-group {
display: flex;
flex-direction: row;
align-items: flex-end;
align-items: center;
justify-content: space-between;
&-1 {
order: 1;
@ -79,4 +79,10 @@ hgroup {
}
}
.sg-toolbar-search {
background-color: sg-color($sogoPaper, 100);
color: rgba(0,0,0,0.54);
md-icon {
color: rgba(0,0,0,0.54);
}
}

View File

@ -11,6 +11,9 @@ main {
.sg-padded {
padding-left: $mg;
padding-right: $mg;
&--right {
padding-right: $mg;
}
}
.sg-logo {