diff --git a/Makefile b/Makefile index a10db38ae..c55779f51 100644 --- a/Makefile +++ b/Makefile @@ -148,7 +148,9 @@ appstore: $(project_directory)/js/vendor/angular-bootstrap/ui-bootstrap-tpls.min.js \ $(project_directory)/js/vendor/angular-sanitize/angular-sanitize.js \ $(project_directory)/js/vendor/ui-select/dist/select.js \ - $(project_directory)/js/vendor/jquery-timepicker/jquery.ui.timepicker.js + $(project_directory)/js/vendor/jquery-timepicker/jquery.ui.timepicker.js \ + $(project_directory)/js/vendor/angular-click-outside/clickoutside.directive.js \ + $(project_directory)/js/vendor/ngclipboard/dist/ngclipboard.min.js # Command for running JS and PHP tests. Works for package.json files in the js/ # and root directory. If phpunit is not installed systemwide, a copy is fetched diff --git a/bower.json b/bower.json index 9bf075766..22419a6e9 100644 --- a/bower.json +++ b/bower.json @@ -26,7 +26,9 @@ "angular-uuid4": "0.3.1", "jquery-timepicker": "883bb2cd94", "ui-select": "angular-ui/ui-select#0.14.9", - "vcard": "0.2.7" + "vcard": "0.2.7", + "angular-click-outside": "^2.10.1", + "ngclipboard": "^1.1.1" }, "devDependencies": { "angular-mocks": "1.5.8", diff --git a/css/public/style.css b/css/public/style.css index 122e5644c..66158d567 100644 --- a/css/public/style.css +++ b/css/public/style.css @@ -45,6 +45,10 @@ display: flex; flex-shrink: 0; } +.contactdetails__header #contact-failed-save { + animation: pulse 1.5s infinite; + border-radius: 50%; +} /* fix placeholder color */ .contactdetails__header .contactdetails__name::-webkit-input-placeholder, .contactdetails__header .contactdetails__org::-webkit-input-placeholder, @@ -300,8 +304,11 @@ avatar.failed { } /* addressbook settings */ -ul.addressBookList li { +ul.addressBookList > li { padding: 6px 0; + display: flex; + align-items: center; + flex-wrap: wrap; } ul.addressBook-share-list { @@ -310,11 +317,42 @@ ul.addressBook-share-list { } ul.addressBook-share-list li { - margin-left: 15px; + padding: 0 5px; + display: inline-flex; + align-items: center; +} + +ul.addressBook-share-list li .icon { + margin-right: 5px; + opacity: .2; +} + +ul.addressBook-share-list li .utils { + display: flex; +} + +/* override core apps css */ +#app-navigation ul.addressBookList > li span.utils { + position: relative; + padding: 0; + flex-shrink: 0; + height: 20px; +} + +ul.addressBookList li .utils .popovermenu { + margin-top: 0; + margin-right: -5px; +} + +#app-navigation ul.addressBookList li .utils .popovermenu li > button { + width: 100%; } ul.addressBookList li .action > span { - padding: 10px 14px; + display: inline-block; + opacity: 0.5; + width: 24px; + height: 20px; } ul.addressBookList li .action > a { @@ -323,11 +361,16 @@ ul.addressBookList li .action > a { div.addressBookShares ul.dropdown-menu { border: 1px solid #ddd; - border-radius: 3px; - width: 229px; - height: 200px; - margin-top: -5px; - overflow: scroll; + border-radius: 0 0 3px 3px; + max-height: 200px; + margin-top: -2px; + overflow-y: auto; + display: flex; + flex-wrap: wrap; + position: absolute; + background-color: #fff; + width: 100%; + z-index: 500; } div.addressBookShares ul.dropdown-menu li > a { @@ -337,7 +380,7 @@ div.addressBookShares ul.dropdown-menu li > a { } ul.dropdown-menu li.active { - background: #eee; + background: #f0f0f0; } div.app-contacts span.utils { @@ -346,39 +389,59 @@ div.app-contacts span.utils { position: relative !important; } -input.newAddressBookInput, input.shareeInput, input.addressBookUrl { +.addressBookUrlContainer { + width: 100%; + position: relative; +} + +input.newAddressBookInput, +input.shareeInput, +input.addressBookUrl { width: 100% !important; + margin-right: 0; + padding-right: 30px; + text-overflow: ellipsis; } .addressBookList form { position: relative; + width: 100%; } -.newAddressBookSubmit { + +addressBookList input[type='submit'].inline-button, +addressBookList input[type='button'].inline-button { position: absolute; right: 0; top: 0; - padding: 6px 13px; + padding: 6px 15px; background-color: transparent; border: none; opacity: .5; + margin-right: 0; + cursor: pointer; } ul.addressBookList li[addressbook] > span.addressBookName { - width: 105px; + width: calc(100% - 52px); /* -actions width */ overflow: hidden; white-space:nowrap; text-overflow: ellipsis; padding-left: 7px; - display: inline-block; } -li.addressBook-share-item span.shareeIdentifier { - max-width: 50px; +ul.addressBookList li[addressbook] > .addressBookShares { + width: 100%; +} + +li.addressBook-share-item span.shareeIdentifier, +li.calendar-share-item span.shareeIdentifier { + width: 100%; overflow:hidden; white-space:nowrap; text-overflow:ellipsis; display: inline-block; vertical-align: top; + opacity: 0.5; } #app-settings-content #upload.button { @@ -387,9 +450,8 @@ li.addressBook-share-item span.shareeIdentifier { padding-left: 34px; background-position: 10px center; text-align: left; - margin: 0; - display: block; margin-bottom: 10px; + display: block; } @@ -506,19 +568,11 @@ contactlist .tooltip { opacity: .5; } -ul.addressBookList li { - margin-bottom: 5px; -} - ul.addressBook-share-list { margin-top: 8px; margin-bottom: 12px; } -ul.addressBook-share-list li { - margin-left: 15px; -} - #app-navigation .utils .action span { cursor: pointer !important; } @@ -622,3 +676,7 @@ detailsitem .select2-container { #app-navigation-toggle-back { display: none; } + +.icon-group { + background-image: url('../../img/group.svg'); +} diff --git a/img/group.svg b/img/group.svg new file mode 100644 index 000000000..8753a4038 --- /dev/null +++ b/img/group.svg @@ -0,0 +1,4 @@ + + + + diff --git a/js/components/addressBook/addressBook_controller.js b/js/components/addressBook/addressBook_controller.js index 2e89b9365..405b691c2 100644 --- a/js/components/addressBook/addressBook_controller.js +++ b/js/components/addressBook/addressBook_controller.js @@ -4,17 +4,42 @@ angular.module('contactsApp') ctrl.t = { download: t('contacts', 'Download'), - showURL:t('contacts', 'Show URL'), - shareAddressbook: t('contacts', 'Share Addressbook'), - deleteAddressbook: t('contacts', 'Delete Addressbook'), + copyURL: t('contacts', 'Copy URL'), + clickToCopy: t('contacts', 'Click to copy the URL into your clipboard'), + shareAddressbook: t('contacts', 'Toggle share'), + deleteAddressbook: t('contacts', 'Delete'), shareInputPlaceHolder: t('contacts', 'Share with users or groups'), delete: t('contacts', 'Delete'), - canEdit: t('contacts', 'can edit') + canEdit: t('contacts', 'can edit'), + close: t('contacts', 'Close') }; - ctrl.showUrl = false; - /* globals oc_config */ + ctrl.tooltipIsOpen = false; + ctrl.tooltipTitle = ctrl.t.clickToCopy; + ctrl.showInputUrl = false; + + ctrl.clipboardSuccess = function() { + ctrl.tooltipIsOpen = true; + ctrl.tooltipTitle = t('core', 'Copied!'); + _.delay(function() { + ctrl.tooltipIsOpen = false; + ctrl.tooltipTitle = ctrl.t.clickToCopy; + }, 3000); + }; + + ctrl.clipboardError = function() { + ctrl.showInputUrl = true; + if (/iPhone|iPad/i.test(navigator.userAgent)) { + ctrl.InputUrlTooltip = t('core', 'Not supported!'); + } else if (/Mac/i.test(navigator.userAgent)) { + ctrl.InputUrlTooltip = t('core', 'Press ⌘-C to copy.'); + } else { + ctrl.InputUrlTooltip = t('core', 'Press Ctrl-C to copy.'); + } + $('#addressBookUrl_'+ctrl.addressBook.ctag).select(); + }; + /* globals oc_config */ function compareVersion(version1, version2) { for (var i = 0; i < Math.max(version1.length, version2.length); i++) { var a = version1[i] || 0; @@ -32,8 +57,21 @@ angular.module('contactsApp') ctrl.canExport = compareVersion([9, 0, 2, 0], oc_config.version.split('.')); /* eslint-enable camelcase */ - ctrl.toggleShowUrl = function() { - ctrl.showUrl = !ctrl.showUrl; + ctrl.closeMenus = function() { + $scope.$parent.ctrl.openedMenu = false; + }; + + ctrl.openMenu = function(index) { + ctrl.closeMenus(); + $scope.$parent.ctrl.openedMenu = index; + }; + + ctrl.toggleMenu = function(index) { + if ($scope.$parent.ctrl.openedMenu === index) { + ctrl.closeMenus(); + } else { + ctrl.openMenu(index); + } }; ctrl.toggleSharesEditor = function() { @@ -103,6 +141,12 @@ angular.module('contactsApp') }; ctrl.onSelectSharee = function (item) { + // Prevent settings to slide down + $('#app-settings-header > button').data('apps-slide-toggle', false); + _.delay(function() { + $('#app-settings-header > button').data('apps-slide-toggle', '#app-settings-content'); + }, 500); + ctrl.selectedSharee = null; AddressBookService.share(ctrl.addressBook, item.type, item.identifier, false, false).then(function() { $scope.$apply(); diff --git a/js/components/addressBookList/addressBookList_controller.js b/js/components/addressBookList/addressBookList_controller.js index 8bad3b74d..5e18ff98e 100644 --- a/js/components/addressBookList/addressBookList_controller.js +++ b/js/components/addressBookList/addressBookList_controller.js @@ -3,6 +3,7 @@ angular.module('contactsApp') var ctrl = this; ctrl.loading = true; + ctrl.openedMenu = false; AddressBookService.getAll().then(function(addressBooks) { ctrl.addressBooks = addressBooks; diff --git a/js/main.js b/js/main.js index 32dbf24e4..3f8faf3e6 100644 --- a/js/main.js +++ b/js/main.js @@ -8,7 +8,7 @@ * @copyright Hendrik Leppelsack 2015 */ -angular.module('contactsApp', ['uuid4', 'angular-cache', 'ngRoute', 'ui.bootstrap', 'ui.select', 'ngSanitize']) +angular.module('contactsApp', ['uuid4', 'angular-cache', 'ngRoute', 'ui.bootstrap', 'ui.select', 'ngSanitize', 'angular-click-outside', 'ngclipboard']) .config(function($routeProvider) { $routeProvider.when('/:gid', { diff --git a/karma.conf.js b/karma.conf.js index 2e63ccecb..d0cbc6c42 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -18,6 +18,8 @@ module.exports = function(config) { 'js/vendor/angular-cache/dist/angular-cache.js', 'js/vendor/angular-sanitize/angular-sanitize.js', 'js/vendor/ui-select/dist/select.js', + 'js/vendor/angular-click-outside/clickoutside.directive.js', + 'js/vendor/ngclipboard/dist/ngclipboard.min.js', 'js/dav/dav.js', 'js/vendor/vcard/src/vcard.js', diff --git a/templates/addressBook.html b/templates/addressBook.html index 4d497f746..92e3a1f1e 100644 --- a/templates/addressBook.html +++ b/templates/addressBook.html @@ -1,36 +1,57 @@ {{ctrl.addressBook.displayName}} - - - + + + - - - - - - - - - - - - + + + + + - + +
+ + +
+
diff --git a/templates/main.php b/templates/main.php index e165fc73d..784cf5977 100644 --- a/templates/main.php +++ b/templates/main.php @@ -6,6 +6,9 @@ script('contacts', 'vendor/angular-cache/dist/angular-cache'); script('contacts', 'vendor/angular-sanitize/angular-sanitize'); script('contacts', 'vendor/ui-select/dist/select'); +script('contacts', 'vendor/angular-click-outside/clickoutside.directive'); +script('contacts', 'vendor/ngclipboard/dist/ngclipboard.min'); + // DAV libraries script('contacts', 'dav/dav');