Skip to content

Commit

Permalink
(js) Improve sg-search directive
Browse files Browse the repository at this point in the history
Will now respect the "listRequiresDot" source parameter and uses
ng-messages to show an error if the minimum number of characters is not
reached.

Fixes #438, #3464
  • Loading branch information
cgx committed Feb 25, 2016
1 parent 4b81667 commit 70fbeab
Show file tree
Hide file tree
Showing 12 changed files with 75 additions and 31 deletions.
4 changes: 4 additions & 0 deletions Documentation/SOGoInstallationGuide.asciidoc
Expand Up @@ -1035,6 +1035,10 @@ not work for entries in this source and thus, freebusy lookups.
|If set as an address book, the human identification name of the LDAP
repository
|listRequiresDot (optional)
|If set to `YES`, listing of this LDAP source is only possible when performing a search (respecting the SOGoSearchMinimumWordLength parameter) or when explicitely typing a single dot.
Defaults to `YES` when unset.
|ModulesConstraints (optional)
|Limits the access of any module through a constraint based on an LDAP
attribute; must be a dictionary with keys `Mail`, and/or `Calendar`,
Expand Down
2 changes: 2 additions & 0 deletions NEWS
Expand Up @@ -17,6 +17,8 @@ Enhancements
- [web] improved confirm dialogs for deletions
- [web] allow resources to prevent invitations (#3410)
- [web] warn when double-booking attendees and offer force save option
- [web] list search now displays a warning regarding the minlength constraint
- [web] loading an LDAP-based addressbook is now instantaneous when listRequiresDot is disabled (#438, #3464)
- [eas] now support EAS MIME truncation

Bug fixes
Expand Down
3 changes: 3 additions & 0 deletions UI/Common/English.lproj/Localizable.strings
Expand Up @@ -104,3 +104,6 @@
"Loading" = "Loading";
"No such user." = "No such user.";
"You cannot (un)subscribe to a folder that you own!" = "You cannot (un)subscribe to a folder that you own!";

/* Error message display bellow search field when the search string has less than the required number of characters */
"Enter at least %{minimumSearchLength} characters" = "Enter at least %{minimumSearchLength} characters";
5 changes: 0 additions & 5 deletions UI/Common/UIxPageFrame.m
Expand Up @@ -615,11 +615,6 @@ - (BOOL) isCompatibleBrowser
);
}

- (int) minimumSearchLength
{
return [[[context activeUser] domainDefaults] searchMinimumWordLength];
}

@end /* UIxPageFrame */

@interface UIxSidenavToolbarTemplate : UIxComponent
Expand Down
2 changes: 2 additions & 0 deletions UI/Contacts/UIxContactFoldersView.m
Expand Up @@ -339,6 +339,8 @@ - (NSString *) contactFolders
[NSNumber numberWithBool: [currentFolder isKindOfClass: SOGoGCSFolderK]], @"isEditable",
[NSNumber numberWithBool: [currentFolder isKindOfClass: SOGoContactSourceFolderK]
&& ![currentFolder isPersonalSource]], @"isRemote",
[NSNumber numberWithBool: [currentFolder isKindOfClass: SOGoContactSourceFolderK]
&& [currentFolder listRequiresDot]], @"listRequiresDot",
acls, @"acls",
urls, @"urls",
nil];
Expand Down
4 changes: 4 additions & 0 deletions UI/SOGoUI/UIxComponent.h
Expand Up @@ -86,6 +86,10 @@
/* SoUser */
- (NSString *) shortUserNameForDisplay;

/* Common defaults and settings */
- (int) minimumSearchLength;
- (NSString *) minimumSearchLengthLabel;

/* labels */
- (NSString *) labelForKey:(NSString *)_key;
- (NSString *) commonLabelForKey:(NSString *)_key;
Expand Down
17 changes: 17 additions & 0 deletions UI/SOGoUI/UIxComponent.m
Expand Up @@ -22,6 +22,7 @@

#import <Foundation/NSKeyValueCoding.h>
#import <Foundation/NSUserDefaults.h> /* for locale strings */
#import <Foundation/NSValue.h>

#import <NGObjWeb/SoObjects.h>
#import <NGObjWeb/WOResponse.h>
Expand Down Expand Up @@ -509,6 +510,22 @@ - (NSString *) shortUserNameForDisplay
return [[context activeUser] login];
}

/* Common defaults and settings */

- (int) minimumSearchLength
{
return [[[context activeUser] domainDefaults] searchMinimumWordLength];
}

- (NSString *) minimumSearchLengthLabel
{
NSDictionary *defaults;

defaults = [NSDictionary dictionaryWithObject: [NSNumber numberWithInt: [self minimumSearchLength]]
forKey: @"minimumSearchLength"];
return [defaults keysWithFormat: [self commonLabelForKey: @"Enter at least %{minimumSearchLength} characters"]];
}

/* labels */

- (NSString *) labelForKey: (NSString *) _str
Expand Down
14 changes: 9 additions & 5 deletions UI/Templates/ContactsUI/UIxContactFoldersView.wox
Expand Up @@ -274,17 +274,21 @@
</md-button>
</div>
<!-- search mode -->
<div class="md-toolbar-tools sg-toolbar-secondary"
<form name="searchForm" class="md-toolbar-tools sg-toolbar-secondary"
layout="row"
ng-show="addressbook.mode.search"
sg-search="addressbook.selectedFolder.$filter(searchText, { search: searchField })">
sg-search="addressbook.selectedFolder.$filter(searchText, { search: searchField })"
sg-allow-dot="addressbook.selectedFolder.listRequiresDot">
<md-button class="md-icon-button"
sg-search-cancel="addressbook.cancelSearch()"
label:aria-label="Back">
<md-icon>arrow_back</md-icon>
</md-button>
<md-input-container class="md-flex" md-no-float="md-no-float">
<input name="folderSearch" type="search" label:placeholder="Search"/>
<input name="folderSearch" type="search" var:minlength="minimumSearchLength" label:placeholder="Search"/>
<div ng-messages="searchForm.folderSearch.$error" ng-show="searchForm.folderSearch.$dirty">
<div ng-message="minlength"><var:string value="minimumSearchLengthLabel"/></div>
</div>
</md-input-container>
<md-input-container flex="25">
<md-select>
Expand All @@ -293,7 +297,7 @@
<md-option value="organization"><var:string label:value="Organization"/></md-option>
</md-select>
</md-input-container>
</div>
</form>
</md-toolbar>

<!-- multiple selection mode -->
Expand Down Expand Up @@ -362,7 +366,7 @@
</span>
</md-subheader>
<md-subheader ng-hide="addressbook.service.$query.value">
<span ng-switch="addressbook.selectedFolder.isRemote">
<span ng-switch="addressbook.selectedFolder.listRequiresDot">
<span ng-switch-when="1">
<var:string label:value="Start a search to browse this address book"/>
</span>
Expand Down
12 changes: 7 additions & 5 deletions UI/Templates/MailerUI/UIxMailFolderTemplate.wox
Expand Up @@ -116,10 +116,12 @@
</md-button>
</div>
<!-- search mode -->
<div class="md-toolbar-tools sg-toolbar-secondary"
layout="row"
ng-show="mailbox.mode.search"
sg-search="mailbox.selectedFolder.$filter(null, [{ searchBy: searchField, searchInput: searchText }])">
<form class="md-toolbar-tools sg-toolbar-secondary"
name="searchForm"
layout="row"
ng-show="mailbox.mode.search"
sg-search="mailbox.selectedFolder.$filter(null, [{ searchBy: searchField, searchInput: searchText }])"
sg-allow-dot="false">
<md-button class="sg-icon-button"
sg-search-cancel="mailbox.cancelSearch()"
label:aria-label="Back">
Expand All @@ -137,7 +139,7 @@
<md-option value="body"><var:string label:value="Entire Message"/></md-option>
</md-select>
</md-input-container>
</div>
</form>
</md-toolbar>

<!-- multiple-selection mode -->
Expand Down
12 changes: 7 additions & 5 deletions UI/Templates/SchedulerUI/UIxCalMainView.wox
Expand Up @@ -457,10 +457,12 @@
</md-button>
</div>
<!-- search mode -->
<div class="md-toolbar-tools sg-toolbar-secondary"
layout="row"
ng-show="list.mode.search"
sg-search="list.component.$filter(list.componentType, { value: searchText, search: searchField })">
<form class="md-toolbar-tools sg-toolbar-secondary"
name="searchForm"
layout="row"
ng-show="list.mode.search"
sg-search="list.component.$filter(list.componentType, { value: searchText, search: searchField })"
sg-allow-dot="false">
<md-button class="md-icon-button"
sg-search-cancel="list.cancelSearch()"
label:aria-label="Back">
Expand All @@ -475,7 +477,7 @@
<md-option value="entireContent"><var:string label:value="Entire content"/></md-option>
</md-select>
</md-input-container>
</div>
</form>
</md-toolbar>

<!-- multiple-selection mode -->
Expand Down
3 changes: 2 additions & 1 deletion UI/Templates/UIxPageFrame.wox
Expand Up @@ -53,11 +53,11 @@
<!-- MAIN CONTENT ROW -->
<var:component-content />

<!-- JAVASCRIPT IMPORTS -->
<script type="text/javascript">
var ApplicationBaseURL = '<var:string value="modulePath" />';
var ResourcesURL = '<var:string value="applicationPath" />.woa/WebServerResources';
var minimumSearchLength = <var:string value="minimumSearchLength" />;
var minimumSearchLengthLabel = '<var:string value="minimumSearchLengthLabel" />';
<var:if condition="isUIxDebugEnabled">
var DebugEnabled = true;
</var:if>
Expand Down Expand Up @@ -121,6 +121,7 @@
<script type="text/javascript" rsrc:src="js/vendor/angular-animate.min.js"><!-- space --></script>
<script type="text/javascript" rsrc:src="js/vendor/angular-sanitize.min.js"><!-- space --></script>
<script type="text/javascript" rsrc:src="js/vendor/angular-aria.min.js"><!-- space --></script>
<script type="text/javascript" rsrc:src="js/vendor/angular-messages.min.js"><!-- space --></script>
<script type="text/javascript" rsrc:src="js/vendor/angular-material.js"><!-- space --></script>
<script type="text/javascript" rsrc:src="js/vendor/angular-ui-router.min.js"><!-- space --></script>

Expand Down
28 changes: 18 additions & 10 deletions UI/WebServerResources/js/Common/sgSearch.directive.js
Expand Up @@ -60,6 +60,13 @@
return function postLink(scope, iElement, iAttr, controller) {
var compiledButtonEl = iElement.find('button');

// Retrive the form and input names to check the form's validity in the controller
controller.formName = iElement.attr('name');
controller.inputName = inputEl.attr('name');

// Associate the sg-allow-dot parameter (boolean) to the controller
controller.allowDot = $parse(iElement.attr('sg-allow-dot'))(scope);

// Associate callback to controller
controller.doSearch = $parse(iElement.attr('sg-search'));

Expand Down Expand Up @@ -99,7 +106,6 @@
minLength = angular.isNumber($window.minimumSearchLength)? $window.minimumSearchLength : 2;

// Controller variables
vm.previous = { searchText: '', searchField: '' };
vm.searchText = null;

// Model options
Expand All @@ -113,20 +119,22 @@

// Method to call on data changes
vm.onChange = function() {
if (typeof vm.searchText !== 'undefined' && vm.searchText !== null) {
if (vm.searchText != vm.previous.searchText || vm.searchField != vm.previous.searchField) {
if (vm.searchText.length > minLength || vm.searchText.length === 0 || vm.searchText == '.') {
// doSearch is the compiled expression of the sg-search attribute
vm.doSearch($scope, { searchText: vm.searchText, searchField: vm.searchField });
}
vm.previous = { searchText: vm.searchText, searchField: vm.searchField };
}
var form = $scope[vm.formName],
input = form[vm.inputName],
rawSearchText = input.$viewValue;

if (vm.allowDot && rawSearchText == '.' || form.$valid) {
if (rawSearchText == '.')
// Ignore the minlength constraint when using the dot operator
input.$setValidity('minlength', true);

// doSearch is the compiled expression of the sg-search attribute
vm.doSearch($scope, { searchText: rawSearchText, searchField: vm.searchField });
}
};

// Reset input field when cancelling the search
vm.cancelSearch = function() {
vm.previous = { searchText: '', searchField: '' };
vm.searchText = null;
};
}
Expand Down

0 comments on commit 70fbeab

Please sign in to comment.