diff options
27 files changed, 267 insertions, 143 deletions
diff --git a/3rdparty b/3rdparty -Subproject 696f7683651fa2ee1f59cbde08c6f5fefbcaad0 +Subproject 3cec97e2cbdbac0a07dc6269e7fc80048596b41 diff --git a/apps/files/js/filelist.js b/apps/files/js/filelist.js index 7a4ea492752..e50b402dea8 100644 --- a/apps/files/js/filelist.js +++ b/apps/files/js/filelist.js @@ -2266,7 +2266,7 @@ function updateInList(fileInfo) { self.updateRow(tr, fileInfo); - self._updateDetailsView(fileInfo, false); + self._updateDetailsView(fileInfo.name, false); } // TODO: too many nested blocks, move parts into functions diff --git a/apps/files/tests/js/filelistSpec.js b/apps/files/tests/js/filelistSpec.js index fc5a6c18f95..08da15b8a88 100644 --- a/apps/files/tests/js/filelistSpec.js +++ b/apps/files/tests/js/filelistSpec.js @@ -612,6 +612,12 @@ describe('OCA.Files.FileList tests', function() { beforeEach(function() { deferredRename = $.Deferred(); renameStub = sinon.stub(filesClient, 'move').returns(deferredRename.promise()); + + for (var i = 0; i < testFiles.length; i++) { + var file = testFiles[i]; + file.path = '/some/subdir'; + fileList.add(file, {silent: true}); + } }); afterEach(function() { renameStub.restore(); @@ -619,9 +625,6 @@ describe('OCA.Files.FileList tests', function() { function doCancelRename() { var $input; - for (var i = 0; i < testFiles.length; i++) { - fileList.add(testFiles[i]); - } // trigger rename prompt fileList.rename('One.txt'); @@ -636,12 +639,6 @@ describe('OCA.Files.FileList tests', function() { function doRename() { var $input; - for (var i = 0; i < testFiles.length; i++) { - var file = testFiles[i]; - file.path = '/some/subdir'; - fileList.add(file, {silent: true}); - } - // trigger rename prompt fileList.rename('One.txt'); $input = fileList.$fileList.find('input.filename'); @@ -677,6 +674,36 @@ describe('OCA.Files.FileList tests', function() { expect(notificationStub.calledOnce).toEqual(true); }); + it('Shows renamed file details if rename ajax call suceeded', function() { + fileList.showDetailsView('One.txt'); + + expect($('#app-sidebar').hasClass('disappear')).toEqual(false); + expect(fileList._detailsView.getFileInfo().get('id')).toEqual(1); + expect(fileList._detailsView.getFileInfo().get('name')).toEqual('One.txt'); + + doRename(); + + deferredRename.resolve(201); + + expect($('#app-sidebar').hasClass('disappear')).toEqual(false); + expect(fileList._detailsView.getFileInfo().get('id')).toEqual(1); + expect(fileList._detailsView.getFileInfo().get('name')).toEqual('Tu_after_three.txt'); + }); + it('Shows again file details if rename ajax call failed', function() { + fileList.showDetailsView('One.txt'); + + expect($('#app-sidebar').hasClass('disappear')).toEqual(false); + expect(fileList._detailsView.getFileInfo().get('id')).toEqual(1); + expect(fileList._detailsView.getFileInfo().get('name')).toEqual('One.txt'); + + doRename(); + + deferredRename.reject(403); + + expect($('#app-sidebar').hasClass('disappear')).toEqual(false); + expect(fileList._detailsView.getFileInfo().get('id')).toEqual(1); + expect(fileList._detailsView.getFileInfo().get('name')).toEqual('One.txt'); + }); it('Correctly updates file link after rename', function() { var $tr; doRename(); @@ -731,10 +758,6 @@ describe('OCA.Files.FileList tests', function() { it('Validates the file name', function() { var $input, $tr; - for (var i = 0; i < testFiles.length; i++) { - fileList.add(testFiles[i], {silent: true}); - } - $tr = fileList.findFileEl('One.txt'); expect($tr.find('a.name').css('display')).not.toEqual('none'); diff --git a/apps/files_sharing/lib/External/Mount.php b/apps/files_sharing/lib/External/Mount.php index d756a1830b2..e12f8823cd8 100644 --- a/apps/files_sharing/lib/External/Mount.php +++ b/apps/files_sharing/lib/External/Mount.php @@ -68,4 +68,14 @@ class Mount extends MountPoint implements MoveableMount { public function removeMount() { return $this->manager->removeShare($this->mountPoint); } + + /** + * Get the type of mount point, used to distinguish things like shares and external storages + * in the web interface + * + * @return string + */ + public function getMountType() { + return 'shared'; + } } diff --git a/apps/theming/lib/Capabilities.php b/apps/theming/lib/Capabilities.php index 1b6bb8927be..a75403a1fd5 100644 --- a/apps/theming/lib/Capabilities.php +++ b/apps/theming/lib/Capabilities.php @@ -81,6 +81,8 @@ class Capabilities implements IPublicCapability { 'background' => $backgroundLogo === 'backgroundColor' ? $this->theming->getColorPrimary() : $this->url->getAbsoluteURL($this->theming->getBackground()), + 'background-plain' => $backgroundLogo === 'backgroundColor', + 'background-default' => !$this->util->isBackgroundThemed(), ], ]; } diff --git a/apps/theming/lib/ThemingDefaults.php b/apps/theming/lib/ThemingDefaults.php index 05d387e6273..9dcc981817e 100644 --- a/apps/theming/lib/ThemingDefaults.php +++ b/apps/theming/lib/ThemingDefaults.php @@ -196,22 +196,13 @@ class ThemingDefaults extends \OC_Defaults { * @return string */ public function getBackground() { - $backgroundLogo = $this->config->getAppValue('theming', 'backgroundMime',false); - - $backgroundExists = true; - try { - $this->appData->getFolder('images')->getFile('background'); - } catch (\Exception $e) { - $backgroundExists = false; - } - $cacheBusterCounter = $this->config->getAppValue('theming', 'cachebuster', '0'); - if(!$backgroundLogo || !$backgroundExists) { - return $this->urlGenerator->imagePath('core','background.png') . '?v=' . $cacheBusterCounter; + if($this->util->isBackgroundThemed()) { + return $this->urlGenerator->linkToRoute('theming.Theming.getLoginBackground') . '?v=' . $cacheBusterCounter; } - return $this->urlGenerator->linkToRoute('theming.Theming.getLoginBackground') . '?v=' . $cacheBusterCounter; + return $this->urlGenerator->imagePath('core','background.png') . '?v=' . $cacheBusterCounter; } /** diff --git a/apps/theming/lib/Util.php b/apps/theming/lib/Util.php index 6a1aa672108..2f6f4128365 100644 --- a/apps/theming/lib/Util.php +++ b/apps/theming/lib/Util.php @@ -235,4 +235,16 @@ class Util { return false; } + public function isBackgroundThemed() { + $backgroundLogo = $this->config->getAppValue('theming', 'backgroundMime',false); + + $backgroundExists = true; + try { + $this->appData->getFolder('images')->getFile('background'); + } catch (\Exception $e) { + $backgroundExists = false; + } + return $backgroundLogo && $backgroundLogo !== 'backgroundColor' && $backgroundExists; + } + } diff --git a/apps/theming/tests/CapabilitiesTest.php b/apps/theming/tests/CapabilitiesTest.php index c760c896425..31e0ae79970 100644 --- a/apps/theming/tests/CapabilitiesTest.php +++ b/apps/theming/tests/CapabilitiesTest.php @@ -50,6 +50,9 @@ class CapabilitiesTest extends TestCase { /** @var IConfig|\PHPUnit_Framework_MockObject_MockObject */ protected $config; + /** @var Util|\PHPUnit_Framework_MockObject_MockObject */ + protected $util; + /** @var Capabilities */ protected $capabilities; @@ -59,13 +62,13 @@ class CapabilitiesTest extends TestCase { $this->theming = $this->createMock(ThemingDefaults::class); $this->url = $this->getMockBuilder(IURLGenerator::class)->getMock(); $this->config = $this->createMock(IConfig::class); - $util = new Util($this->config, $this->createMock(IAppManager::class), $this->createMock(IAppData::class)); - $this->capabilities = new Capabilities($this->theming, $util, $this->url, $this->config); + $this->util = $this->createMock(Util::class); + $this->capabilities = new Capabilities($this->theming, $this->util, $this->url, $this->config); } public function dataGetCapabilities() { return [ - ['name', 'url', 'slogan', '#FFFFFF', '#000000', 'logo', 'background', 'http://absolute/', [ + ['name', 'url', 'slogan', '#FFFFFF', '#000000', 'logo', 'background', 'http://absolute/', true, [ 'name' => 'name', 'url' => 'url', 'slogan' => 'slogan', @@ -74,8 +77,10 @@ class CapabilitiesTest extends TestCase { 'color-element' => '#555555', 'logo' => 'http://absolute/logo', 'background' => 'http://absolute/background', + 'background-plain' => false, + 'background-default' => false, ]], - ['name1', 'url2', 'slogan3', '#01e4a0', '#ffffff', 'logo5', 'background6', 'http://localhost/', [ + ['name1', 'url2', 'slogan3', '#01e4a0', '#ffffff', 'logo5', 'background6', 'http://localhost/', false, [ 'name' => 'name1', 'url' => 'url2', 'slogan' => 'slogan3', @@ -84,8 +89,22 @@ class CapabilitiesTest extends TestCase { 'color-element' => '#01e4a0', 'logo' => 'http://localhost/logo5', 'background' => 'http://localhost/background6', + 'background-plain' => false, + 'background-default' => true, + ]], + ['name1', 'url2', 'slogan3', '#000000', '#ffffff', 'logo5', 'backgroundColor', 'http://localhost/', true, [ + 'name' => 'name1', + 'url' => 'url2', + 'slogan' => 'slogan3', + 'color' => '#000000', + 'color-text' => '#ffffff', + 'color-element' => '#000000', + 'logo' => 'http://localhost/logo5', + 'background' => '#000000', + 'background-plain' => true, + 'background-default' => false, ]], - ['name1', 'url2', 'slogan3', '#000000', '#ffffff', 'logo5', 'backgroundColor', 'http://localhost/', [ + ['name1', 'url2', 'slogan3', '#000000', '#ffffff', 'logo5', 'backgroundColor', 'http://localhost/', false, [ 'name' => 'name1', 'url' => 'url2', 'slogan' => 'slogan3', @@ -94,6 +113,8 @@ class CapabilitiesTest extends TestCase { 'color-element' => '#000000', 'logo' => 'http://localhost/logo5', 'background' => '#000000', + 'background-plain' => true, + 'background-default' => true, ]], ]; } @@ -104,13 +125,14 @@ class CapabilitiesTest extends TestCase { * @param string $url * @param string $slogan * @param string $color - * @param string $logo * @param string $textColor + * @param string $logo * @param string $background * @param string $baseUrl + * @param bool $backgroundThemed * @param string[] $expected */ - public function testGetCapabilities($name, $url, $slogan, $color, $textColor, $logo, $background, $baseUrl, array $expected) { + public function testGetCapabilities($name, $url, $slogan, $color, $textColor, $logo, $background, $baseUrl, $backgroundThemed, array $expected) { $this->config->expects($this->once()) ->method('getAppValue') ->willReturn($background); @@ -133,6 +155,16 @@ class CapabilitiesTest extends TestCase { ->method('getTextColorPrimary') ->willReturn($textColor); + $util = new Util($this->config, $this->createMock(IAppManager::class), $this->createMock(IAppData::class)); + $this->util->expects($this->once()) + ->method('elementColor') + ->with($color) + ->willReturn($util->elementColor($color)); + + $this->util->expects($this->once()) + ->method('isBackgroundThemed') + ->willReturn($backgroundThemed); + if($background !== 'backgroundColor') { $this->theming->expects($this->once()) ->method('getBackground') diff --git a/apps/theming/tests/ThemingDefaultsTest.php b/apps/theming/tests/ThemingDefaultsTest.php index 843c1d34f9e..d0dc6587f74 100644 --- a/apps/theming/tests/ThemingDefaultsTest.php +++ b/apps/theming/tests/ThemingDefaultsTest.php @@ -391,24 +391,14 @@ class ThemingDefaultsTest extends TestCase { } public function testGetBackgroundDefault() { - $this->appData->expects($this->once()) - ->method('getFolder') - ->willThrowException(new NotFoundException()); - $this->config - ->expects($this->at(0)) - ->method('getAppValue') - ->with('theming', 'backgroundMime') - ->willReturn(''); $this->config - ->expects($this->at(1)) + ->expects($this->once()) ->method('getAppValue') ->with('theming', 'cachebuster', '0') ->willReturn('0'); - $this->appData - ->expects($this->once()) - ->method('getFolder') - ->with('images') - ->willThrowException(new \Exception()); + $this->util->expects($this->once()) + ->method('isBackgroundThemed') + ->willReturn(false); $this->urlGenerator->expects($this->once()) ->method('imagePath') ->with('core', 'background.png') @@ -417,24 +407,14 @@ class ThemingDefaultsTest extends TestCase { } public function testGetBackgroundCustom() { - $folder = $this->createMock(ISimpleFolder::class); - $file = $this->createMock(ISimpleFile::class); - $folder->expects($this->once()) - ->method('getFile') - ->willReturn($file); - $this->appData->expects($this->once()) - ->method('getFolder') - ->willReturn($folder); $this->config - ->expects($this->at(0)) - ->method('getAppValue') - ->with('theming', 'backgroundMime', false) - ->willReturn('image/svg+xml'); - $this->config - ->expects($this->at(1)) + ->expects($this->once()) ->method('getAppValue') ->with('theming', 'cachebuster', '0') ->willReturn('0'); + $this->util->expects($this->once()) + ->method('isBackgroundThemed') + ->willReturn(true); $this->urlGenerator->expects($this->once()) ->method('linkToRoute') ->with('theming.Theming.getLoginBackground') @@ -513,12 +493,12 @@ class ThemingDefaultsTest extends TestCase { $this->config->expects($this->at(2))->method('getAppValue')->with('theming', 'backgroundMime', false)->willReturn('jpeg'); $this->config->expects($this->at(3))->method('getAppValue')->with('theming', 'logoMime', false)->willReturn('jpeg'); $this->config->expects($this->at(4))->method('getAppValue')->with('theming', 'cachebuster', '0')->willReturn('0'); - $this->config->expects($this->at(5))->method('getAppValue')->with('theming', 'backgroundMime', false)->willReturn('jpeg'); - $this->config->expects($this->at(6))->method('getAppValue')->with('theming', 'cachebuster', '0')->willReturn('0'); - $this->config->expects($this->at(7))->method('getAppValue')->with('theming', 'color', null)->willReturn($this->defaults->getColorPrimary()); + $this->util->expects($this->once())->method('isBackgroundThemed')->willReturn(true); + $this->config->expects($this->at(5))->method('getAppValue')->with('theming', 'cachebuster', '0')->willReturn('0'); + $this->config->expects($this->at(6))->method('getAppValue')->with('theming', 'color', null)->willReturn($this->defaults->getColorPrimary()); + $this->config->expects($this->at(7))->method('getAppValue')->with('theming', 'color', $this->defaults->getColorPrimary())->willReturn($this->defaults->getColorPrimary()); $this->config->expects($this->at(8))->method('getAppValue')->with('theming', 'color', $this->defaults->getColorPrimary())->willReturn($this->defaults->getColorPrimary()); $this->config->expects($this->at(9))->method('getAppValue')->with('theming', 'color', $this->defaults->getColorPrimary())->willReturn($this->defaults->getColorPrimary()); - $this->config->expects($this->at(10))->method('getAppValue')->with('theming', 'color', $this->defaults->getColorPrimary())->willReturn($this->defaults->getColorPrimary()); $this->util->expects($this->any())->method('invertTextColor')->with($this->defaults->getColorPrimary())->willReturn(false); $this->util->expects($this->any())->method('elementColor')->with($this->defaults->getColorPrimary())->willReturn('#aaaaaa'); diff --git a/apps/theming/tests/UtilTest.php b/apps/theming/tests/UtilTest.php index 1ad77be72d5..247bcbae0b2 100644 --- a/apps/theming/tests/UtilTest.php +++ b/apps/theming/tests/UtilTest.php @@ -189,7 +189,6 @@ class UtilTest extends TestCase { } public function testIsAlreadyThemedFalse() { - $theme = $this->config->getSystemValue('theme', ''); $this->config->expects($this->once()) ->method('getSystemValue') ->with('theme', '') @@ -199,7 +198,6 @@ class UtilTest extends TestCase { } public function testIsAlreadyThemedTrue() { - $theme = $this->config->getSystemValue('theme', ''); $this->config->expects($this->once()) ->method('getSystemValue') ->with('theme', '') @@ -208,4 +206,35 @@ class UtilTest extends TestCase { $this->assertTrue($actual); } + public function dataIsBackgroundThemed() { + return [ + [false, false, false], + ['png', true, true], + ['backgroundColor', false, false], + ]; + } + /** + * @dataProvider dataIsBackgroundThemed + */ + public function testIsBackgroundThemed($backgroundMime, $fileFound, $expected) { + $this->config->expects($this->once()) + ->method('getAppValue') + ->with('theming', 'backgroundMime', false) + ->willReturn($backgroundMime); + $folder = $this->createMock(ISimpleFolder::class); + if ($fileFound) { + $folder->expects($this->once()) + ->method('getFile') + ->willReturn($this->createMock(ISimpleFile::class)); + } else { + $folder->expects($this->once()) + ->method('getFile') + ->willThrowException(new NotFoundException()); + } + $this->appData->expects($this->once()) + ->method('getFolder') + ->willReturn($folder); + $this->assertEquals($expected, $this->util->isBackgroundThemed()); + } + } diff --git a/apps/updatenotification/js/notification.js b/apps/updatenotification/js/notification.js index a2e78cecb09..a588ede5ffd 100644 --- a/apps/updatenotification/js/notification.js +++ b/apps/updatenotification/js/notification.js @@ -17,10 +17,5 @@ $(document).ready(function(){ var text = t('core', '{version} is available. Get more information on how to update.', {version: oc_updateState.updateVersion}), element = $('<a>').attr('href', oc_updateState.updateLink).attr('target','_blank').text(text); - OC.Notification.show(element, - { - isHTML: true, - type: 'error' - } - ); + OC.Notification.showHtml(element, { type: 'error' }); }); diff --git a/apps/user_ldap/js/renewPassword.js b/apps/user_ldap/js/renewPassword.js index bea2c0409f7..7a58832c984 100644 --- a/apps/user_ldap/js/renewPassword.js +++ b/apps/user_ldap/js/renewPassword.js @@ -46,5 +46,6 @@ $(document).ready(function() { t('core', 'Strong password') ], drawTitles: true, + $addAfter: $('input[name="newPassword-clone"]'), }); }); diff --git a/bower.json b/bower.json index 3808a698163..d37a9244689 100644 --- a/bower.json +++ b/bower.json @@ -25,7 +25,7 @@ "select2": "~3.4.8", "zxcvbn": "*", "snapjs": "~2.0.0-rc1", - "strengthify": "^0.5.2", + "strengthify": "^0.5.3", "underscore": "~1.8.0", "bootstrap": "~3.3.6", "backbone": "~1.2.3", diff --git a/core/css/guest.css b/core/css/guest.css index 4256c66302f..ecc3da9d081 100644 --- a/core/css/guest.css +++ b/core/css/guest.css @@ -93,7 +93,7 @@ body { form { position: relative; width: 280px; - margin: 16px auto; + margin: auto; padding: 0; } form fieldset { @@ -410,7 +410,6 @@ form .warning input[type='checkbox']+label { padding: 12px; margin-top: -6px; color: #fff; - opacity: .7; } #forgot-password { padding: 11px; @@ -579,8 +578,7 @@ fieldset.update legend + p { margin-bottom: 15px; } p.info { - margin: 0 auto; - padding-top: 20px; + margin: 20px auto; text-shadow: 0 0 2px rgba(0, 0, 0, .4); // better readability on bright background -webkit-user-select: none; -moz-user-select: none; diff --git a/core/js/jquery-showpassword.js b/core/js/jquery-showpassword.js index fc9de2170f9..5d518c78bcb 100644 --- a/core/js/jquery-showpassword.js +++ b/core/js/jquery-showpassword.js @@ -74,7 +74,7 @@ // Create clone var $clone = cloneElement($input); - $clone.insertBefore($input); + $clone.insertAfter($input); // Set callback arguments if(callback.fn){ diff --git a/core/js/lostpassword.js b/core/js/lostpassword.js index b44962f552e..8c770047444 100644 --- a/core/js/lostpassword.js +++ b/core/js/lostpassword.js @@ -50,6 +50,7 @@ OC.Lostpassword = { event.preventDefault(); $('#lost-password').hide(); + $('.wrongPasswordMsg').hide(); $('#lost-password-back').slideDown().fadeIn(); $('.remember-login-container').slideUp().fadeOut(); $('#submit-wrapper').slideUp().fadeOut(); diff --git a/core/js/public/comments.js b/core/js/public/comments.js index 955e88c8609..ac0bf8e0ab7 100644 --- a/core/js/public/comments.js +++ b/core/js/public/comments.js @@ -43,7 +43,7 @@ } var linkText = url.replace(self.protocolRegex, ''); - return '<a class="external" target="_blank" href="' + url + '">' + linkText + '</a>'; + return '<a class="external" target="_blank" rel="noopener noreferrer" href="' + url + '">' + linkText + '</a>'; }); }, diff --git a/core/templates/login.php b/core/templates/login.php index d28c92e36ef..de991e08d97 100644 --- a/core/templates/login.php +++ b/core/templates/login.php @@ -51,17 +51,17 @@ script('core', 'merged-login'); <label for="password" class="infield"><?php p($l->t('Password')); ?></label> </p> - <?php if (!empty($_['invalidpassword'])) { ?> - <p class="warning"> - <?php p($l->t('Wrong password.')); ?> - </p> - <?php } ?> - <div id="submit-wrapper"> <input type="submit" id="submit" class="login primary" title="" value="<?php p($l->t('Log in')); ?>" disabled="disabled" /> <div class="submit-icon icon-confirm-white"></div> </div> + <?php if (!empty($_['invalidpassword'])) { ?> + <p class="warning wrongPasswordMsg"> + <?php p($l->t('Wrong password.')); ?> + </p> + <?php } ?> + <?php if (!empty($_['canResetPassword'])) { ?> <div id="reset-password-wrapper" style="display: none;"> <input type="submit" id="reset-password-submit" class="login primary" title="" value="<?php p($l->t('Reset password')); ?>" disabled="disabled" /> diff --git a/core/vendor/strengthify/.bower.json b/core/vendor/strengthify/.bower.json index 9a5973c3116..de9904137ef 100644 --- a/core/vendor/strengthify/.bower.json +++ b/core/vendor/strengthify/.bower.json @@ -1,6 +1,6 @@ { "name": "strengthify", - "version": "0.5.2", + "version": "0.5.3", "homepage": "https://github.com/MorrisJobke/strengthify", "authors": [ "Eve Ragins <eve.ragins@eve-corp.com", @@ -9,13 +9,13 @@ "description": "Combine jQuery and zxcvbn to create a password strength meter.", "main": "jquery.strengthify.js", "license": "MIT", - "_release": "0.5.2", + "_release": "0.5.3", "_resolution": { "type": "version", - "tag": "0.5.2", - "commit": "82d63c39de1b7b60ae38d24d0f866cba325904b5" + "tag": "0.5.3", + "commit": "a97e861762ccb17ce5f51d5c608b5d9e42732ae3" }, "_source": "https://github.com/MorrisJobke/strengthify.git", - "_target": "^0.5.2", + "_target": "^0.5.3", "_originalSource": "strengthify" }
\ No newline at end of file diff --git a/core/vendor/strengthify/jquery.strengthify.js b/core/vendor/strengthify/jquery.strengthify.js index 046c2150210..204a0b33ccd 100644 --- a/core/vendor/strengthify/jquery.strengthify.js +++ b/core/vendor/strengthify/jquery.strengthify.js @@ -51,7 +51,8 @@ }, drawTitles: false, drawMessage: false, - drawBars: true + drawBars: true, + $addAfter: null }; return this.each(function() { @@ -175,8 +176,13 @@ elemId = $elem.attr('id'); var drawSelf = drawStrengthify.bind(this); + var $addAfter = options.$addAfter; + if (!$addAfter) { + $addAfter = $elem; + } + // add elements - $elem.after('<div class="strengthify-wrapper" data-strengthifyFor="' + $elem.attr('id') + '"></div>'); + $addAfter.after('<div class="strengthify-wrapper" data-strengthifyFor="' + $elem.attr('id') + '"></div>'); if (options.drawBars) { getWrapperFor(elemId) diff --git a/settings/css/settings.scss b/settings/css/settings.scss index 268cb0eee5d..d2dd973e887 100644 --- a/settings/css/settings.scss +++ b/settings/css/settings.scss @@ -347,7 +347,7 @@ table.nostyle { } .token-list { td > a.icon { - opacity: 0; + transition: opacity 0.5s; } a.icon { @@ -563,36 +563,26 @@ tr:hover > td { } td.userActions { - width: 25px; - text-align: center; - position: relative; - .action { - position: relative; - top: 3px; - } + width: 44px; .toggleUserActions { - border: none; - background-color: rgba(0, 0, 0, 0); - width: 34px; - height: 34px; - margin: 0; - opacity: 0.5; - &:hover, - &:focus { - background-color: transparent; - opacity: 1; + width: 44px; + height: 44px; + position: relative; + .action { + display: block; + padding: 14px; + opacity: 0.5; + .icon-more { + display: inline-block; + } + &:hover, + &:focus { + opacity: 1; + } } } } -tr.active td.userActions .action { - opacity: 1; -} - -td.userActions .action:hover { - cursor: pointer; -} - div.recoveryPassword { left: 50em; display: block; diff --git a/settings/js/settings/personalInfo.js b/settings/js/settings/personalInfo.js index 0a39e607762..99254c42090 100644 --- a/settings/js/settings/personalInfo.js +++ b/settings/js/settings/personalInfo.js @@ -395,6 +395,7 @@ $(document).ready(function () { t('settings', 'Strong password') ], drawTitles: true, + $addAfter: $('input[name="newpassword-clone"]'), }); // Load the big avatar diff --git a/settings/js/users/users.js b/settings/js/users/users.js index 1d6cb93452a..5a337c38556 100644 --- a/settings/js/users/users.js +++ b/settings/js/users/users.js @@ -101,16 +101,9 @@ var UserList = { $tdSubadmins.find('.action').tooltip({placement: 'top'}); /** - * user actions menu + * hide user actions menu for current user */ - if ($tr.find('td.userActions > span > img').length === 0 && OC.currentUser !== user.name) { - var menuImage = $('<img class="svg action">').attr({ - src: OC.imagePath('core', 'actions/more') - }); - var menuLink = $('<span class="toggleUserActions"></span>') - .append(menuImage); - $tr.find('td.userActions > span').replaceWith(menuLink); - } else if (OC.currentUser === user.name) { + if (OC.currentUser === user.name) { $tr.find('td.userActions').empty(); } diff --git a/settings/templates/users/part.userlist.php b/settings/templates/users/part.userlist.php index 146e35d11ac..aaf20b6eaef 100644 --- a/settings/templates/users/part.userlist.php +++ b/settings/templates/users/part.userlist.php @@ -1,4 +1,4 @@ -<table id="userlist" class="hascontrols grid" data-groups="<?php p($_['allGroups']);?>"> +<table id="userlist" class="grid" data-groups="<?php p($_['allGroups']);?>"> <thead> <tr> <th id="headerAvatar" scope="col"></th> @@ -64,19 +64,22 @@ <td class="storageLocation"></td> <td class="userBackend"></td> <td class="lastLogin"></td> - <td class="userActions"><span></span> - <div class="popovermenu bubble menu"> - <ul class="userActionsMenu"> - <li> - <a href="#" class="menuitem action-togglestate permanent" data-action="togglestate"></a> - </li> - <li> - <a href="#" class="menuitem action-remove permanent" data-action="remove"> - <span class="icon icon-delete"></span> - <span><?php p($l->t('Delete')); ?></span> - </a> - </li> - </ul> + <td class="userActions"> + <div class="toggleUserActions"> + <a class="action"><span class="icon-more"></span></a> + <div class="popovermenu bubble menu"> + <ul class="userActionsMenu"> + <li> + <a href="#" class="menuitem action-togglestate permanent" data-action="togglestate"></a> + </li> + <li> + <a href="#" class="menuitem action-remove permanent" data-action="remove"> + <span class="icon icon-delete"></span> + <span><?php p($l->t('Delete')); ?></span> + </a> + </li> + </ul> + </div> </div> </td> </tr> diff --git a/tests/acceptance/features/app-files.feature b/tests/acceptance/features/app-files.feature index 2cb43611b9a..ef3d07ae499 100644 --- a/tests/acceptance/features/app-files.feature +++ b/tests/acceptance/features/app-files.feature @@ -23,6 +23,13 @@ Feature: app-files When I open the details view for "welcome.txt" Then I see that the details view for "All files" section is open + Scenario: rename a file with the details view open + Given I am logged in + And I open the details view for "welcome.txt" + When I rename "welcome.txt" to "farewell.txt" + Then I see that the file list contains a file named "farewell.txt" + And I see that the file name shown in the details view is "farewell.txt" + Scenario: open the menu in a public shared link Given I act as John And I am logged in diff --git a/tests/acceptance/features/bootstrap/FilesAppContext.php b/tests/acceptance/features/bootstrap/FilesAppContext.php index 4951dc43f1d..117f3b54fb8 100644 --- a/tests/acceptance/features/bootstrap/FilesAppContext.php +++ b/tests/acceptance/features/bootstrap/FilesAppContext.php @@ -89,6 +89,15 @@ class FilesAppContext implements Context, ActorAwareInterface { /** * @return Locator */ + public static function fileNameInCurrentSectionDetailsView() { + return Locator::forThe()->css(".fileName")-> + descendantOf(self::currentSectionDetailsView())-> + describedAs("File name in current section details view in Files app"); + } + + /** + * @return Locator + */ public static function fileDetailsInCurrentSectionDetailsViewWithText($fileDetailsText) { return Locator::forThe()->xpath("//span[normalize-space() = '$fileDetailsText']")-> descendantOf(self::fileDetailsInCurrentSectionDetailsView())-> @@ -319,6 +328,14 @@ class FilesAppContext implements Context, ActorAwareInterface { /** * @return Locator */ + public static function renameInputForFile($fileName) { + return Locator::forThe()->css("input.filename")->descendantOf(self::rowForFile($fileName))-> + describedAs("Rename input for file $fileName in Files app"); + } + + /** + * @return Locator + */ public static function shareActionForFile($fileName) { return Locator::forThe()->css(".action-share")->descendantOf(self::rowForFile($fileName))-> describedAs("Share action for file $fileName in Files app"); @@ -350,6 +367,13 @@ class FilesAppContext implements Context, ActorAwareInterface { /** * @return Locator */ + public static function renameMenuItem() { + return self::fileActionsMenuItemFor("Rename"); + } + + /** + * @return Locator + */ public static function addToFavoritesMenuItem() { return self::fileActionsMenuItemFor("Add to favorites"); } @@ -418,6 +442,17 @@ class FilesAppContext implements Context, ActorAwareInterface { } /** + * @Given I rename :fileName1 to :fileName2 + */ + public function iRenameTo($fileName1, $fileName2) { + $this->actor->find(self::fileActionsMenuButtonForFile($fileName1), 10)->click(); + + $this->actor->find(self::renameMenuItem(), 2)->click(); + + $this->actor->find(self::renameInputForFile($fileName1), 10)->setValue($fileName2 . "\r"); + } + + /** * @Given I mark :fileName as favorite */ public function iMarkAsFavorite($fileName) { @@ -543,6 +578,13 @@ class FilesAppContext implements Context, ActorAwareInterface { } /** + * @Then I see that the file list contains a file named :fileName + */ + public function iSeeThatTheFileListContainsAFileNamed($fileName) { + PHPUnit_Framework_Assert::assertNotNull($this->actor->find(self::rowForFile($fileName), 10)); + } + + /** * @Then I see that :fileName1 precedes :fileName2 in the file list */ public function iSeeThatPrecedesInTheFileList($fileName1, $fileName2) { @@ -564,6 +606,14 @@ class FilesAppContext implements Context, ActorAwareInterface { } /** + * @Then I see that the file name shown in the details view is :fileName + */ + public function iSeeThatTheFileNameShownInTheDetailsViewIs($fileName) { + PHPUnit_Framework_Assert::assertEquals( + $this->actor->find(self::fileNameInCurrentSectionDetailsView(), 10)->getText(), $fileName); + } + + /** * @Then I see that the input field for tags in the details view is shown */ public function iSeeThatTheInputFieldForTagsInTheDetailsViewIsShown() { diff --git a/tests/acceptance/features/bootstrap/LoginPageContext.php b/tests/acceptance/features/bootstrap/LoginPageContext.php index 560dd83f308..1496e3030c2 100644 --- a/tests/acceptance/features/bootstrap/LoginPageContext.php +++ b/tests/acceptance/features/bootstrap/LoginPageContext.php @@ -66,7 +66,7 @@ class LoginPageContext implements Context, ActorAwareInterface { * @return Locator */ public static function wrongPasswordMessage() { - return Locator::forThe()->xpath("//*[@class = 'warning' and normalize-space() = 'Wrong password.']")-> + return Locator::forThe()->xpath("//*[@class = 'warning wrongPasswordMsg' and normalize-space() = 'Wrong password.']")-> describedAs("Wrong password message in Login page"); } |