summaryrefslogtreecommitdiffstats
path: root/apps
diff options
context:
space:
mode:
authorJoas Schilling <coding@schilljs.com>2016-07-18 12:43:11 +0200
committerGitHub <noreply@github.com>2016-07-18 12:43:11 +0200
commit89a32a2f84d73fedf12da3d90404b1894f64d0a9 (patch)
tree5196ffa43f70689fc187be1510194a67318961c8 /apps
parent5157c5a9c4b08518dc86e5755b991183f4323c43 (diff)
parent48ac845266fb4b4d9b3266ee58e622ac5965d0d3 (diff)
downloadnextcloud-server-89a32a2f84d73fedf12da3d90404b1894f64d0a9.tar.gz
nextcloud-server-89a32a2f84d73fedf12da3d90404b1894f64d0a9.zip
Merge pull request #412 from nextcloud/theming-foreground-color
Theming: invert foreground color on bright backgrounds
Diffstat (limited to 'apps')
-rw-r--r--apps/theming/js/settings-admin.js35
-rw-r--r--apps/theming/lib/controller/themingcontroller.php7
-rw-r--r--apps/theming/lib/util.php57
-rw-r--r--apps/theming/tests/lib/UtilTest.php66
-rw-r--r--apps/theming/tests/lib/controller/ThemingControllerTest.php67
5 files changed, 228 insertions, 4 deletions
diff --git a/apps/theming/js/settings-admin.js b/apps/theming/js/settings-admin.js
index bd4b4b34ed1..85e781411ed 100644
--- a/apps/theming/js/settings-admin.js
+++ b/apps/theming/js/settings-admin.js
@@ -31,17 +31,50 @@ function setThemingValue(setting, value) {
preview(setting, value);
}
+function calculateLuminance(rgb) {
+ var hexValue = rgb.replace(/[^0-9A-Fa-f]/, '');
+ var r,g,b;
+ if (hexValue.length === 3) {
+ hexValue = hexValue[0] + hexValue[0] + hexValue[1] + hexValue[1] + hexValue[2] + hexValue[2];
+ }
+ if (hexValue.length !== 6) {
+ return 0;
+ }
+ r = parseInt(hexValue.substring(0,2), 16);
+ g = parseInt(hexValue.substring(2,4), 16);
+ b = parseInt(hexValue.substring(4,6), 16);
+ return (0.299*r + 0.587*g + 0.114*b)/255;
+}
+
function preview(setting, value) {
if (setting === 'color') {
var headerClass = document.getElementById('header');
+ var expandDisplayNameClass = document.getElementById('expandDisplayName');
+ var headerAppName = headerClass.getElementsByClassName('header-appname')[0];
+ var textColor, icon;
+
+ if (calculateLuminance(value) > 0.5) {
+ textColor = "#000000";
+ icon = 'caret-dark';
+ } else {
+ textColor = "#ffffff";
+ icon = 'caret';
+ }
+
headerClass.style.background = value;
headerClass.style.backgroundImage = '../img/logo-icon.svg';
+ expandDisplayNameClass.style.color = textColor;
+ headerAppName.style.color = textColor;
+
+ $(headerClass).find('.icon-caret').each(function() {
+ $(this).css('background-image', "url('" + OC.getRootPath() + '/core/img/actions/' + icon + ".svg')");
+ });
}
if (setting === 'logoMime') {
console.log(setting);
var logos = document.getElementsByClassName('logo-icon');
var timestamp = new Date().getTime();
- if(value !== '') {
+ if (value !== '') {
logos[0].style.background = "url('" + OC.generateUrl('/apps/theming/logo') + "?v" + timestamp + "')";
logos[0].style.backgroundSize = "62px 34px";
} else {
diff --git a/apps/theming/lib/controller/themingcontroller.php b/apps/theming/lib/controller/themingcontroller.php
index a9ac36ca786..303bb85f540 100644
--- a/apps/theming/lib/controller/themingcontroller.php
+++ b/apps/theming/lib/controller/themingcontroller.php
@@ -30,6 +30,7 @@ use OCP\Files\IRootFolder;
use OCP\IConfig;
use OCP\IL10N;
use OCP\IRequest;
+use OCA\Theming\Util;
/**
* Class ThemingController
@@ -231,6 +232,12 @@ class ThemingController extends Controller {
background-image: url(\'./loginbackground?v='.$cacheBusterValue.'\');
}';
}
+ if(Util::invertTextColor($color)) {
+ $responseCss .= '#header .header-appname, #expandDisplayName { color: #000000; } ';
+ $responseCss .= '#header .icon-caret { background-image: url(\'' . \OC::$WEBROOT . '/core/img/actions/caret-dark.svg\'); } ';
+ $responseCss .= '.searchbox input[type="search"] { background: transparent url(\'' . \OC::$WEBROOT . '/core/img/actions/search.svg\') no-repeat 6px center; color: #000; }';
+ $responseCss .= '.searchbox input[type="search"]:focus,.searchbox input[type="search"]:active,.searchbox input[type="search"]:valid { color: #000; border: 1px solid rgba(0, 0, 0, .5); }';
+ }
\OC_Response::setExpiresHeader(gmdate('D, d M Y H:i:s', time() + (60*60*24*45)) . ' GMT');
\OC_Response::enableCaching();
diff --git a/apps/theming/lib/util.php b/apps/theming/lib/util.php
new file mode 100644
index 00000000000..8ff5ae89b14
--- /dev/null
+++ b/apps/theming/lib/util.php
@@ -0,0 +1,57 @@
+<?php
+/**
+ * @copyright Copyright (c) 2016 Julius Härtl <jus@bitgrid.net>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OCA\Theming;
+
+class Util {
+
+ /**
+ * @param string $color rgb color value
+ * @return bool
+ */
+ public static function invertTextColor($color) {
+ $l = self::calculateLuminance($color);
+ if($l>0.5) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * @param string $color rgb color value
+ * @return float
+ */
+ public static function calculateLuminance($color) {
+ $hex = preg_replace("/[^0-9A-Fa-f]/", '', $color);
+ if (strlen($hex) === 3) {
+ $hex = $hex{0} . $hex{0} . $hex{1} . $hex{1} . $hex{2} . $hex{2};
+ }
+ if (strlen($hex) !== 6) {
+ return 0;
+ }
+ $r = hexdec(substr($hex, 0, 2));
+ $g = hexdec(substr($hex, 2, 2));
+ $b = hexdec(substr($hex, 4, 2));
+ return (0.299 * $r + 0.587 * $g + 0.114 * $b)/255;
+ }
+
+}
diff --git a/apps/theming/tests/lib/UtilTest.php b/apps/theming/tests/lib/UtilTest.php
new file mode 100644
index 00000000000..266e6fc6c2d
--- /dev/null
+++ b/apps/theming/tests/lib/UtilTest.php
@@ -0,0 +1,66 @@
+<?php
+/**
+ * @copyright Copyright (c) 2016 Julius Härtl <jus@bitgrid.net>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+namespace OCA\Theming\Tests;
+
+use OCA\Theming\Util;
+use Test\TestCase;
+
+class UtilTest extends TestCase {
+
+ public function testInvertTextColorLight() {
+ $invert = Util::invertTextColor('#ffffff');
+ $this->assertEquals(true, $invert);
+ }
+
+ public function testInvertTextColorDark() {
+ $invert = Util::invertTextColor('#000000');
+ $this->assertEquals(false, $invert);
+ }
+
+ public function testCalculateLuminanceLight() {
+ $luminance = Util::calculateLuminance('#ffffff');
+ $this->assertEquals(1, $luminance);
+ }
+
+ public function testCalculateLuminanceDark() {
+ $luminance = Util::calculateLuminance('#000000');
+ $this->assertEquals(0, $luminance);
+ }
+
+ public function testCalculateLuminanceLightShorthand() {
+ $luminance = Util::calculateLuminance('#fff');
+ $this->assertEquals(1, $luminance);
+ }
+
+ public function testCalculateLuminanceDarkShorthand() {
+ $luminance = Util::calculateLuminance('#000');
+ $this->assertEquals(0, $luminance);
+ }
+ public function testInvertTextColorInvalid() {
+ $invert = Util::invertTextColor('aaabbbcccddd123');
+ $this->assertEquals(false, $invert);
+ }
+
+ public function testInvertTextColorEmpty() {
+ $invert = Util::invertTextColor('');
+ $this->assertEquals(false, $invert);
+ }
+}
diff --git a/apps/theming/tests/lib/controller/ThemingControllerTest.php b/apps/theming/tests/lib/controller/ThemingControllerTest.php
index d08ebce8663..1ed82ab8b58 100644
--- a/apps/theming/tests/lib/controller/ThemingControllerTest.php
+++ b/apps/theming/tests/lib/controller/ThemingControllerTest.php
@@ -311,6 +311,33 @@ class ThemingControllerTest extends TestCase {
->expects($this->at(1))
->method('getAppValue')
->with('theming', 'color', '')
+ ->willReturn('#000');
+ $this->config
+ ->expects($this->at(2))
+ ->method('getAppValue')
+ ->with('theming', 'logoMime', '')
+ ->willReturn('');
+ $this->config
+ ->expects($this->at(3))
+ ->method('getAppValue')
+ ->with('theming', 'backgroundMime', '')
+ ->willReturn('');
+
+ $expected = new Http\DataDownloadResponse('#body-user #header,#body-settings #header,#body-public #header {background-color: #000}', 'style', 'text/css');
+ $expected->cacheFor(3600);
+ @$this->assertEquals($expected, $this->themingController->getStylesheet());
+ }
+
+ public function testGetStylesheetWithOnlyColorInvert() {
+ $this->config
+ ->expects($this->at(0))
+ ->method('getAppValue')
+ ->with('theming', 'cachebuster', '0')
+ ->willReturn('0');
+ $this->config
+ ->expects($this->at(1))
+ ->method('getAppValue')
+ ->with('theming', 'color', '')
->willReturn('#fff');
$this->config
->expects($this->at(2))
@@ -323,7 +350,7 @@ class ThemingControllerTest extends TestCase {
->with('theming', 'backgroundMime', '')
->willReturn('');
- $expected = new Http\DataDownloadResponse('#body-user #header,#body-settings #header,#body-public #header {background-color: #fff}', 'style', 'text/css');
+ $expected = new Http\DataDownloadResponse('#body-user #header,#body-settings #header,#body-public #header {background-color: #fff}#header .header-appname, #expandDisplayName { color: #000000; } #header .icon-caret { background-image: url(\'' . \OC::$WEBROOT . '/core/img/actions/caret-dark.svg\'); } .searchbox input[type="search"] { background: transparent url(\'' . \OC::$WEBROOT . '/core/img/actions/search.svg\') no-repeat 6px center; color: #000; }.searchbox input[type="search"]:focus,.searchbox input[type="search"]:active,.searchbox input[type="search"]:valid { color: #000; border: 1px solid rgba(0, 0, 0, .5); }', 'style', 'text/css');
$expected->cacheFor(3600);
@$this->assertEquals($expected, $this->themingController->getStylesheet());
}
@@ -400,7 +427,7 @@ class ThemingControllerTest extends TestCase {
->expects($this->at(1))
->method('getAppValue')
->with('theming', 'color', '')
- ->willReturn('#abc');
+ ->willReturn('#000');
$this->config
->expects($this->at(2))
->method('getAppValue')
@@ -412,7 +439,7 @@ class ThemingControllerTest extends TestCase {
->with('theming', 'backgroundMime', '')
->willReturn('image/png');
- $expected = new Http\DataDownloadResponse('#body-user #header,#body-settings #header,#body-public #header {background-color: #abc}#header .logo {
+ $expected = new Http\DataDownloadResponse('#body-user #header,#body-settings #header,#body-public #header {background-color: #000}#header .logo {
background-image: url(\'./logo?v=0\');
}
#header .logo-icon {
@@ -424,5 +451,39 @@ class ThemingControllerTest extends TestCase {
$expected->cacheFor(3600);
@$this->assertEquals($expected, $this->themingController->getStylesheet());
}
+ public function testGetStylesheetWithAllCombinedInverted() {
+ $this->config
+ ->expects($this->at(0))
+ ->method('getAppValue')
+ ->with('theming', 'cachebuster', '0')
+ ->willReturn('0');
+ $this->config
+ ->expects($this->at(1))
+ ->method('getAppValue')
+ ->with('theming', 'color', '')
+ ->willReturn('#fff');
+ $this->config
+ ->expects($this->at(2))
+ ->method('getAppValue')
+ ->with('theming', 'logoMime', '')
+ ->willReturn('text/svg');
+ $this->config
+ ->expects($this->at(3))
+ ->method('getAppValue')
+ ->with('theming', 'backgroundMime', '')
+ ->willReturn('image/png');
+
+ $expected = new Http\DataDownloadResponse('#body-user #header,#body-settings #header,#body-public #header {background-color: #fff}#header .logo {
+ background-image: url(\'./logo?v=0\');
+ }
+ #header .logo-icon {
+ background-image: url(\'./logo?v=0\');
+ background-size: 62px 34px;
+ }#body-login {
+ background-image: url(\'./loginbackground?v=0\');
+ }#header .header-appname, #expandDisplayName { color: #000000; } #header .icon-caret { background-image: url(\'' . \OC::$WEBROOT . '/core/img/actions/caret-dark.svg\'); } .searchbox input[type="search"] { background: transparent url(\'' . \OC::$WEBROOT . '/core/img/actions/search.svg\') no-repeat 6px center; color: #000; }.searchbox input[type="search"]:focus,.searchbox input[type="search"]:active,.searchbox input[type="search"]:valid { color: #000; border: 1px solid rgba(0, 0, 0, .5); }', 'style', 'text/css');
+ $expected->cacheFor(3600);
+ @$this->assertEquals($expected, $this->themingController->getStylesheet());
+ }
}