diff --git a/Gemfile.lock b/Gemfile.lock index 95d723105e..cadf36185c 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -559,10 +559,9 @@ DEPENDENCIES rubytree (~> 0.8.3) sass (~> 3.4.12) sass-rails! + selenium-webdriver (~> 2.45.0) shoulda-context (~> 1.2) shoulda-matchers (~> 2.8) - selenium-webdriver (~> 2.45.0) - shoulda simplecov (= 0.8.0.pre) sprockets! sprockets-rails! diff --git a/app/assets/stylesheets/content/_select2.scss b/app/assets/stylesheets/content/_select2.scss index 3040b1078c..147db2c0a7 100644 --- a/app/assets/stylesheets/content/_select2.scss +++ b/app/assets/stylesheets/content/_select2.scss @@ -62,7 +62,7 @@ .select2-results .select2-highlighted { border-radius: 5px; - background-color: #24B3E7; + background-color: $drop-down-selected-bg-color; font-weight:bold; } .select2-results .select2-result-unselectable { @@ -172,7 +172,7 @@ $se2-width: 100%; } &.select2-dropdown-open { - + .select2-choice { background-color: $se2-theme-selectable-color; } diff --git a/app/assets/stylesheets/layout/_top_menu.sass b/app/assets/stylesheets/layout/_top_menu.sass index afafd585e3..b0ef9c17a4 100644 --- a/app/assets/stylesheets/layout/_top_menu.sass +++ b/app/assets/stylesheets/layout/_top_menu.sass @@ -216,7 +216,7 @@ padding: 0 .select2-highlighted - background: $header-item-bg-hover-color !important + background: $primary-color !important border-radius: 0 !important font-weight: bold !important color: $header-drop-down-item-font-hover-color diff --git a/app/assets/stylesheets/open_project_global/_variables.sass b/app/assets/stylesheets/open_project_global/_variables.sass index 30a8f03de5..1419499b42 100644 --- a/app/assets/stylesheets/open_project_global/_variables.sass +++ b/app/assets/stylesheets/open_project_global/_variables.sass @@ -165,7 +165,7 @@ $my-page-edit-box-border-color: $primary-color-dark !default $drop-down-unselected-font-color: $main-menu-font-color !default $drop-down-selected-font-color: $main-menu-font-color !default -$drop-down-selected-bg-color: #24B3E7 !default +$drop-down-selected-bg-color: $primary-color !default $action-menu-bg-color: #FFFFFF diff --git a/frontend/app/openproject-app.js b/frontend/app/openproject-app.js index 8c4c349c8c..06ad4c24bd 100644 --- a/frontend/app/openproject-app.js +++ b/frontend/app/openproject-app.js @@ -203,7 +203,12 @@ openprojectApp $httpProvider.interceptors.push(function($q) { return { 'request': function(config) { - if (!config.url.match('(^/templates|\\.html$)')) { + // OpenProject can run in a subpath e.g. https://mydomain/open_project. + // We append the path found as the base-tag value to all http requests + // to the server except: + // * when the path is already appended + // * when we are getting a template + if (!config.url.match('(^/templates|\\.html$|^' + window.appBasePath + ')')) { config.url = window.appBasePath + config.url; } diff --git a/frontend/app/services/timezone-service.js b/frontend/app/services/timezone-service.js index 118ed270b9..3cfb5f80ad 100644 --- a/frontend/app/services/timezone-service.js +++ b/frontend/app/services/timezone-service.js @@ -33,8 +33,8 @@ module.exports = function(ConfigurationService, I18n) { moment.locale(I18n.locale); }, - parseDate: function(date, format) { - var d = moment.utc(date, format); + parseDatetime: function(datetime, format) { + var d = moment.utc(datetime, format); if (ConfigurationService.isTimezoneSet()) { d.local(); @@ -44,18 +44,27 @@ module.exports = function(ConfigurationService, I18n) { return d; }, + parseDate: function(date, format) { + return moment(date, format); + }, + parseISODate: function(date) { return TimezoneService.parseDate(date, 'YYYY-MM-DD'); }, formattedDate: function(date) { - var format = ConfigurationService.dateFormatPresent() ? ConfigurationService.dateFormat() : 'L'; - return TimezoneService.parseDate(date).format(format); + var d = TimezoneService.parseDate(date); + return d.format(TimezoneService.getDateFormat()); + }, + + formattedTime: function(datetimeString) { + return TimezoneService.parseDatetime(datetimeString).format(TimezoneService.getTimeFormat()); }, - formattedTime: function(date) { - var format = ConfigurationService.timeFormatPresent() ? ConfigurationService.timeFormat() : 'LT'; - return TimezoneService.parseDate(date).format(format); + formattedDatetime: function(datetimeString) { + var d = TimezoneService.parseDatetime(datetimeString); + return d.format(TimezoneService.getDateFormat()) + ' ' + + d.format(TimezoneService.getTimeFormat()); }, formattedISODate: function(date) { @@ -70,6 +79,14 @@ module.exports = function(ConfigurationService, I18n) { var format = dateFormat || (ConfigurationService.dateFormatPresent() ? ConfigurationService.dateFormat() : 'L'); return moment(date, [format]).isValid(); + }, + + getDateFormat: function() { + return ConfigurationService.dateFormatPresent() ? ConfigurationService.dateFormat() : 'L'; + }, + + getTimeFormat: function() { + return ConfigurationService.timeFormatPresent() ? ConfigurationService.timeFormat() : 'LT'; } }; diff --git a/frontend/app/ui_components/authoring-directive.js b/frontend/app/ui_components/authoring-directive.js index fc2dbe4a77..3d047b3efe 100644 --- a/frontend/app/ui_components/authoring-directive.js +++ b/frontend/app/ui_components/authoring-directive.js @@ -36,7 +36,7 @@ module.exports = function(I18n, PathHelper, TimezoneService) { link: function(scope, element, attrs) { moment.locale(I18n.locale); - var createdOn = TimezoneService.parseDate(scope.createdOn); + var createdOn = TimezoneService.parseDatetime(scope.createdOn); var timeago = createdOn.fromNow(); var time = createdOn.format('LLL'); diff --git a/frontend/app/work_packages/helpers/work-packages-helper.js b/frontend/app/work_packages/helpers/work-packages-helper.js index 3d917ddddd..63ad83666c 100644 --- a/frontend/app/work_packages/helpers/work-packages-helper.js +++ b/frontend/app/work_packages/helpers/work-packages-helper.js @@ -141,9 +141,7 @@ module.exports =function(TimezoneService, currencyFilter, CustomFieldHelper) { case 'datetime': var dateTime; if (value) { - dateTime = TimezoneService.formattedDate(value) + - ' ' + - TimezoneService.formattedTime(value); + dateTime = TimezoneService.formattedDatetime(value); } return dateTime || ''; case 'date': diff --git a/frontend/tests/integration/mocks/work-package.json b/frontend/tests/integration/mocks/work-package.json index c57a988e02..6c67609900 100644 --- a/frontend/tests/integration/mocks/work-package.json +++ b/frontend/tests/integration/mocks/work-package.json @@ -86,8 +86,8 @@ "raw": "Sapiente terra dolores tempore debitis stultus. Adeo aduro repellendus. Vereor vulgivagus maxime ulciscor barba deleniti cognomen ustulo. Hic tubineus sumptus argumentum animi arcesso. Voluntarius dolore et. Apostolus vobis ultra delego acervus averto vitae." }, "priority": "Normal", - "startDate": "2014-02-28T00:00:00+00:00", - "dueDate": "2014-04-28T00:00:00+00:00", + "startDate": "2014-02-28", + "dueDate": "2014-04-28", "estimatedTime": { "units": "hours", "value": null diff --git a/frontend/tests/integration/mocks/work-packages/819_patch.json b/frontend/tests/integration/mocks/work-packages/819_patch.json index 55e839a28e..69967bd998 100644 --- a/frontend/tests/integration/mocks/work-packages/819_patch.json +++ b/frontend/tests/integration/mocks/work-packages/819_patch.json @@ -107,8 +107,8 @@ "status": "specified", "isClosed": false, "priority": "Normal", - "startDate": "2014-10-23T00:00:00+00:00", - "dueDate": "2014-12-27T00:00:00+00:00", + "startDate": "2014-10-23", + "dueDate": "2014-12-27", "estimatedTime": "PT0S", "spentTime": "PT0S", "percentageDone": 0, diff --git a/frontend/tests/integration/mocks/work-packages/820.json b/frontend/tests/integration/mocks/work-packages/820.json index 7f51263bae..73d9b9c392 100644 --- a/frontend/tests/integration/mocks/work-packages/820.json +++ b/frontend/tests/integration/mocks/work-packages/820.json @@ -93,8 +93,8 @@ "raw": "#54\n2" }, "priority": "Normal", - "startDate": "2014-10-23T00:00:00+00:00", - "dueDate": "2014-12-27T00:00:00+00:00", + "startDate": "2014-10-23", + "dueDate": "2014-12-27", "estimatedTime": "PT0S", "spentTime": "PT0S", "percentageDone": 0, diff --git a/frontend/tests/integration/mocks/work-packages/821.json b/frontend/tests/integration/mocks/work-packages/821.json index 5c9a5fddde..9766b218c6 100644 --- a/frontend/tests/integration/mocks/work-packages/821.json +++ b/frontend/tests/integration/mocks/work-packages/821.json @@ -103,8 +103,8 @@ "raw": "#54\n2" }, "priority": "Normal", - "startDate": "2014-10-23T00:00:00+00:00", - "dueDate": "2014-12-27T00:00:00+00:00", + "startDate": "2014-10-23", + "dueDate": "2014-12-27", "estimatedTime": "PT0S", "spentTime": "PT0S", "percentageDone": 0, diff --git a/frontend/tests/integration/mocks/work-packages/822.json b/frontend/tests/integration/mocks/work-packages/822.json index 52fccc45f4..9bb8a95941 100644 --- a/frontend/tests/integration/mocks/work-packages/822.json +++ b/frontend/tests/integration/mocks/work-packages/822.json @@ -105,8 +105,8 @@ "description": "", "rawDescription": "", "priority": "Normal", - "startDate": "2014-10-23T00:00:00+00:00", - "dueDate": "2014-12-27T00:00:00+00:00", + "startDate": "2014-10-23", + "dueDate": "2014-12-27", "estimatedTime": "PT0S", "spentTime": "PT12H", "percentageDone": 0, diff --git a/frontend/tests/integration/mocks/work-packages/823.json b/frontend/tests/integration/mocks/work-packages/823.json index 4494a5896f..ee2dc70d9f 100644 --- a/frontend/tests/integration/mocks/work-packages/823.json +++ b/frontend/tests/integration/mocks/work-packages/823.json @@ -109,7 +109,7 @@ }, "priority": "Normal", "startDate": null, - "dueDate": "2014-12-27T00:00:00+00:00", + "dueDate": "2014-12-27", "estimatedTime": "PT0S", "spentTime": "PT0S", "percentageDone": 0, diff --git a/frontend/tests/integration/mocks/work-packages/824.json b/frontend/tests/integration/mocks/work-packages/824.json index cc90188e37..251258402e 100644 --- a/frontend/tests/integration/mocks/work-packages/824.json +++ b/frontend/tests/integration/mocks/work-packages/824.json @@ -108,7 +108,7 @@ "raw": "#54" }, "priority": "Normal", - "startDate": "2014-10-23T00:00:00+00:00", + "startDate": "2014-10-23", "dueDate": null, "estimatedTime": "PT0S", "spentTime": "PT0S", diff --git a/frontend/tests/integration/mocks/work-packages/825.json b/frontend/tests/integration/mocks/work-packages/825.json index f7b2130656..6a1d754d77 100644 --- a/frontend/tests/integration/mocks/work-packages/825.json +++ b/frontend/tests/integration/mocks/work-packages/825.json @@ -112,7 +112,7 @@ "raw": "#54" }, "priority": "Normal", - "startDate": "2014-10-23T00:00:00+00:00", + "startDate": "2014-10-23", "dueDate": null, "estimatedTime": "PT0S", "spentTime": "PT0S", diff --git a/frontend/tests/unit/tests/services/timezone-service-test.js b/frontend/tests/unit/tests/services/timezone-service-test.js index 982be18d0b..27ab994c16 100644 --- a/frontend/tests/unit/tests/services/timezone-service-test.js +++ b/frontend/tests/unit/tests/services/timezone-service-test.js @@ -31,6 +31,7 @@ describe('TimezoneService', function() { var TIME = '2013-02-08T09:30:26'; + var DATE = '2013-02-08'; var TimezoneService; var ConfigurationService; var isTimezoneSetStub; @@ -42,15 +43,15 @@ describe('TimezoneService', function() { TimezoneService = _TimezoneService_; ConfigurationService = _ConfigurationService_; - isTimezoneSetStub = sinon.stub(ConfigurationService, "isTimezoneSet"); - timezoneStub = sinon.stub(ConfigurationService, "timezone"); + isTimezoneSetStub = sinon.stub(ConfigurationService, 'isTimezoneSet'); + timezoneStub = sinon.stub(ConfigurationService, 'timezone'); })); - describe('#parseDate', function() { + describe('#parseDatetime', function() { it('is UTC', function() { - var time = TimezoneService.parseDate(TIME); + var time = TimezoneService.parseDatetime(TIME); expect(time.zone()).to.equal(0); - expect(time.format("HH:mm")).to.eq("09:30"); + expect(time.format('HH:mm')).to.eq('09:30'); }); describe('Non-UTC timezone', function() { @@ -61,12 +62,24 @@ describe('TimezoneService', function() { isTimezoneSetStub.returns(true); timezoneStub.returns(timezone); - date = TimezoneService.parseDate(TIME); + date = TimezoneService.parseDatetime(TIME); }); it('is ' + timezone, function() { - expect(date.format("HH:mm")).to.eq("01:30"); + expect(date.format('HH:mm')).to.eq('01:30'); }); }); }); + + describe('#parseDate', function() { + it('has local time zone', function() { + var time = TimezoneService.parseDate(DATE); + expect(time.zone()).to.equal(time.clone().local().zone()); + }); + + it('has no time information', function() { + var time = TimezoneService.parseDate(DATE); + expect(time.format('HH:mm')).to.eq('00:00'); + }); + }); }); diff --git a/frontend/tests/unit/tests/ui_components/authoring-directive-test.js b/frontend/tests/unit/tests/ui_components/authoring-directive-test.js index a503913fab..3197a6b0d7 100644 --- a/frontend/tests/unit/tests/ui_components/authoring-directive-test.js +++ b/frontend/tests/unit/tests/ui_components/authoring-directive-test.js @@ -37,7 +37,7 @@ describe('authoring Directive', function() { beforeEach(module('openproject.templates', function($provide) { timezoneService = {}; - timezoneService.parseDate = sinon.stub().returns(createdOn); + timezoneService.parseDatetime = sinon.stub().returns(createdOn); $provide.constant('TimezoneService', timezoneService); }));