From ca3a3817c7c5de0b89e5105adb88a0f7419df8e1 Mon Sep 17 00:00:00 2001 From: Felix Hammerl Date: Fri, 26 Feb 2016 18:27:13 +0100 Subject: Issue #617: Serve content from Sandbox resource --- service/pixelated/resources/root_resource.py | 2 ++ service/pixelated/resources/sandbox_resource.py | 34 +++++++++++++++++++ .../test/unit/resources/test_sandbox_resource.py | 38 ++++++++++++++++++++++ 3 files changed, 74 insertions(+) create mode 100644 service/pixelated/resources/sandbox_resource.py create mode 100644 service/test/unit/resources/test_sandbox_resource.py diff --git a/service/pixelated/resources/root_resource.py b/service/pixelated/resources/root_resource.py index 86435d89..109dc08e 100644 --- a/service/pixelated/resources/root_resource.py +++ b/service/pixelated/resources/root_resource.py @@ -20,6 +20,7 @@ from string import Template from pixelated.resources import BaseResource, UnAuthorizedResource from pixelated.resources.attachments_resource import AttachmentsResource +from pixelated.resources.sandbox_resource import SandboxResource from pixelated.resources.contacts_resource import ContactsResource from pixelated.resources.features_resource import FeaturesResource from pixelated.resources.feedback_resource import FeedbackResource @@ -75,6 +76,7 @@ class RootResource(BaseResource): return csrf_input and csrf_input == xsrf_token def initialize(self, portal=None, disclaimer_banner=None): + self._child_resources.add('sandbox', SandboxResource(self._static_folder)) self._child_resources.add('assets', File(self._static_folder)) self._child_resources.add('keys', KeysResource(self._services_factory)) self._child_resources.add(AttachmentsResource.BASE_URL, AttachmentsResource(self._services_factory)) diff --git a/service/pixelated/resources/sandbox_resource.py b/service/pixelated/resources/sandbox_resource.py new file mode 100644 index 00000000..28e8c9be --- /dev/null +++ b/service/pixelated/resources/sandbox_resource.py @@ -0,0 +1,34 @@ +# +# Copyright (c) 2016 ThoughtWorks, Inc. +# +# Pixelated 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. +# +# Pixelated 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 Pixelated. If not, see . + +from twisted.web.static import File + + +class SandboxResource(File): + CSP_HEADER_VALUES = "sandbox allow-popups allow-scripts;" \ + "default-src 'self';" \ + "style-src *;" \ + "script-src *;" \ + "font-src *;" \ + "img-src *;" \ + "object-src 'none';" \ + "connect-src 'none';" + + def render_GET(self, request): + request.setHeader('Content-Security-Policy', self.CSP_HEADER_VALUES) + request.setHeader('X-Content-Security-Policy', self.CSP_HEADER_VALUES) + request.setHeader('X-Webkit-CSP', self.CSP_HEADER_VALUES) + return super(SandboxResource, self).render_GET(request) diff --git a/service/test/unit/resources/test_sandbox_resource.py b/service/test/unit/resources/test_sandbox_resource.py new file mode 100644 index 00000000..3db43e12 --- /dev/null +++ b/service/test/unit/resources/test_sandbox_resource.py @@ -0,0 +1,38 @@ +import os +import unittest + +from twisted.internet import defer +from twisted.web.test.requesthelper import DummyRequest + +from pixelated.resources.sandbox_resource import SandboxResource +from test.unit.resources import DummySite + + +class TestSandBoxResource(unittest.TestCase): + def setUp(self): + static_folder = os.path.dirname(os.path.abspath(__file__)) + self.resource = SandboxResource(static_folder) + self.resource.isLeaf = True + self.web = DummySite(self.resource) + + @defer.inlineCallbacks + def test_render_GET_should_set_sandbox_csp_header(self): + request = DummyRequest(['/sandbox']) + request.method = 'GET' + request.isSecure = lambda: True + request.redirect = lambda _: 'irrelevant' + + expected_csp_headers = "sandbox allow-popups allow-scripts;" \ + "default-src 'self';" \ + "style-src *;" \ + "script-src *;" \ + "font-src *;" \ + "img-src *;" \ + "object-src 'none';" \ + "connect-src 'none';" + + yield self.web.get(request) + + self.assertEquals(expected_csp_headers, request.outgoingHeaders.get('X-Content-Security-Policy'.lower())) + self.assertEquals(expected_csp_headers, request.outgoingHeaders.get('Content-Security-Policy'.lower())) + self.assertEquals(expected_csp_headers, request.outgoingHeaders.get('X-Webkit-CSP'.lower())) -- cgit v1.2.3 From 3bdb9ecbeccae7842ef566f47b8119583d327cb2 Mon Sep 17 00:00:00 2001 From: Felix Hammerl Date: Fri, 26 Feb 2016 18:29:24 +0100 Subject: Issue #617: Add iframe-resizer --- web-ui/app/index.html | 1 + web-ui/bower.json | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/web-ui/app/index.html b/web-ui/app/index.html index 2d35662c..107e9102 100644 --- a/web-ui/app/index.html +++ b/web-ui/app/index.html @@ -100,6 +100,7 @@ + diff --git a/web-ui/bower.json b/web-ui/bower.json index 263ac2e4..018a57c4 100644 --- a/web-ui/bower.json +++ b/web-ui/bower.json @@ -17,7 +17,8 @@ "jquery-file-upload": "~9.11.2", "jquery-ui": "~1.11.4", "DOMPurify": "~0.7.4", - "he": "~0.5.0" + "he": "~0.5.0", + "iframe-resizer": "~3.5.3" }, "devDependencies": { "handlebars": "2.0.0", -- cgit v1.2.3 From 7b5d5ef57289c00b0314522b2c2981e4fc7a0f6c Mon Sep 17 00:00:00 2001 From: Felix Hammerl Date: Fri, 26 Feb 2016 18:31:29 +0100 Subject: Issue #617: Create sandbox resouces --- web-ui/app/js/sandbox.js | 9 +++++++++ web-ui/app/sandbox.html | 17 +++++++++++++++++ web-ui/app/scss/sandbox.scss | 14 ++++++++++++++ 3 files changed, 40 insertions(+) create mode 100644 web-ui/app/js/sandbox.js create mode 100644 web-ui/app/sandbox.html create mode 100644 web-ui/app/scss/sandbox.scss diff --git a/web-ui/app/js/sandbox.js b/web-ui/app/js/sandbox.js new file mode 100644 index 00000000..f9e708d6 --- /dev/null +++ b/web-ui/app/js/sandbox.js @@ -0,0 +1,9 @@ +(function () { + 'use strict'; + + window.onmessage = function (e) { + if (e.data.html) { + document.body.innerHTML = e.data.html; + } + }; +})(); diff --git a/web-ui/app/sandbox.html b/web-ui/app/sandbox.html new file mode 100644 index 00000000..13a86f25 --- /dev/null +++ b/web-ui/app/sandbox.html @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/web-ui/app/scss/sandbox.scss b/web-ui/app/scss/sandbox.scss new file mode 100644 index 00000000..e722753d --- /dev/null +++ b/web-ui/app/scss/sandbox.scss @@ -0,0 +1,14 @@ +body { + font-family: "Open Sans", "Microsoft YaHei", "Hiragino Sans GB", "Hiragino Sans GB W3", "微软雅黑", "Helvetica Neue", Arial, sans-serif; + font-size: 13px; + line-height: 1.2em; + background: white; + color: #333; + padding: 0; + margin: 0; + font-weight: normal; + -webkit-font-smoothing: antialiased; + font-style: normal; + box-sizing: border-box; + word-wrap: break-word; +} -- cgit v1.2.3 From 9cbf33071f895a3ca1c9dad398d964e189e4a766 Mon Sep 17 00:00:00 2001 From: Felix Hammerl Date: Fri, 26 Feb 2016 18:33:10 +0100 Subject: Issue #617: Add sandbox to user-agent --- .../test/functional/features/steps/mail_view.py | 5 ++- web-ui/app/js/mail_view/ui/mail_view.js | 46 +++++++++++++++++++++- web-ui/app/scss/_read.scss | 7 ++++ web-ui/app/templates/mails/full_view.hbs | 1 + 4 files changed, 57 insertions(+), 2 deletions(-) diff --git a/service/test/functional/features/steps/mail_view.py b/service/test/functional/features/steps/mail_view.py index 82fc28af..c0e9e22b 100644 --- a/service/test/functional/features/steps/mail_view.py +++ b/service/test/functional/features/steps/mail_view.py @@ -25,8 +25,11 @@ def impl(context, subject): @then('I see that the body reads \'{expected_body}\'') def impl(context, expected_body): - e = find_element_by_css_selector(context, '#mail-view .bodyArea') + find_element_by_css_selector(context, '#read-sandbox') + context.browser.switch_to_frame('read-sandbox') + e = find_element_by_css_selector(context, 'body') assert e.text == expected_body + context.browser.switch_to_default_content() @then('that email has the \'{tag}\' tag') diff --git a/web-ui/app/js/mail_view/ui/mail_view.js b/web-ui/app/js/mail_view/ui/mail_view.js index dfc57585..d15788bb 100644 --- a/web-ui/app/js/mail_view/ui/mail_view.js +++ b/web-ui/app/js/mail_view/ui/mail_view.js @@ -71,7 +71,51 @@ define( attachments: attachments })); - this.$node.find('.bodyArea').html(viewHelpers.formatMailBody(data.mail)); + var $iframe = $("#read-sandbox"); + var iframe = $iframe[0]; + + var content = viewHelpers.formatMailBody(data.mail); + + iframe.onload = function() { + // use iframe-resizer to dynamically adapt iframe size to its content + var config = { + resizedCallback: scaleToFit, + checkOrigin: false + }; + $iframe.iFrameResize(config); + + // transform scale iframe to fit container width + // necessary if iframe is wider than container + function scaleToFit() { + var parentWidth = $iframe.parent().width(); + var w = $iframe.width(); + var scale = 'none'; + + // only scale html mails + var mail = data.mail; + if (mail && mail.htmlBody && (w > parentWidth)) { + scale = parentWidth / w; + scale = 'scale(' + scale + ',' + scale + ')'; + } + + $iframe.css({ + '-webkit-transform-origin': '0 0', + '-moz-transform-origin': '0 0', + '-ms-transform-origin': '0 0', + 'transform-origin': '0 0', + '-webkit-transform': scale, + '-moz-transform': scale, + '-ms-transform': scale, + 'transform': scale + }); + } + + iframe.contentWindow.postMessage({ + html: content + }, '*'); + }; + + this.trigger(document, events.search.highlightResults, {where: '.bodyArea'}); this.trigger(document, events.search.highlightResults, {where: '.subjectArea'}); diff --git a/web-ui/app/scss/_read.scss b/web-ui/app/scss/_read.scss index 2c079408..236a7c7c 100644 --- a/web-ui/app/scss/_read.scss +++ b/web-ui/app/scss/_read.scss @@ -66,6 +66,13 @@ .bodyArea { padding: 10px 30px 0 30px; + box-sizing: border-box; + + iframe { + box-sizing: inherit; + border: none; + width: 100%; + } } .attachmentsAreaWrap { diff --git a/web-ui/app/templates/mails/full_view.hbs b/web-ui/app/templates/mails/full_view.hbs index f9ec084a..3ff109e9 100644 --- a/web-ui/app/templates/mails/full_view.hbs +++ b/web-ui/app/templates/mails/full_view.hbs @@ -64,6 +64,7 @@
+
{{#if attachments}} -- cgit v1.2.3 From a29c07d54947b712a41226df1242b4cb21fd55ec Mon Sep 17 00:00:00 2001 From: Felix Hammerl Date: Fri, 26 Feb 2016 18:35:11 +0100 Subject: Issue #617: Add sandbox to build scripts --- web-ui/config/package.sh | 20 ++++++++++++++++++-- web-ui/package.json | 1 + 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/web-ui/config/package.sh b/web-ui/config/package.sh index 9b6bc66c..0bd82367 100644 --- a/web-ui/config/package.sh +++ b/web-ui/config/package.sh @@ -28,16 +28,24 @@ mkdir -p dist ./go handlebars ./go imagemin ./go minify_html +./go minify_sandbox ./go add_git_version ./go buildmain # copy files cd app -cp --parents 404.html fonts/* locales/**/* bower_components/font-awesome/css/font-awesome.min.css bower_components/jquery-file-upload/css/jquery.fileupload.css bower_components/font-awesome/fonts/* ../dist +cp --parents \ +404.html \ +fonts/* \ +locales/**/* \ +bower_components/font-awesome/css/font-awesome.min.css \ +bower_components/jquery-file-upload/css/jquery.fileupload.css \ +bower_components/font-awesome/fonts/* \ +../dist cd - -# concat js files and minify +# concat js files and minify for app.min.js cat \ app/bower_components/modernizr/modernizr.js \ app/bower_components/lodash/dist/lodash.js \ @@ -51,6 +59,14 @@ app/bower_components/foundation/js/foundation.js \ app/bower_components/foundation/js/foundation/foundation.reveal.js \ app/bower_components/foundation/js/foundation/foundation.offcanvas.js \ app/js/foundation/initialize_foundation.js \ +app/bower_components/iframe-resizer/js/iframeResizer.min.js \ .tmp/app.concatenated.js > dist/app.js node_modules/.bin/minify dist/app.js > dist/app.min.js rm dist/app.js + +# concat js files and minify for sandbox.min.js +cat \ +app/js/sandbox.js \ +app/bower_components/iframe-resizer/js/iframeResizer.contentWindow.min.js > dist/sandbox.js +node_modules/.bin/minify dist/sandbox.js > dist/sandbox.min.js +rm dist/sandbox.js diff --git a/web-ui/package.json b/web-ui/package.json index a49e32d1..0e8b9262 100644 --- a/web-ui/package.json +++ b/web-ui/package.json @@ -38,6 +38,7 @@ "package": "/bin/bash config/package.sh", "imagemin": "node config/imagemin.js", "minify_html": "node_modules/.bin/html-minifier app/index.html --collapse-whitespace | sed 's|.*||' > dist/index.html", + "minify_sandbox": "node_modules/.bin/html-minifier app/sandbox.html --collapse-whitespace | sed 's|.*||' > dist/sandbox.html", "add_git_version": "/bin/bash config/add_git_version.sh" } } -- cgit v1.2.3 From 1ae14c78bcf79db82d492f9b9a9ae186433ac8fc Mon Sep 17 00:00:00 2001 From: Felix Hammerl Date: Tue, 1 Mar 2016 19:06:36 +0100 Subject: Issue #617: Remove highlighting for sandboxed content --- web-ui/app/js/mail_list/ui/mail_list.js | 1 - web-ui/app/js/mail_view/ui/mail_view.js | 1 - 2 files changed, 2 deletions(-) diff --git a/web-ui/app/js/mail_list/ui/mail_list.js b/web-ui/app/js/mail_list/ui/mail_list.js index 18d36049..0f6c4fb5 100644 --- a/web-ui/app/js/mail_list/ui/mail_list.js +++ b/web-ui/app/js/mail_list/ui/mail_list.js @@ -81,7 +81,6 @@ define( this.renderMails = function (mails) { _.each(mails, this.appendMail, this); this.trigger(document, events.search.highlightResults, {where: '#mail-list'}); - this.trigger(document, events.search.highlightResults, {where: '.bodyArea'}); this.trigger(document, events.search.highlightResults, {where: '.subjectArea'}); this.trigger(document, events.search.highlightResults, {where: '.msg-header .recipients'}); }; diff --git a/web-ui/app/js/mail_view/ui/mail_view.js b/web-ui/app/js/mail_view/ui/mail_view.js index d15788bb..fbbba409 100644 --- a/web-ui/app/js/mail_view/ui/mail_view.js +++ b/web-ui/app/js/mail_view/ui/mail_view.js @@ -117,7 +117,6 @@ define( - this.trigger(document, events.search.highlightResults, {where: '.bodyArea'}); this.trigger(document, events.search.highlightResults, {where: '.subjectArea'}); this.trigger(document, events.search.highlightResults, {where: '.msg-header .recipients'}); this.trigger(document, events.ui.replyBox.showReplyContainer); -- cgit v1.2.3 From 2b41494b1472049cc056959cb093411c96370145 Mon Sep 17 00:00:00 2001 From: Felix Hammerl Date: Wed, 2 Mar 2016 11:57:05 +0100 Subject: Issue #617: Restrict searching to alphanumeric characters --- web-ui/app/templates/search/search_trigger.hbs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web-ui/app/templates/search/search_trigger.hbs b/web-ui/app/templates/search/search_trigger.hbs index 2261d154..376dd04c 100644 --- a/web-ui/app/templates/search/search_trigger.hbs +++ b/web-ui/app/templates/search/search_trigger.hbs @@ -1,3 +1,3 @@
- +
-- cgit v1.2.3 From d2d6fb98b909021efa435411ec95f554769fa9c9 Mon Sep 17 00:00:00 2001 From: Felix Hammerl Date: Thu, 3 Mar 2016 11:21:09 +0100 Subject: Issue #617: Allow only >=3 alphanumeric characters in search field --- web-ui/app/templates/search/search_trigger.hbs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web-ui/app/templates/search/search_trigger.hbs b/web-ui/app/templates/search/search_trigger.hbs index 376dd04c..f2c410a4 100644 --- a/web-ui/app/templates/search/search_trigger.hbs +++ b/web-ui/app/templates/search/search_trigger.hbs @@ -1,3 +1,3 @@
- +
-- cgit v1.2.3 From 23b175742f20d96e5b5d3d9cfcc0ed7067197f92 Mon Sep 17 00:00:00 2001 From: Felix Hammerl Date: Thu, 3 Mar 2016 12:25:25 +0100 Subject: Issue #617: Highlight search terms by altering mail content --- web-ui/app/js/helpers/sanitizer.js | 32 +++++++++++++++++----- web-ui/app/js/mail_view/ui/mail_view.js | 10 ++++++- web-ui/app/js/page/events.js | 2 ++ web-ui/app/js/search/results_highlighter.js | 29 ++++++++++++++++++++ web-ui/app/scss/sandbox.scss | 6 ++++ web-ui/test/spec/helpers/sanitizer.spec.js | 6 ++++ web-ui/test/spec/mail_view/ui/mail_view.spec.js | 6 ++++ .../test/spec/search/results_highlighter.spec.js | 14 ++++++++-- 8 files changed, 94 insertions(+), 11 deletions(-) diff --git a/web-ui/app/js/helpers/sanitizer.js b/web-ui/app/js/helpers/sanitizer.js index eea1f0f7..443e8602 100644 --- a/web-ui/app/js/helpers/sanitizer.js +++ b/web-ui/app/js/helpers/sanitizer.js @@ -23,6 +23,16 @@ define(['DOMPurify', 'he'], function (DOMPurify, he) { */ var sanitizer = {}; + sanitizer.whitelist = [{ + // highlight tag open + pre: '<em class="search-highlight">', + post: '' + }, { + // highlight tag close + pre: '</em>', + post: '' + }]; + /** * Adds html line breaks to a plaintext with line breaks (incl carriage return) * @@ -55,16 +65,24 @@ define(['DOMPurify', 'he'], function (DOMPurify, he) { }; /** - * Runs a given dirty body through he, thereby encoding everything - * as HTML entities. - * - * @param {string} dirtyBody The unsanitized string - * @return {string} Safe-to-display HTML string - */ + * Runs a given dirty body through he, thereby encoding everything + * as HTML entities. + * + * @param {string} dirtyBody The unsanitized string + * @return {string} Safe-to-display HTML string + */ sanitizer.purifyText = function (dirtyBody) { - return he.encode(dirtyBody, { + var escapedBody = he.encode(dirtyBody, { encodeEverything: true }); + + this.whitelist.forEach(function(entry) { + while (escapedBody.indexOf(entry.pre) > -1) { + escapedBody = escapedBody.replace(entry.pre, entry.post); + } + }); + + return escapedBody; }; /** diff --git a/web-ui/app/js/mail_view/ui/mail_view.js b/web-ui/app/js/mail_view/ui/mail_view.js index fbbba409..d952fed7 100644 --- a/web-ui/app/js/mail_view/ui/mail_view.js +++ b/web-ui/app/js/mail_view/ui/mail_view.js @@ -257,9 +257,17 @@ define( this.trigger(events.mail.want, {mail: this.attr.ident, caller: this}); }; + this.highlightMailContent = function (event, data) { + // we can't directly manipulate the iFrame to highlight the content + // so we need to take an indirection where we directly manipulate + // the mail content to accomodate the highlighting + this.trigger(document, events.mail.highlightMailContent, data); + }; + this.after('initialize', function () { - this.on(this, events.mail.here, this.displayMail); this.on(this, events.mail.notFound, this.openNoMessageSelectedPane); + this.on(this, events.mail.here, this.highlightMailContent); + this.on(document, events.mail.display, this.displayMail); this.on(document, events.dispatchers.rightPane.clear, this.teardown); this.on(document, events.mail.tags.updated, this.tagsUpdated); this.on(document, events.mail.deleted, this.mailDeleted); diff --git a/web-ui/app/js/page/events.js b/web-ui/app/js/page/events.js index 7a0dbf9d..ad15e76e 100644 --- a/web-ui/app/js/page/events.js +++ b/web-ui/app/js/page/events.js @@ -121,6 +121,8 @@ define(function () { mail: { here: 'mail:here', want: 'mail:want', + display: 'mail:display', + highlightMailContent: 'mail:highlightMailContent', send: 'mail:send', send_failed: 'mail:send_failed', sent: 'mail:sent', diff --git a/web-ui/app/js/search/results_highlighter.js b/web-ui/app/js/search/results_highlighter.js index 9e3ba167..831be0cd 100644 --- a/web-ui/app/js/search/results_highlighter.js +++ b/web-ui/app/js/search/results_highlighter.js @@ -40,6 +40,7 @@ define( var domIdent = data.where; if(this.attr.keywords) { _.each(this.attr.keywords, function (keyword) { + keyword = escapeRegExp(keyword); $(domIdent).highlightRegex(new RegExp(keyword, 'i'), { tagType: 'em', className: 'search-highlight' @@ -57,12 +58,40 @@ define( }); }; + this.highlightString = function (string) { + _.each(this.attr.keywords, function (keyword) { + keyword = escapeRegExp(keyword); + var regex = new RegExp('(' + keyword + ')', 'ig'); + string = string.replace(regex, '$1'); + }); + return string; + }; + + /* + * Alter data.mail.textPlainBody to highlight each of this.attr.keywords + * and pass it back to the mail_view when done + */ + this.highlightMailContent = function(ev, data){ + var mail = data.mail; + mail.textPlainBody = this.highlightString(mail.textPlainBody); + this.trigger(document, events.mail.display, data); + }; + + /* + * Escapes the special charaters used regular expressions that + * would cause problems with strings in the RegExp constructor + */ + function escapeRegExp(string){ + return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); + } + this.after('initialize', function () { this.on(document, events.search.perform, this.getKeywordsSearch); this.on(document, events.ui.tag.select, this.clearHighlights); this.on(document, events.search.resetHighlight, this.clearHighlights); this.on(document, events.search.highlightResults, this.highlightResults); + this.on(document, events.mail.highlightMailContent, this.highlightMailContent); }); } }); diff --git a/web-ui/app/scss/sandbox.scss b/web-ui/app/scss/sandbox.scss index e722753d..3cb4c441 100644 --- a/web-ui/app/scss/sandbox.scss +++ b/web-ui/app/scss/sandbox.scss @@ -1,3 +1,5 @@ +$search-highlight: #FFEF29; + body { font-family: "Open Sans", "Microsoft YaHei", "Hiragino Sans GB", "Hiragino Sans GB W3", "微软雅黑", "Helvetica Neue", Arial, sans-serif; font-size: 13px; @@ -12,3 +14,7 @@ body { box-sizing: border-box; word-wrap: break-word; } + +.search-highlight { + background-color: $search-highlight; +} diff --git a/web-ui/test/spec/helpers/sanitizer.spec.js b/web-ui/test/spec/helpers/sanitizer.spec.js index acd4b2b2..b553583e 100644 --- a/web-ui/test/spec/helpers/sanitizer.spec.js +++ b/web-ui/test/spec/helpers/sanitizer.spec.js @@ -25,6 +25,12 @@ define(['helpers/sanitizer'], function (sanitizer) { var output = sanitizer.purifyText('123asd'); expect(output).toEqual(expectedOutput); }); + + it('should leave highlighted text untouched', function () { + var expectedOutput = '123<a>asd</a>'; + var output = sanitizer.purifyText('123asd'); + expect(output).toEqual(expectedOutput); + }); }); describe('sanitizer.sanitize', function () { diff --git a/web-ui/test/spec/mail_view/ui/mail_view.spec.js b/web-ui/test/spec/mail_view/ui/mail_view.spec.js index 9ed56023..9f1114a7 100644 --- a/web-ui/test/spec/mail_view/ui/mail_view.spec.js +++ b/web-ui/test/spec/mail_view/ui/mail_view.spec.js @@ -21,6 +21,12 @@ describeComponent('mail_view/ui/mail_view', function () { expect(spyEvent.mostRecentCall.data.mail).toEqual(1); }); + it('triggers mail.highlightMailContent when receiving mail.here', function () { + var hightlightEvent = spyOnEvent(document,Pixelated.events.mail.highlightMailContent); + this.component.trigger(this.component, Pixelated.events.mail.here); + expect(hightlightEvent).toHaveBeenTriggeredOn(document); + }); + it('triggers dispatchers.rightPane.openNoMessageSelected when getting mail.notFound', function () { var openNoMessageSelectedEvent = spyOnEvent(document, Pixelated.events.dispatchers.rightPane.openNoMessageSelected); diff --git a/web-ui/test/spec/search/results_highlighter.spec.js b/web-ui/test/spec/search/results_highlighter.spec.js index cfb61e9c..13131a8e 100644 --- a/web-ui/test/spec/search/results_highlighter.spec.js +++ b/web-ui/test/spec/search/results_highlighter.spec.js @@ -1,9 +1,11 @@ describeComponent('search/results_highlighter', function () { 'use strict'; - it('highlights words or parts of words that match with the keywords given', function () { + beforeEach(function () { this.setupComponent('
Any one seeing too many open bugs
'); + }); + it('highlights words or parts of words that match with the keywords given', function () { this.component.attr = {keywords: ['any']}; this.component.highlightResults(event, {where: '#text'}); @@ -12,9 +14,15 @@ describeComponent('search/results_highlighter', function () { expect(highlightedWords).toEqual(2); }); - it('resets highlights when a new search is performed', function() { - this.setupComponent('
Any one seeing too many open bugs
'); + it('highlights a string with the keywords given', function () { + this.component.attr = {keywords: ['foo']}; + var expectedString = 'the foo bar'; + var string = this.component.highlightString('the foo bar'); + + expect(string).toEqual(expectedString); + }); + it('resets highlights when a new search is performed', function() { this.component.attr = {keywords: ['any']}; this.component.highlightResults(event, {where: '#text'}); $(document).trigger(Pixelated.events.search.resetHighlight); -- cgit v1.2.3 From d4822d8923c6e4535ee09eafb035f1b15742c637 Mon Sep 17 00:00:00 2001 From: Felix Hammerl Date: Mon, 7 Mar 2016 17:59:51 +0100 Subject: Issue #620: Spike growl CSS modularization --- web-ui/app/index.html | 5 +- web-ui/app/js/user_alerts/ui/user_alerts.js | 14 +- web-ui/app/scss/_alerts.scss | 23 - web-ui/app/scss/_colors.scss | 62 - web-ui/app/scss/_main.scss | 37 + web-ui/app/scss/_mixins.scss | 2 +- web-ui/app/scss/_others.scss | 7 + web-ui/app/scss/base/_colors.scss | 62 + web-ui/app/scss/base/_fonts.scss | 60 + web-ui/app/scss/base/_scaffolding.scss | 10 + web-ui/app/scss/foundation.scss | 2066 -------------------------- web-ui/app/scss/layout/_message-panel.scss | 9 + web-ui/app/scss/main.scss | 37 - web-ui/app/scss/opensans.scss | 60 - web-ui/app/scss/reset.scss | 421 ------ web-ui/app/scss/style.scss | 35 + web-ui/app/scss/vendor/_foundation.scss | 2066 ++++++++++++++++++++++++++ web-ui/app/scss/vendor/_reset.scss | 421 ++++++ web-ui/app/scss/views/_message-panel.scss | 26 + web-ui/app/templates/user_alerts/message.hbs | 2 +- 20 files changed, 2747 insertions(+), 2678 deletions(-) delete mode 100644 web-ui/app/scss/_alerts.scss delete mode 100644 web-ui/app/scss/_colors.scss create mode 100644 web-ui/app/scss/_main.scss create mode 100644 web-ui/app/scss/_others.scss create mode 100644 web-ui/app/scss/base/_colors.scss create mode 100644 web-ui/app/scss/base/_fonts.scss create mode 100644 web-ui/app/scss/base/_scaffolding.scss delete mode 100644 web-ui/app/scss/foundation.scss create mode 100644 web-ui/app/scss/layout/_message-panel.scss delete mode 100644 web-ui/app/scss/main.scss delete mode 100644 web-ui/app/scss/opensans.scss delete mode 100644 web-ui/app/scss/reset.scss create mode 100644 web-ui/app/scss/style.scss create mode 100644 web-ui/app/scss/vendor/_foundation.scss create mode 100644 web-ui/app/scss/vendor/_reset.scss create mode 100644 web-ui/app/scss/views/_message-panel.scss diff --git a/web-ui/app/index.html b/web-ui/app/index.html index 107e9102..4d6f3037 100644 --- a/web-ui/app/index.html +++ b/web-ui/app/index.html @@ -9,8 +9,7 @@ - - + @@ -56,7 +55,7 @@
-
+
diff --git a/web-ui/app/js/user_alerts/ui/user_alerts.js b/web-ui/app/js/user_alerts/ui/user_alerts.js index b02762aa..e944a7a5 100644 --- a/web-ui/app/js/user_alerts/ui/user_alerts.js +++ b/web-ui/app/js/user_alerts/ui/user_alerts.js @@ -32,20 +32,26 @@ define( dismissTimeout: 3000 }); - this.render = function (message) { + this.render = function(message) { this.$node.html(templates.userAlerts.message(message)); this.show(); setTimeout(this.hide.bind(this), this.attr.dismissTimeout); }; - this.displayMessage = function (ev, data) { - this.render({ message: {content: data.message, class: (data.class || 'success')}}); + this.displayMessage = function(ev, data) { + this.render({ + message: { + content: data.message, + class: 'message-panel__growl--' + (data.class || 'success') + } + }); }; - this.after('initialize', function () { + this.after('initialize', function() { this.on(document, events.ui.userAlerts.displayMessage, this.displayMessage); }); } } ); + diff --git a/web-ui/app/scss/_alerts.scss b/web-ui/app/scss/_alerts.scss deleted file mode 100644 index cfb31cbe..00000000 --- a/web-ui/app/scss/_alerts.scss +++ /dev/null @@ -1,23 +0,0 @@ -.message-panel { - width: 100%; - margin: 10px auto; - position: fixed; - z-index: 10000; - text-align: center; - span{ - padding: 5px 60px; - &.success { - background: $warning; - color: darken($warning, 50%); - border: 1px solid darken($warning, 10%); - @include box-shadow(1px 1px 3px darken($warning, 60%)); - } - &.error { - font-weight: bold; - color: white; - background: $error; - border: 1px solid darken($error, 10%); - @include box-shadow(1px 1px 3px darken($error, 60%)); - } - } -} diff --git a/web-ui/app/scss/_colors.scss b/web-ui/app/scss/_colors.scss deleted file mode 100644 index de5f76b3..00000000 --- a/web-ui/app/scss/_colors.scss +++ /dev/null @@ -1,62 +0,0 @@ -/* Pixelated Color Palette - don't change these! */ -$dark_slate_gray: #3E3A37; -$light_gray: #C2C2C2; -$lighter_blue: #91C2D1; -$light_blue: #3DABC4; -$dark_blue: #178CA6; -$light_orange: #FF9C00; -$dark_orange: #FF7902; - - -/* Side nav background color */ -$navigation_background: $dark_slate_gray; - -/* Action buttons and links */ -$action_buttons: $light_blue; - -/* Primary Highlight*/ -$primary_highlight: $light_orange; - -/* Logo color*/ -$logo_color: $light_orange; - -/* Unread count dialog bubble background color */ -$secondary_callout: darken($primary_highlight, 5); - -/* Grayscale */ -$contrast: #EEE; -$white: #FFF; -$dark_white: #FAFAFA; -$lighter_gray: #DDD; -$medium_light_grey: #999; -$medium_grey: #777; -$medium_dark_grey: #666; -$dark_grey: #333; -$black: #000; -$top_pane: $contrast; -$total_count_bg: #C0B9B9; - -$background_light_grey: #F5F5F5; -$border_light_grey: #D9D9D9; - -/* Feedback to Users */ -$warning: #F7E8AF; -$search-highlight: #FFEF29; - -/* Light gray indicator icons */ -$indicator_icon_color: $light_gray; - -$error: #D93C38; -$attention: #F6A41C; -$success: #50BA5B; - -$will_be_encrypted: $success; -$wont_be_encrypted: $attention; -$recipients_font_color: #AAA; - -/* Attachments */ -$attachment_text: #555; -$attachment_icon: lighten($attachment_text, 30); -$attachment_size: lighten($attachment_text, 30); -$attachment_area_background: #F5F5F5; -$attachment_area_border: #D9D9D9; diff --git a/web-ui/app/scss/_main.scss b/web-ui/app/scss/_main.scss new file mode 100644 index 00000000..b582a5d5 --- /dev/null +++ b/web-ui/app/scss/_main.scss @@ -0,0 +1,37 @@ +@import "compass/css3"; +@import "reset"; +@import "foundation"; +@import "colors"; +@import "mixins"; +@import "alerts"; +@import "read"; +@import "reply"; +@import "compose"; +@import "security"; +@import "mascot"; +@import "styles"; + +html { + height:100%; +} +body { + min-height:100%; + overflow: hidden; + background: $white; +} +header#main { + overflow: hidden; + position: fixed; + top: 0; + width: 100%; + position: relative; + margin-bottom: 0; +} + +.no-padding { + padding: 0; +} + +.text-right { + text-align: right; +} diff --git a/web-ui/app/scss/_mixins.scss b/web-ui/app/scss/_mixins.scss index 5bb84105..4583c55d 100644 --- a/web-ui/app/scss/_mixins.scss +++ b/web-ui/app/scss/_mixins.scss @@ -1,4 +1,4 @@ -@import 'colors'; +@import 'base/colors'; // SHARED MIXINS @mixin btn-transition { diff --git a/web-ui/app/scss/_others.scss b/web-ui/app/scss/_others.scss new file mode 100644 index 00000000..e73ed33d --- /dev/null +++ b/web-ui/app/scss/_others.scss @@ -0,0 +1,7 @@ +.no-padding { + padding: 0; +} + +.text-right { + text-align: right; +} diff --git a/web-ui/app/scss/base/_colors.scss b/web-ui/app/scss/base/_colors.scss new file mode 100644 index 00000000..de5f76b3 --- /dev/null +++ b/web-ui/app/scss/base/_colors.scss @@ -0,0 +1,62 @@ +/* Pixelated Color Palette - don't change these! */ +$dark_slate_gray: #3E3A37; +$light_gray: #C2C2C2; +$lighter_blue: #91C2D1; +$light_blue: #3DABC4; +$dark_blue: #178CA6; +$light_orange: #FF9C00; +$dark_orange: #FF7902; + + +/* Side nav background color */ +$navigation_background: $dark_slate_gray; + +/* Action buttons and links */ +$action_buttons: $light_blue; + +/* Primary Highlight*/ +$primary_highlight: $light_orange; + +/* Logo color*/ +$logo_color: $light_orange; + +/* Unread count dialog bubble background color */ +$secondary_callout: darken($primary_highlight, 5); + +/* Grayscale */ +$contrast: #EEE; +$white: #FFF; +$dark_white: #FAFAFA; +$lighter_gray: #DDD; +$medium_light_grey: #999; +$medium_grey: #777; +$medium_dark_grey: #666; +$dark_grey: #333; +$black: #000; +$top_pane: $contrast; +$total_count_bg: #C0B9B9; + +$background_light_grey: #F5F5F5; +$border_light_grey: #D9D9D9; + +/* Feedback to Users */ +$warning: #F7E8AF; +$search-highlight: #FFEF29; + +/* Light gray indicator icons */ +$indicator_icon_color: $light_gray; + +$error: #D93C38; +$attention: #F6A41C; +$success: #50BA5B; + +$will_be_encrypted: $success; +$wont_be_encrypted: $attention; +$recipients_font_color: #AAA; + +/* Attachments */ +$attachment_text: #555; +$attachment_icon: lighten($attachment_text, 30); +$attachment_size: lighten($attachment_text, 30); +$attachment_area_background: #F5F5F5; +$attachment_area_border: #D9D9D9; diff --git a/web-ui/app/scss/base/_fonts.scss b/web-ui/app/scss/base/_fonts.scss new file mode 100644 index 00000000..ada6a025 --- /dev/null +++ b/web-ui/app/scss/base/_fonts.scss @@ -0,0 +1,60 @@ +@font-face { + font-family: 'Open Sans'; + font-style: normal; + font-weight: 300; + src: local('Open Sans Light'), local('OpenSans-Light'), url('/assets/fonts/OpenSans-Light.woff') format('woff'); +} +@font-face { + font-family: 'Open Sans'; + font-style: normal; + font-weight: 400; + src: local('Open Sans'), local('OpenSans'), url('/assets/fonts/OpenSans.woff') format('woff'); +} +@font-face { + font-family: 'Open Sans'; + font-style: normal; + font-weight: 600; + src: local('Open Sans Semibold'), local('OpenSans-Semibold'), url('/assets/fonts/OpenSans-Semibold.woff') format('woff'); +} +@font-face { + font-family: 'Open Sans'; + font-style: normal; + font-weight: 700; + src: local('Open Sans Bold'), local('OpenSans-Bold'), url('/assets/fonts/OpenSans-Bold.woff') format('woff'); +} +@font-face { + font-family: 'Open Sans'; + font-style: normal; + font-weight: 800; + src: local('Open Sans Extrabold'), local('OpenSans-Extrabold'), url('/assets/fonts/OpenSans-Extrabold.woff') format('woff'); +} +@font-face { + font-family: 'Open Sans'; + font-style: italic; + font-weight: 300; + src: local('Open Sans Light Italic'), local('OpenSansLight-Italic'), url('/assets/fonts/OpenSansLight-Italic.woff') format('woff'); +} +@font-face { + font-family: 'Open Sans'; + font-style: italic; + font-weight: 400; + src: local('Open Sans Italic'), local('OpenSans-Italic'), url('/assets/fonts/OpenSans-Italic.woff') format('woff'); +} +@font-face { + font-family: 'Open Sans'; + font-style: italic; + font-weight: 600; + src: local('Open Sans Semibold Italic'), local('OpenSans-SemiboldItalic'), url('/assets/fonts/OpenSans-SemiboldItalic.woff') format('woff'); +} +@font-face { + font-family: 'Open Sans'; + font-style: italic; + font-weight: 700; + src: local('Open Sans Bold Italic'), local('OpenSans-BoldItalic'), url('/assets/fonts/OpenSans-BoldItalic.woff') format('woff'); +} +@font-face { + font-family: 'Open Sans'; + font-style: italic; + font-weight: 800; + src: local('Open Sans Extrabold Italic'), local('OpenSans-ExtraboldItalic'), url('/assets/fonts/OpenSans-ExtraboldItalic.woff') format('woff'); +} diff --git a/web-ui/app/scss/base/_scaffolding.scss b/web-ui/app/scss/base/_scaffolding.scss new file mode 100644 index 00000000..b8b5fa3b --- /dev/null +++ b/web-ui/app/scss/base/_scaffolding.scss @@ -0,0 +1,10 @@ +html { + height: 100% ; +} + +body { + min-height: 100% ; + overflow: hidden; + background: $white; +} + diff --git a/web-ui/app/scss/foundation.scss b/web-ui/app/scss/foundation.scss deleted file mode 100644 index 7918cf26..00000000 --- a/web-ui/app/scss/foundation.scss +++ /dev/null @@ -1,2066 +0,0 @@ -@import 'compass/css3'; - -meta { - &.foundation-version { - font-family: "/5.2.3/"; - } - &.foundation-mq-small { - font-family: "/only screen/"; - width: 0em; - } - &.foundation-mq-medium { - font-family: "/only screen and (min-width:40.063em)/"; - width: 40.063em; - } - &.foundation-mq-large { - font-family: "/only screen and (min-width:64.063em)/"; - width: 64.063em; - } - &.foundation-mq-xlarge { - font-family: "/only screen and (min-width:90.063em)/"; - width: 90.063em; - } - &.foundation-mq-xxlarge { - font-family: "/only screen and (min-width:120.063em)/"; - width: 120.063em; - } - &.foundation-data-attribute-namespace { - font-family: false; - } -} - -html, body { - height: 100%; -} - -* { - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; - &:before, &:after { - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; - } -} - -html { - font-size: 100%; -} - -body { - font-family: "Open Sans", "Microsoft YaHei", "Hiragino Sans GB", "Hiragino Sans GB W3", "微软雅黑", "Helvetica Neue", Arial, sans-serif; - font-size: 13px; - line-height: 1.2em; - background: white; - color: #333; - padding: 0; - margin: 0; - font-weight: normal; - -webkit-font-smoothing: antialiased; - font-style: normal; - position: relative; - cursor: default; -} - -a:hover { - cursor: pointer; -} - -img { - max-width: 100%; - height: auto; - -ms-interpolation-mode: bicubic; -} - -#map_canvas { - img, embed, object { - max-width: none !important; - } -} - -.map_canvas { - img, embed, object { - max-width: none !important; - } -} - -.left { - float: left !important; -} - -.right { - float: right !important; -} - -.clearfix { - &:before { - content: " "; - display: table; - } - &:after { - content: " "; - display: table; - clear: both; - } -} - -.hide { - display: none; -} - -.antialiased { - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} - -img { - display: inline-block; - vertical-align: middle; -} - -textarea { - height: auto; - min-height: 50px; - &:focus { - outline: none; - } -} - -select { - width: 100%; -} - -.row { - width: 100%; - margin-left: auto; - margin-right: auto; - margin-top: 0; - margin-bottom: 0; - &:before { - content: " "; - display: table; - } - &:after { - content: " "; - display: table; - clear: both; - } - &.collapse { - > { - .column, .columns { - padding-left: 0; - padding-right: 0; - } - } - .row { - margin-left: 0; - margin-right: 0; - } - } - .row { - width: auto; - margin-left: -0.9375em; - margin-right: -0.9375em; - margin-top: 0; - margin-bottom: 0; - max-width: none; - &:before { - content: " "; - display: table; - } - &:after { - content: " "; - display: table; - clear: both; - } - &.collapse { - width: auto; - margin: 0; - max-width: none; - &:before { - content: " "; - display: table; - } - &:after { - content: " "; - display: table; - clear: both; - } - } - } -} - -.column, .columns { - padding-left: 0.9375em; - padding-right: 0.9375em; - width: 100%; - float: left; -} - -@media only screen { - .small-push-0 { - position: relative; - left: 0%; - right: auto; - } - .small-pull-0 { - position: relative; - right: 0%; - left: auto; - } - .small-push-1 { - position: relative; - left: 8.33333%; - right: auto; - } - .small-pull-1 { - position: relative; - right: 8.33333%; - left: auto; - } - .small-push-2 { - position: relative; - left: 16.66667%; - right: auto; - } - .small-pull-2 { - position: relative; - right: 16.66667%; - left: auto; - } - .small-push-3 { - position: relative; - left: 25%; - right: auto; - } - .small-pull-3 { - position: relative; - right: 25%; - left: auto; - } - .small-push-4 { - position: relative; - left: 33.33333%; - right: auto; - } - .small-pull-4 { - position: relative; - right: 33.33333%; - left: auto; - } - .small-push-5 { - position: relative; - left: 41.66667%; - right: auto; - } - .small-pull-5 { - position: relative; - right: 41.66667%; - left: auto; - } - .small-push-6 { - position: relative; - left: 50%; - right: auto; - } - .small-pull-6 { - position: relative; - right: 50%; - left: auto; - } - .small-push-7 { - position: relative; - left: 58.33333%; - right: auto; - } - .small-pull-7 { - position: relative; - right: 58.33333%; - left: auto; - } - .small-push-8 { - position: relative; - left: 66.66667%; - right: auto; - } - .small-pull-8 { - position: relative; - right: 66.66667%; - left: auto; - } - .small-push-9 { - position: relative; - left: 75%; - right: auto; - } - .small-pull-9 { - position: relative; - right: 75%; - left: auto; - } - .small-push-10 { - position: relative; - left: 83.33333%; - right: auto; - } - .small-pull-10 { - position: relative; - right: 83.33333%; - left: auto; - } - .small-push-11 { - position: relative; - left: 91.66667%; - right: auto; - } - .small-pull-11 { - position: relative; - right: 91.66667%; - left: auto; - } - .column, .columns { - position: relative; - padding-left: 0.9375em; - padding-right: 0.9375em; - float: left; - } - .small-1 { - width: 8.33333%; - } - .small-2 { - width: 16.66667%; - } - .small-3 { - width: 25%; - } - .small-4 { - width: 33.33333%; - } - .small-5 { - width: 41.66667%; - } - .small-6 { - width: 50%; - } - .small-7 { - width: 58.33333%; - } - .small-8 { - width: 66.66667%; - } - .small-9 { - width: 75%; - } - .small-10 { - width: 83.33333%; - } - .small-11 { - width: 91.66667%; - } - .small-12 { - width: 100%; - } - [class*="column"] + [class*="column"] { - &:last-child { - float: right; - } - &.end { - float: left; - } - } - .small-offset-0 { - margin-left: 0% !important; - } - .small-offset-1 { - margin-left: 8.33333% !important; - } - .small-offset-2 { - margin-left: 16.66667% !important; - } - .small-offset-3 { - margin-left: 25% !important; - } - .small-offset-4 { - margin-left: 33.33333% !important; - } - .small-offset-5 { - margin-left: 41.66667% !important; - } - .small-offset-6 { - margin-left: 50% !important; - } - .small-offset-7 { - margin-left: 58.33333% !important; - } - .small-offset-8 { - margin-left: 66.66667% !important; - } - .small-offset-9 { - margin-left: 75% !important; - } - .small-offset-10 { - margin-left: 83.33333% !important; - } - .small-offset-11 { - margin-left: 91.66667% !important; - } - .small-reset-order { - margin-left: 0; - margin-right: 0; - left: auto; - right: auto; - float: left; - } - .column.small-centered, .columns.small-centered { - margin-left: auto; - margin-right: auto; - float: none !important; - } - .column.small-uncentered, .columns.small-uncentered { - margin-left: 0; - margin-right: 0; - float: left !important; - } - .column.small-uncentered.opposite, .columns.small-uncentered.opposite { - float: right; - } -} - -@media only screen and (min-width: 40.063em) { - .medium-push-0 { - position: relative; - left: 0%; - right: auto; - } - .medium-pull-0 { - position: relative; - right: 0%; - left: auto; - } - .medium-push-1 { - position: relative; - left: 8.33333%; - right: auto; - } - .medium-pull-1 { - position: relative; - right: 8.33333%; - left: auto; - } - .medium-push-2 { - position: relative; - left: 16.66667%; - right: auto; - } - .medium-pull-2 { - position: relative; - right: 16.66667%; - left: auto; - } - .medium-push-3 { - position: relative; - left: 25%; - right: auto; - } - .medium-pull-3 { - position: relative; - right: 25%; - left: auto; - } - .medium-push-4 { - position: relative; - left: 33.33333%; - right: auto; - } - .medium-pull-4 { - position: relative; - right: 33.33333%; - left: auto; - } - .medium-push-5 { - position: relative; - left: 41.66667%; - right: auto; - } - .medium-pull-5 { - position: relative; - right: 41.66667%; - left: auto; - } - .medium-push-6 { - position: relative; - left: 50%; - right: auto; - } - .medium-pull-6 { - position: relative; - right: 50%; - left: auto; - } - .medium-push-7 { - position: relative; - left: 58.33333%; - right: auto; - } - .medium-pull-7 { - position: relative; - right: 58.33333%; - left: auto; - } - .medium-push-8 { - position: relative; - left: 66.66667%; - right: auto; - } - .medium-pull-8 { - position: relative; - right: 66.66667%; - left: auto; - } - .medium-push-9 { - position: relative; - left: 75%; - right: auto; - } - .medium-pull-9 { - position: relative; - right: 75%; - left: auto; - } - .medium-push-10 { - position: relative; - left: 83.33333%; - right: auto; - } - .medium-pull-10 { - position: relative; - right: 83.33333%; - left: auto; - } - .medium-push-11 { - position: relative; - left: 91.66667%; - right: auto; - } - .medium-pull-11 { - position: relative; - right: 91.66667%; - left: auto; - } - .column, .columns { - position: relative; - padding-left: 0.9375em; - padding-right: 0.9375em; - float: left; - } - .medium-1 { - width: 8.33333%; - } - .medium-2 { - width: 16.66667%; - } - .medium-3 { - width: 25%; - } - .medium-4 { - width: 33.33333%; - } - .medium-5 { - width: 41.66667%; - } - .medium-6 { - width: 50%; - } - .medium-7 { - width: 58.33333%; - } - .medium-8 { - width: 66.66667%; - } - .medium-9 { - width: 75%; - } - .medium-10 { - width: 83.33333%; - } - .medium-11 { - width: 91.66667%; - } - .medium-12 { - width: 100%; - } - [class*="column"] + [class*="column"] { - &:last-child { - float: right; - } - &.end { - float: left; - } - } - .medium-offset-0 { - margin-left: 0% !important; - } - .medium-offset-1 { - margin-left: 8.33333% !important; - } - .medium-offset-2 { - margin-left: 16.66667% !important; - } - .medium-offset-3 { - margin-left: 25% !important; - } - .medium-offset-4 { - margin-left: 33.33333% !important; - } - .medium-offset-5 { - margin-left: 41.66667% !important; - } - .medium-offset-6 { - margin-left: 50% !important; - } - .medium-offset-7 { - margin-left: 58.33333% !important; - } - .medium-offset-8 { - margin-left: 66.66667% !important; - } - .medium-offset-9 { - margin-left: 75% !important; - } - .medium-offset-10 { - margin-left: 83.33333% !important; - } - .medium-offset-11 { - margin-left: 91.66667% !important; - } - .medium-reset-order { - margin-left: 0; - margin-right: 0; - left: auto; - right: auto; - float: left; - } - .column.medium-centered, .columns.medium-centered { - margin-left: auto; - margin-right: auto; - float: none !important; - } - .column.medium-uncentered, .columns.medium-uncentered { - margin-left: 0; - margin-right: 0; - float: left !important; - } - .column.medium-uncentered.opposite, .columns.medium-uncentered.opposite { - float: right; - } - .push-0 { - position: relative; - left: 0%; - right: auto; - } - .pull-0 { - position: relative; - right: 0%; - left: auto; - } - .push-1 { - position: relative; - left: 8.33333%; - right: auto; - } - .pull-1 { - position: relative; - right: 8.33333%; - left: auto; - } - .push-2 { - position: relative; - left: 16.66667%; - right: auto; - } - .pull-2 { - position: relative; - right: 16.66667%; - left: auto; - } - .push-3 { - position: relative; - left: 25%; - right: auto; - } - .pull-3 { - position: relative; - right: 25%; - left: auto; - } - .push-4 { - position: relative; - left: 33.33333%; - right: auto; - } - .pull-4 { - position: relative; - right: 33.33333%; - left: auto; - } - .push-5 { - position: relative; - left: 41.66667%; - right: auto; - } - .pull-5 { - position: relative; - right: 41.66667%; - left: auto; - } - .push-6 { - position: relative; - left: 50%; - right: auto; - } - .pull-6 { - position: relative; - right: 50%; - left: auto; - } - .push-7 { - position: relative; - left: 58.33333%; - right: auto; - } - .pull-7 { - position: relative; - right: 58.33333%; - left: auto; - } - .push-8 { - position: relative; - left: 66.66667%; - right: auto; - } - .pull-8 { - position: relative; - right: 66.66667%; - left: auto; - } - .push-9 { - position: relative; - left: 75%; - right: auto; - } - .pull-9 { - position: relative; - right: 75%; - left: auto; - } - .push-10 { - position: relative; - left: 83.33333%; - right: auto; - } - .pull-10 { - position: relative; - right: 83.33333%; - left: auto; - } - .push-11 { - position: relative; - left: 91.66667%; - right: auto; - } - .pull-11 { - position: relative; - right: 91.66667%; - left: auto; - } -} - -@media only screen and (min-width: 64.063em) { - .large-push-0 { - position: relative; - left: 0%; - right: auto; - } - .large-pull-0 { - position: relative; - right: 0%; - left: auto; - } - .large-push-1 { - position: relative; - left: 8.33333%; - right: auto; - } - .large-pull-1 { - position: relative; - right: 8.33333%; - left: auto; - } - .large-push-2 { - position: relative; - left: 16.66667%; - right: auto; - } - .large-pull-2 { - position: relative; - right: 16.66667%; - left: auto; - } - .large-push-3 { - position: relative; - left: 25%; - right: auto; - } - .large-pull-3 { - position: relative; - right: 25%; - left: auto; - } - .large-push-4 { - position: relative; - left: 33.33333%; - right: auto; - } - .large-pull-4 { - position: relative; - right: 33.33333%; - left: auto; - } - .large-push-5 { - position: relative; - left: 41.66667%; - right: auto; - } - .large-pull-5 { - position: relative; - right: 41.66667%; - left: auto; - } - .large-push-6 { - position: relative; - left: 50%; - right: auto; - } - .large-pull-6 { - position: relative; - right: 50%; - left: auto; - } - .large-push-7 { - position: relative; - left: 58.33333%; - right: auto; - } - .large-pull-7 { - position: relative; - right: 58.33333%; - left: auto; - } - .large-push-8 { - position: relative; - left: 66.66667%; - right: auto; - } - .large-pull-8 { - position: relative; - right: 66.66667%; - left: auto; - } - .large-push-9 { - position: relative; - left: 75%; - right: auto; - } - .large-pull-9 { - position: relative; - right: 75%; - left: auto; - } - .large-push-10 { - position: relative; - left: 83.33333%; - right: auto; - } - .large-pull-10 { - position: relative; - right: 83.33333%; - left: auto; - } - .large-push-11 { - position: relative; - left: 91.66667%; - right: auto; - } - .large-pull-11 { - position: relative; - right: 91.66667%; - left: auto; - } - .column, .columns { - position: relative; - padding-left: 0.9375em; - padding-right: 0.9375em; - float: left; - } - .large-1 { - width: 8.33333%; - } - .large-2 { - width: 16.66667%; - } - .large-3 { - width: 25%; - } - .large-4 { - width: 33.33333%; - } - .large-5 { - width: 41.66667%; - } - .large-6 { - width: 50%; - } - .large-7 { - width: 58.33333%; - } - .large-8 { - width: 66.66667%; - } - .large-9 { - width: 75%; - } - .large-10 { - width: 83.33333%; - } - .large-11 { - width: 91.66667%; - } - .large-12 { - width: 100%; - } - [class*="column"] + [class*="column"] { - &:last-child { - float: right; - } - &.end { - float: left; - } - } - .large-offset-0 { - margin-left: 0% !important; - } - .large-offset-1 { - margin-left: 8.33333% !important; - } - .large-offset-2 { - margin-left: 16.66667% !important; - } - .large-offset-3 { - margin-left: 25% !important; - } - .large-offset-4 { - margin-left: 33.33333% !important; - } - .large-offset-5 { - margin-left: 41.66667% !important; - } - .large-offset-6 { - margin-left: 50% !important; - } - .large-offset-7 { - margin-left: 58.33333% !important; - } - .large-offset-8 { - margin-left: 66.66667% !important; - } - .large-offset-9 { - margin-left: 75% !important; - } - .large-offset-10 { - margin-left: 83.33333% !important; - } - .large-offset-11 { - margin-left: 91.66667% !important; - } - .large-reset-order { - margin-left: 0; - margin-right: 0; - left: auto; - right: auto; - float: left; - } - .column.large-centered, .columns.large-centered { - margin-left: auto; - margin-right: auto; - float: none !important; - } - .column.large-uncentered, .columns.large-uncentered { - margin-left: 0; - margin-right: 0; - float: left !important; - } - .column.large-uncentered.opposite, .columns.large-uncentered.opposite { - float: right; - } - .push-0 { - position: relative; - left: 0%; - right: auto; - } - .pull-0 { - position: relative; - right: 0%; - left: auto; - } - .push-1 { - position: relative; - left: 8.33333%; - right: auto; - } - .pull-1 { - position: relative; - right: 8.33333%; - left: auto; - } - .push-2 { - position: relative; - left: 16.66667%; - right: auto; - } - .pull-2 { - position: relative; - right: 16.66667%; - left: auto; - } - .push-3 { - position: relative; - left: 25%; - right: auto; - } - .pull-3 { - position: relative; - right: 25%; - left: auto; - } - .push-4 { - position: relative; - left: 33.33333%; - right: auto; - } - .pull-4 { - position: relative; - right: 33.33333%; - left: auto; - } - .push-5 { - position: relative; - left: 41.66667%; - right: auto; - } - .pull-5 { - position: relative; - right: 41.66667%; - left: auto; - } - .push-6 { - position: relative; - left: 50%; - right: auto; - } - .pull-6 { - position: relative; - right: 50%; - left: auto; - } - .push-7 { - position: relative; - left: 58.33333%; - right: auto; - } - .pull-7 { - position: relative; - right: 58.33333%; - left: auto; - } - .push-8 { - position: relative; - left: 66.66667%; - right: auto; - } - .pull-8 { - position: relative; - right: 66.66667%; - left: auto; - } - .push-9 { - position: relative; - left: 75%; - right: auto; - } - .pull-9 { - position: relative; - right: 75%; - left: auto; - } - .push-10 { - position: relative; - left: 83.33333%; - right: auto; - } - .pull-10 { - position: relative; - right: 83.33333%; - left: auto; - } - .push-11 { - position: relative; - left: 91.66667%; - right: auto; - } - .pull-11 { - position: relative; - right: 91.66667%; - left: auto; - } -} - -.inline-list { - margin: 0 auto 1.0625rem auto; - margin-left: -1.375rem; - margin-right: 0; - padding: 0; - list-style: none; - overflow: hidden; - > li { - list-style: none; - float: left; - margin-left: 1.375rem; - display: block; - > * { - display: block; - } - } -} - -.text-left { - text-align: left !important; -} - -.text-right { - text-align: right !important; -} - -.text-center { - text-align: center !important; -} - -.text-justify { - text-align: justify !important; -} - -@media only screen and (max-width: 40em) { - .small-only-text-left { - text-align: left !important; - } - .small-only-text-right { - text-align: right !important; - } - .small-only-text-center { - text-align: center !important; - } - .small-only-text-justify { - text-align: justify !important; - } -} - -@media only screen { - .small-text-left { - text-align: left !important; - } - .small-text-right { - text-align: right !important; - } - .small-text-center { - text-align: center !important; - } - .small-text-justify { - text-align: justify !important; - } -} - -@media only screen and (min-width: 40.063em) and (max-width: 64em) { - .medium-only-text-left { - text-align: left !important; - } - .medium-only-text-right { - text-align: right !important; - } - .medium-only-text-center { - text-align: center !important; - } - .medium-only-text-justify { - text-align: justify !important; - } -} - -@media only screen and (min-width: 40.063em) { - .medium-text-left { - text-align: left !important; - } - .medium-text-right { - text-align: right !important; - } - .medium-text-center { - text-align: center !important; - } - .medium-text-justify { - text-align: justify !important; - } -} - -@media only screen and (min-width: 64.063em) and (max-width: 90em) { - .large-only-text-left { - text-align: left !important; - } - .large-only-text-right { - text-align: right !important; - } - .large-only-text-center { - text-align: center !important; - } - .large-only-text-justify { - text-align: justify !important; - } -} - -@media only screen and (min-width: 64.063em) { - .large-text-left { - text-align: left !important; - } - .large-text-right { - text-align: right !important; - } - .large-text-center { - text-align: center !important; - } - .large-text-justify { - text-align: justify !important; - } -} - -@media only screen and (min-width: 90.063em) and (max-width: 120em) { - .xlarge-only-text-left { - text-align: left !important; - } - .xlarge-only-text-right { - text-align: right !important; - } - .xlarge-only-text-center { - text-align: center !important; - } - .xlarge-only-text-justify { - text-align: justify !important; - } -} - -@media only screen and (min-width: 90.063em) { - .xlarge-text-left { - text-align: left !important; - } - .xlarge-text-right { - text-align: right !important; - } - .xlarge-text-center { - text-align: center !important; - } - .xlarge-text-justify { - text-align: justify !important; - } -} - -@media only screen and (min-width: 120.063em) and (max-width: 99999999em) { - .xxlarge-only-text-left { - text-align: left !important; - } - .xxlarge-only-text-right { - text-align: right !important; - } - .xxlarge-only-text-center { - text-align: center !important; - } - .xxlarge-only-text-justify { - text-align: justify !important; - } -} - -@media only screen and (min-width: 120.063em) { - .xxlarge-text-left { - text-align: left !important; - } - .xxlarge-text-right { - text-align: right !important; - } - .xxlarge-text-center { - text-align: center !important; - } - .xxlarge-text-justify { - text-align: justify !important; - } -} - -/* Typography resets */ - -div, dl, dt, dd, ul, ol, li, h1, h2, h3, h4, h5, h6, pre, form, p, blockquote, th, td { - margin: 0; - padding: 0; -} - -/* Default Link Styles */ - -a { - color: #2ba6cb; - text-decoration: none; - line-height: inherit; - &:hover, &:focus { - color: #258faf; - outline: none; - } - img { - border: none; - } -} - -/* Default paragraph styles */ - -p { - font-family: inherit; - font-weight: normal; - font-size: 0.9rem; - line-height: 1.4; - margin-bottom: 1.25rem; - text-rendering: optimizeLegibility; - &.lead { - font-size: 1.21875rem; - line-height: 1.4; - } - aside { - font-size: 0.875rem; - line-height: 1.35; - font-style: italic; - } -} - -/* Default header styles */ - -h1, h2, h3, h4, h5, h6 { - font-weight: normal; - font-style: normal; - color: #222; - text-rendering: optimizeLegibility; - margin-top: 0.2rem; - margin-bottom: 0.5rem; - line-height: 1.2; -} - -h1 small, h2 small, h3 small, h4 small, h5 small, h6 small { - font-size: 60%; - color: #6f6f6f; - line-height: 0; -} - -h1 { - font-size: 2.125rem; -} - -h2 { - font-size: 1.6875rem; -} - -h3 { - font-size: 1.375rem; -} - -h4, h5 { - font-size: 1.125rem; -} - -h6 { - font-size: 1rem; -} - -.subheader { - line-height: 1.4; - color: #6f6f6f; - font-weight: normal; - margin-top: 0.2rem; - margin-bottom: 0.5rem; -} - -hr { - border: solid #dddddd; - border-width: 1px 0 0; - clear: both; - margin: 1.25rem 0 1.1875rem; - height: 0; -} - -/* Helpful Typography Defaults */ - -em, i { - font-style: italic; - line-height: inherit; -} - -strong, b { - font-weight: bold; - line-height: inherit; -} - -small { - font-size: 60%; - line-height: inherit; -} - -code { - font-family: Consolas, "Liberation Mono", Courier, monospace; - font-weight: bold; - color: #910b0e; -} - -/* Lists */ - -ul, ol, dl { - font-size: 0.9rem; - line-height: 1.6; - margin-bottom: 1.25rem; - list-style-position: outside; - font-family: inherit; -} - -ul { - margin-left: 0; - &.bullets { - margin-left: 1.1rem; - li { - margin-left: 1.25rem; - margin-bottom: 0; - list-style: circle; - } - } - li { - margin-bottom: 0; - list-style: none; - } -} - -/* Abbreviations */ - -abbr, acronym { - text-transform: uppercase; - font-size: 90%; - color: #222222; - border-bottom: 1px dotted #dddddd; - cursor: help; -} - -abbr { - text-transform: none; -} - -/* Blockquotes */ - -blockquote { - margin: 0 0 1.25rem; - padding: 0.5625rem 1.25rem 0 1.1875rem; - border-left: 1px solid #dddddd; - cite { - display: block; - font-size: 0.8125rem; - color: #555555; - &:before { - content: "\2014 \0020"; - } - a { - color: #555555; - &:visited { - color: #555555; - } - } - } - line-height: 1.6; - color: #6f6f6f; - p { - line-height: 1.6; - color: #6f6f6f; - } -} - -/* Microformats */ - -.vcard { - display: inline-block; - margin: 0 0 1.25rem 0; - border: 1px solid #dddddd; - padding: 0.625rem 0.75rem; - li { - margin: 0; - display: block; - } - .fn { - font-weight: bold; - font-size: 0.9375rem; - } -} - -.vevent { - .summary { - font-weight: bold; - } - abbr { - cursor: default; - text-decoration: none; - font-weight: bold; - border: none; - padding: 0 0.0625rem; - } -} - -@media only screen and (min-width: 40.063em) { - h1, h2, h3, h4, h5, h6 { - line-height: 1.2; - } - h1 { - font-size: 2.55rem; - } - h2 { - font-size: 2.3125rem; - } - h3 { - font-size: 1.4875rem; - } - h4 { - font-size: 1.1375rem; - } -} - -/* - * Print styles. - * - * Inlined to avoid required HTTP connection: www.phpied.com/delay-loading-your-print-css/ - * Credit to Paul Irish and HTML5 Boilerplate (html5boilerplate.com) -*/ - -.print-only { - display: none !important; -} - -@media print { - * { - background: transparent !important; - color: black !important; - /* Black prints faster: h5bp.com/s */ - box-shadow: none !important; - text-shadow: none !important; - } - a { - text-decoration: underline; - &:visited { - text-decoration: underline; - } - &[href]:after { - content: " (" attr(href) ")"; - } - } - abbr[title]:after { - content: " (" attr(title) ")"; - } - .ir a:after { - content: ""; - } - a { - &[href^="javascript:"]:after, &[href^="#"]:after { - content: ""; - } - } - pre, blockquote { - border: 1px solid #999999; - page-break-inside: avoid; - } - thead { - display: table-header-group; - /* h5bp.com/t */ - } - tr { - page-break-inside: avoid; - } - img { - page-break-inside: avoid; - max-width: 100% !important; - } - @page { - margin: 0.5cm; - } - - p, h2, h3 { - orphans: 3; - widows: 3; - } - h2, h3 { - page-break-after: avoid; - } - .hide-on-print { - display: none !important; - } - .print-only { - display: block !important; - } - .hide-for-print { - display: none !important; - } - .show-for-print { - display: inherit !important; - } -} - -.reveal-modal-bg { - position: fixed; - height: 100%; - width: 100%; - background: black; - background: rgba(0, 0, 0, 0.45); - z-index: 99; - display: none; - top: 0; - left: 0; -} - -dialog, .reveal-modal { - visibility: hidden; - display: none; - position: absolute; - z-index: 100; - width: 100vw; - top: 0; - left: 0; - background-color: white; - padding: 1.25rem; - border: solid 1px #666666; - box-shadow: 0 0 10px rgba(0, 0, 0, 0.4); -} - -@media only screen and (max-width: 40em) { - dialog, .reveal-modal { - min-height: 100vh; - } -} - -@media only screen and (min-width: 40.063em) { - dialog, .reveal-modal { - left: 50%; - } -} - -dialog { - .column, .columns { - min-width: 0; - } -} - -.reveal-modal { - .column, .columns { - min-width: 0; - } -} - -dialog > :first-child, .reveal-modal > :first-child { - margin-top: 0; -} - -dialog > :last-child, .reveal-modal > :last-child { - margin-bottom: 0; -} - -@media only screen and (min-width: 40.063em) { - dialog, .reveal-modal { - margin-left: -26%; - width: 50%; - } -} - -@media only screen and (min-width: 40.063em) { - dialog, .reveal-modal { - top: 6.25rem; - } -} - -dialog .close-reveal-modal, .reveal-modal .close-reveal-modal { - font-size: 2.5rem; - line-height: 1; - position: absolute; - top: 0.5rem; - right: 0.6875rem; - color: #aaaaaa; - font-weight: bold; - cursor: pointer; -} - -dialog[open] { - display: block; - visibility: visible; -} - -@media only screen and (min-width: 40.063em) { - dialog, .reveal-modal { - padding: 1.875rem; - } - dialog.radius, .reveal-modal.radius { - border-radius: 3px; - } - dialog.round, .reveal-modal.round { - border-radius: 1000px; - } - dialog.collapse, .reveal-modal.collapse { - padding: 0; - } - dialog.full, .reveal-modal.full { - top: 0; - left: 0; - height: 100vh; - min-height: 100vh; - margin-left: 0 !important; - } -} - -@media only screen and (min-width: 40.063em) and (min-width: 40.063em) { - dialog.tiny, .reveal-modal.tiny { - margin-left: -15%; - width: 30%; - } -} - -@media only screen and (min-width: 40.063em) and (min-width: 40.063em) { - dialog.small, .reveal-modal.small { - margin-left: -20%; - width: 40%; - } -} - -@media only screen and (min-width: 40.063em) and (min-width: 40.063em) { - dialog.medium, .reveal-modal.medium { - margin-left: -30%; - width: 60%; - } -} - -@media only screen and (min-width: 40.063em) and (min-width: 40.063em) { - dialog.large, .reveal-modal.large { - margin-left: -35%; - width: 70%; - } -} - -@media only screen and (min-width: 40.063em) and (min-width: 40.063em) { - dialog.xlarge, .reveal-modal.xlarge { - margin-left: -47.5%; - width: 95%; - } -} - -@media only screen and (min-width: 40.063em) and (min-width: 40.063em) { - dialog.full, .reveal-modal.full { - margin-left: -50vw; - width: 100vw; - } -} - -@media print { - dialog, .reveal-modal { - background: white !important; - } -} - -.label { - font-weight: normal; - text-align: center; - text-decoration: none; - line-height: 1; - white-space: nowrap; - display: inline-block; - position: relative; - margin-bottom: inherit; - padding: 0.25rem 0.5rem 0.375rem; - font-size: 0.6875rem; - background-color: #2ba6cb; - color: white; - &.radius { - border-radius: 3px; - } - &.round { - border-radius: 1000px; - } - &.alert { - background-color: #c60f13; - color: white; - } - &.success { - background-color: #5da423; - color: white; - } - &.secondary { - background-color: #e9e9e9; - color: #333333; - } -} - -button, .button, input[type=button] { - cursor: pointer; - margin: 0 0 1.25rem; - border: none; - position: relative; - text-decoration: none; - text-align: center; - -webkit-appearance: none; - display: inline-block; - padding: 0.4rem 1.1rem; - font-size: 0.9rem; - background-color: #2ba6cb; - border-color: #2285a2; - color: white; - transition: background-color 150ms ease-out; - @include border-radius(2px); - &:hover, &:focus { - background-color: #2285a2; - outline: none; - color: white; - } - &.large { - padding-top: 1.125rem; - padding-right: 2.25rem; - padding-bottom: 1.1875rem; - padding-left: 2.25rem; - font-size: 1.25rem; - } - - &.small { - padding-top: 0.875rem; - padding-right: 1.75rem; - padding-bottom: 0.9375rem; - padding-left: 1.75rem; - font-size: 0.8125rem; - } - - &.tiny { - padding-top: 0.625rem; - padding-right: 1.25rem; - padding-bottom: 0.6875rem; - padding-left: 1.25rem; - font-size: 0.6875rem; - } - - &.expand { - padding-right: 0; - padding-left: 0; - width: 100%; - } - - &.left-align { - text-align: left; - text-indent: 0.75rem; - } - - &.right-align { - text-align: right; - padding-right: 0.75rem; - } - - &.round { - border-radius: 1000px; - } - - &.disabled, &[disabled] { - background-color: #2285a2; - border-color: #2285a2; - color: white; - cursor: default; - opacity: 0.5; - box-shadow: none; - &:hover, &:focus { - background-color: #2285a2; - opacity: 0.5; - } - } -} - - -@media only screen and (min-width: 40.063em) { - button, .button { - display: inline-block; - } -} - -.keystroke, kbd { - background-color: #ededed; - border-color: #dddddd; - color: #222222; - border-style: solid; - border-width: 1px; - margin: 0; - font-family: "Consolas", "Menlo", "Courier", monospace; - font-size: inherit; - padding: 0.125rem 0.25rem 0; - border-radius: 3px; -} - - - -/* We use this to get basic styling on all basic form elements */ -input[type="text"], -input[type="password"], -input[type="date"], -input[type="datetime"], -input[type="datetime-local"], -input[type="month"], -input[type="week"], -input[type="email"], -input[type="number"], -input[type="search"], -input[type="tel"], -input[type="time"], -input[type="url"], -textarea { - -webkit-appearance: none; - background-color: white; - font-family: inherit; - border: 1px solid #cccccc; - color: rgba(0, 0, 0, 0.75); - display: block; - font-size: 0.875rem; - margin: 0 0 1rem 0; - padding: 0.4rem; - width: 100%; - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; -} - input[type="text"]:focus, - input[type="password"]:focus, - input[type="date"]:focus, - input[type="datetime"]:focus, - input[type="datetime-local"]:focus, - input[type="month"]:focus, - input[type="week"]:focus, - input[type="email"]:focus, - input[type="number"]:focus, - input[type="search"]:focus, - input[type="tel"]:focus, - input[type="time"]:focus, - input[type="url"]:focus, - textarea:focus {} - input[type="text"]:focus, - input[type="password"]:focus, - input[type="date"]:focus, - input[type="datetime"]:focus, - input[type="datetime-local"]:focus, - input[type="month"]:focus, - input[type="week"]:focus, - input[type="email"]:focus, - input[type="number"]:focus, - input[type="search"]:focus, - input[type="tel"]:focus, - input[type="time"]:focus, - input[type="url"]:focus, - textarea:focus { - background: #fafafa; - border-color: #999999; - outline: none; } - input[type="text"][disabled], fieldset[disabled] input[type="text"], - input[type="password"][disabled], fieldset[disabled] - input[type="password"], - input[type="date"][disabled], fieldset[disabled] - input[type="date"], - input[type="datetime"][disabled], fieldset[disabled] - input[type="datetime"], - input[type="datetime-local"][disabled], fieldset[disabled] - input[type="datetime-local"], - input[type="month"][disabled], fieldset[disabled] - input[type="month"], - input[type="week"][disabled], fieldset[disabled] - input[type="week"], - input[type="email"][disabled], fieldset[disabled] - input[type="email"], - input[type="number"][disabled], fieldset[disabled] - input[type="number"], - input[type="search"][disabled], fieldset[disabled] - input[type="search"], - input[type="tel"][disabled], fieldset[disabled] - input[type="tel"], - input[type="time"][disabled], fieldset[disabled] - input[type="time"], - input[type="url"][disabled], fieldset[disabled] - input[type="url"], - textarea[disabled], fieldset[disabled] - textarea { - background-color: #dddddd; } - input[type="text"].radius, - input[type="password"].radius, - input[type="date"].radius, - input[type="datetime"].radius, - input[type="datetime-local"].radius, - input[type="month"].radius, - input[type="week"].radius, - input[type="email"].radius, - input[type="number"].radius, - input[type="search"].radius, - input[type="tel"].radius, - input[type="time"].radius, - input[type="url"].radius, - textarea.radius { - border-radius: 3px; } - -input[type="submit"] { - -webkit-appearance: none; } - -/* Respect enforced amount of rows for textarea */ -textarea[rows] { - height: auto; } - -/* Add height value for select elements to match text input height */ -select { - -webkit-appearance: none !important; - background-color: #fafafa; - background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZlcnNpb249IjEuMSIgeD0iMHB4IiB5PSIwcHgiIHdpZHRoPSI2cHgiIGhlaWdodD0iM3B4IiB2aWV3Qm94PSIwIDAgNiAzIiBlbmFibGUtYmFja2dyb3VuZD0ibmV3IDAgMCA2IDMiIHhtbDpzcGFjZT0icHJlc2VydmUiPjxwb2x5Z29uIHBvaW50cz0iNS45OTIsMCAyLjk5MiwzIC0wLjAwOCwwICIvPjwvc3ZnPg=="); - background-repeat: no-repeat; - background-position: 97% center; - border: 1px solid #cccccc; - padding: 0.5rem; - font-size: 0.875rem; - color: rgba(0, 0, 0, 0.75); - line-height: normal; - border-radius: 0; -} - select.radius { - border-radius: 3px; } - select:hover { - background-color: #f3f3f3; - border-color: #999999; } - -/* Adjust margin for form elements below */ -input[type="file"], -input[type="checkbox"], -input[type="radio"], -select { - margin: 0 0 1rem 0; } - -input[type="checkbox"] + label, -input[type="radio"] + label { - display: inline-block; - - margin-left: 0.5rem; - margin-right: 1rem; - margin-bottom: 0; - vertical-align: baseline; } - -/* Normalize file input width */ -input[type="file"] { - width: 100%; } diff --git a/web-ui/app/scss/layout/_message-panel.scss b/web-ui/app/scss/layout/_message-panel.scss new file mode 100644 index 00000000..e311a9bf --- /dev/null +++ b/web-ui/app/scss/layout/_message-panel.scss @@ -0,0 +1,9 @@ +message-panel-container { + overflow: hidden; + position: fixed; + top: 0; + width: 100% ; + position: relative; + margin-bottom: 0; +} + diff --git a/web-ui/app/scss/main.scss b/web-ui/app/scss/main.scss deleted file mode 100644 index b582a5d5..00000000 --- a/web-ui/app/scss/main.scss +++ /dev/null @@ -1,37 +0,0 @@ -@import "compass/css3"; -@import "reset"; -@import "foundation"; -@import "colors"; -@import "mixins"; -@import "alerts"; -@import "read"; -@import "reply"; -@import "compose"; -@import "security"; -@import "mascot"; -@import "styles"; - -html { - height:100%; -} -body { - min-height:100%; - overflow: hidden; - background: $white; -} -header#main { - overflow: hidden; - position: fixed; - top: 0; - width: 100%; - position: relative; - margin-bottom: 0; -} - -.no-padding { - padding: 0; -} - -.text-right { - text-align: right; -} diff --git a/web-ui/app/scss/opensans.scss b/web-ui/app/scss/opensans.scss deleted file mode 100644 index ada6a025..00000000 --- a/web-ui/app/scss/opensans.scss +++ /dev/null @@ -1,60 +0,0 @@ -@font-face { - font-family: 'Open Sans'; - font-style: normal; - font-weight: 300; - src: local('Open Sans Light'), local('OpenSans-Light'), url('/assets/fonts/OpenSans-Light.woff') format('woff'); -} -@font-face { - font-family: 'Open Sans'; - font-style: normal; - font-weight: 400; - src: local('Open Sans'), local('OpenSans'), url('/assets/fonts/OpenSans.woff') format('woff'); -} -@font-face { - font-family: 'Open Sans'; - font-style: normal; - font-weight: 600; - src: local('Open Sans Semibold'), local('OpenSans-Semibold'), url('/assets/fonts/OpenSans-Semibold.woff') format('woff'); -} -@font-face { - font-family: 'Open Sans'; - font-style: normal; - font-weight: 700; - src: local('Open Sans Bold'), local('OpenSans-Bold'), url('/assets/fonts/OpenSans-Bold.woff') format('woff'); -} -@font-face { - font-family: 'Open Sans'; - font-style: normal; - font-weight: 800; - src: local('Open Sans Extrabold'), local('OpenSans-Extrabold'), url('/assets/fonts/OpenSans-Extrabold.woff') format('woff'); -} -@font-face { - font-family: 'Open Sans'; - font-style: italic; - font-weight: 300; - src: local('Open Sans Light Italic'), local('OpenSansLight-Italic'), url('/assets/fonts/OpenSansLight-Italic.woff') format('woff'); -} -@font-face { - font-family: 'Open Sans'; - font-style: italic; - font-weight: 400; - src: local('Open Sans Italic'), local('OpenSans-Italic'), url('/assets/fonts/OpenSans-Italic.woff') format('woff'); -} -@font-face { - font-family: 'Open Sans'; - font-style: italic; - font-weight: 600; - src: local('Open Sans Semibold Italic'), local('OpenSans-SemiboldItalic'), url('/assets/fonts/OpenSans-SemiboldItalic.woff') format('woff'); -} -@font-face { - font-family: 'Open Sans'; - font-style: italic; - font-weight: 700; - src: local('Open Sans Bold Italic'), local('OpenSans-BoldItalic'), url('/assets/fonts/OpenSans-BoldItalic.woff') format('woff'); -} -@font-face { - font-family: 'Open Sans'; - font-style: italic; - font-weight: 800; - src: local('Open Sans Extrabold Italic'), local('OpenSans-ExtraboldItalic'), url('/assets/fonts/OpenSans-ExtraboldItalic.woff') format('woff'); -} diff --git a/web-ui/app/scss/reset.scss b/web-ui/app/scss/reset.scss deleted file mode 100644 index 55f8d054..00000000 --- a/web-ui/app/scss/reset.scss +++ /dev/null @@ -1,421 +0,0 @@ -/*! normalize.css v3.0.1 | MIT License | git.io/normalize */ - -/** - * 1. Set default font family to sans-serif. - * 2. Prevent iOS text size adjust after orientation change, without disabling - * user zoom. - */ - -html { - font-family: sans-serif; - /* 1 */ - -ms-text-size-adjust: 100%; - /* 2 */ - -webkit-text-size-adjust: 100%; - /* 2 */ -} - -/** - * Remove default margin. - */ - -body { - margin: 0; -} - -/* HTML5 display definitions - ========================================================================== */ - -/** - * Correct `block` display not defined for any HTML5 element in IE 8/9. - * Correct `block` display not defined for `details` or `summary` in IE 10/11 and Firefox. - * Correct `block` display not defined for `main` in IE 11. - */ - -article, aside, details, figcaption, figure, footer, header, hgroup, main, nav, section, summary { - display: block; -} - -/** - * 1. Correct `inline-block` display not defined in IE 8/9. - * 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera. - */ - -audio, canvas, progress, video { - display: inline-block; - /* 1 */ - vertical-align: baseline; - /* 2 */ -} - -/** - * Prevent modern browsers from displaying `audio` without controls. - * Remove excess height in iOS 5 devices. - */ - -audio:not([controls]) { - display: none; - height: 0; -} - -/** - * Address `[hidden]` styling not present in IE 8/9/10. - * Hide the `template` element in IE 8/9/11, Safari, and Firefox < 22. - */ - -[hidden], template { - display: none; -} - -/* Links - ========================================================================== */ - -/** - * Remove the gray background color from active links in IE 10. - */ - -a { - background: transparent; - &:active, &:hover { - outline: 0; - } -} - -/** - * Improve readability when focused and also mouse hovered in all browsers. - */ - -/* Text-level semantics - ========================================================================== */ - -/** - * Address styling not present in IE 8/9/10/11, Safari, and Chrome. - */ - -abbr[title] { - border-bottom: 1px dotted; -} - -/** - * Address style set to `bolder` in Firefox 4+, Safari, and Chrome. - */ - -b, strong { - font-weight: bold; -} - -/** - * Address styling not present in Safari and Chrome. - */ - -dfn { - font-style: italic; -} - -/** - * Address variable `h1` font-size and margin within `section` and `article` - * contexts in Firefox 4+, Safari, and Chrome. - */ - -h1 { - font-size: 2em; - margin: 0.67em 0; -} - -/** - * Address styling not present in IE 8/9. - */ - -mark { - background: #ff0; - color: #000; -} - -/** - * Address inconsistent and variable font size in all browsers. - */ - -small { - font-size: 80%; -} - -/** - * Prevent `sub` and `sup` affecting `line-height` in all browsers. - */ - -sub { - font-size: 75%; - line-height: 0; - position: relative; - vertical-align: baseline; -} - -sup { - font-size: 75%; - line-height: 0; - position: relative; - vertical-align: baseline; - top: -0.5em; -} - -sub { - bottom: -0.25em; -} - -/* Embedded content - ========================================================================== */ - -/** - * Remove border when inside `a` element in IE 8/9/10. - */ - -img { - border: 0; -} - -/** - * Correct overflow not hidden in IE 9/10/11. - */ - -svg:not(:root) { - overflow: hidden; -} - -/* Grouping content - ========================================================================== */ - -/** - * Address margin not present in IE 8/9 and Safari. - */ - -figure { - margin: 1em 40px; -} - -/** - * Address differences between Firefox and other browsers. - */ - -hr { - -moz-box-sizing: content-box; - box-sizing: content-box; - height: 0; -} - -/** - * Contain overflow in all browsers. - */ - -pre { - overflow: auto; -} - -/** - * Address odd `em`-unit font size rendering in all browsers. - */ - -code, kbd, pre, samp { - font-family: monospace, monospace; - font-size: 1em; -} - -/* Forms - ========================================================================== */ - -/** - * Known limitation: by default, Chrome and Safari on OS X allow very limited - * styling of `select`, unless a `border` property is set. - */ - -/** - * 1. Correct color not being inherited. - * Known issue: affects color of disabled elements. - * 2. Correct font properties not being inherited. - * 3. Address margins set differently in Firefox 4+, Safari, and Chrome. - */ - -button, input, optgroup, select, textarea { - color: inherit; - /* 1 */ - font: inherit; - /* 2 */ - margin: 0; - /* 3 */ -} - -/** - * Address `overflow` set to `hidden` in IE 8/9/10/11. - */ - -button { - overflow: visible; - text-transform: none; -} - -/** - * Address inconsistent `text-transform` inheritance for `button` and `select`. - * All other form control elements do not inherit `text-transform` values. - * Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera. - * Correct `select` style inheritance in Firefox. - */ - -select { - text-transform: none; -} - -/** - * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio` - * and `video` controls. - * 2. Correct inability to style clickable `input` types in iOS. - * 3. Improve usability and consistency of cursor style between image-type - * `input` and others. - */ - -button, html input[type="button"] { - -webkit-appearance: button; - /* 2 */ - cursor: pointer; - /* 3 */ -} - -input { - &[type="reset"], &[type="submit"] { - -webkit-appearance: button; - /* 2 */ - cursor: pointer; - /* 3 */ - } -} - -/** - * Re-set default cursor for disabled elements. - */ - -button[disabled], html input[disabled] { - cursor: default; -} - -/** - * Remove inner padding and border in Firefox 4+. - */ - -button::-moz-focus-inner { - border: 0; - padding: 0; -} - -input { - &::-moz-focus-inner { - border: 0; - padding: 0; - } - line-height: normal; - &[type="checkbox"], &[type="radio"] { - box-sizing: border-box; - /* 1 */ - padding: 0; - /* 2 */ - } - &[type="number"] { - &::-webkit-inner-spin-button, &::-webkit-outer-spin-button { - height: auto; - } - } - &[type="search"] { - -webkit-appearance: textfield; - /* 1 */ - -moz-box-sizing: content-box; - -webkit-box-sizing: content-box; - /* 2 */ - box-sizing: content-box; - &::-webkit-search-cancel-button, &::-webkit-search-decoration { - -webkit-appearance: none; - } - } -} - -/** - * Address Firefox 4+ setting `line-height` on `input` using `!important` in - * the UA stylesheet. - */ - -/** - * It's recommended that you don't attempt to style these elements. - * Firefox's implementation doesn't respect box-sizing, padding, or width. - * - * 1. Address box sizing set to `content-box` in IE 8/9/10. - * 2. Remove excess padding in IE 8/9/10. - */ - -/** - * Fix the cursor style for Chrome's increment/decrement buttons. For certain - * `font-size` values of the `input`, it causes the cursor style of the - * decrement button to change from `default` to `text`. - */ - -/** - * 1. Address `appearance` set to `searchfield` in Safari and Chrome. - * 2. Address `box-sizing` set to `border-box` in Safari and Chrome - * (include `-moz` to future-proof). - */ - -/** - * Remove inner padding and search cancel button in Safari and Chrome on OS X. - * Safari (but not Chrome) clips the cancel button when the search input has - * padding (and `textfield` appearance). - */ - -/** - * Define consistent border, margin, and padding. - */ - -fieldset { - border: 1px solid #c0c0c0; - margin: 0 2px; - padding: 0.35em 0.625em 0.75em; -} - -/** - * 1. Correct `color` not being inherited in IE 8/9/10/11. - * 2. Remove padding so people aren't caught out if they zero out fieldsets. - */ - -legend { - border: 0; - /* 1 */ - padding: 0; - /* 2 */ -} - -/** - * Remove default vertical scrollbar in IE 8/9/10/11. - */ - -textarea { - overflow: auto; -} - -/** - * Don't inherit the `font-weight` (applied by a rule above). - * NOTE: the default cannot safely be changed in Chrome and Safari on OS X. - */ - -optgroup { - font-weight: bold; -} - -/* Tables - ========================================================================== */ - -/** - * Remove most spacing between table cells. - */ - -table { - border-collapse: collapse; - border-spacing: 0; -} - -td, th { - padding: 0; -} diff --git a/web-ui/app/scss/style.scss b/web-ui/app/scss/style.scss new file mode 100644 index 00000000..eeadd662 --- /dev/null +++ b/web-ui/app/scss/style.scss @@ -0,0 +1,35 @@ +// vendor stylesheets and resets +@import "vendor/reset"; +@import "compass/css3"; +@import "vendor/foundation"; + +// basic configuration +@import "base/fonts"; +@import "base/colors"; +@import "base/scaffolding"; + +// templates + + +// mixins +@import "mixins"; + + +// layout +@import "layout/message-panel"; + +// modules +@import "views/message-panel"; + + +// misc stuff +@import "others"; + +// TODO +@import "compose"; +@import "mascot"; +@import "read"; +@import "reply"; +@import "security"; +@import "styles"; + diff --git a/web-ui/app/scss/vendor/_foundation.scss b/web-ui/app/scss/vendor/_foundation.scss new file mode 100644 index 00000000..7918cf26 --- /dev/null +++ b/web-ui/app/scss/vendor/_foundation.scss @@ -0,0 +1,2066 @@ +@import 'compass/css3'; + +meta { + &.foundation-version { + font-family: "/5.2.3/"; + } + &.foundation-mq-small { + font-family: "/only screen/"; + width: 0em; + } + &.foundation-mq-medium { + font-family: "/only screen and (min-width:40.063em)/"; + width: 40.063em; + } + &.foundation-mq-large { + font-family: "/only screen and (min-width:64.063em)/"; + width: 64.063em; + } + &.foundation-mq-xlarge { + font-family: "/only screen and (min-width:90.063em)/"; + width: 90.063em; + } + &.foundation-mq-xxlarge { + font-family: "/only screen and (min-width:120.063em)/"; + width: 120.063em; + } + &.foundation-data-attribute-namespace { + font-family: false; + } +} + +html, body { + height: 100%; +} + +* { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + &:before, &:after { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + } +} + +html { + font-size: 100%; +} + +body { + font-family: "Open Sans", "Microsoft YaHei", "Hiragino Sans GB", "Hiragino Sans GB W3", "微软雅黑", "Helvetica Neue", Arial, sans-serif; + font-size: 13px; + line-height: 1.2em; + background: white; + color: #333; + padding: 0; + margin: 0; + font-weight: normal; + -webkit-font-smoothing: antialiased; + font-style: normal; + position: relative; + cursor: default; +} + +a:hover { + cursor: pointer; +} + +img { + max-width: 100%; + height: auto; + -ms-interpolation-mode: bicubic; +} + +#map_canvas { + img, embed, object { + max-width: none !important; + } +} + +.map_canvas { + img, embed, object { + max-width: none !important; + } +} + +.left { + float: left !important; +} + +.right { + float: right !important; +} + +.clearfix { + &:before { + content: " "; + display: table; + } + &:after { + content: " "; + display: table; + clear: both; + } +} + +.hide { + display: none; +} + +.antialiased { + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +img { + display: inline-block; + vertical-align: middle; +} + +textarea { + height: auto; + min-height: 50px; + &:focus { + outline: none; + } +} + +select { + width: 100%; +} + +.row { + width: 100%; + margin-left: auto; + margin-right: auto; + margin-top: 0; + margin-bottom: 0; + &:before { + content: " "; + display: table; + } + &:after { + content: " "; + display: table; + clear: both; + } + &.collapse { + > { + .column, .columns { + padding-left: 0; + padding-right: 0; + } + } + .row { + margin-left: 0; + margin-right: 0; + } + } + .row { + width: auto; + margin-left: -0.9375em; + margin-right: -0.9375em; + margin-top: 0; + margin-bottom: 0; + max-width: none; + &:before { + content: " "; + display: table; + } + &:after { + content: " "; + display: table; + clear: both; + } + &.collapse { + width: auto; + margin: 0; + max-width: none; + &:before { + content: " "; + display: table; + } + &:after { + content: " "; + display: table; + clear: both; + } + } + } +} + +.column, .columns { + padding-left: 0.9375em; + padding-right: 0.9375em; + width: 100%; + float: left; +} + +@media only screen { + .small-push-0 { + position: relative; + left: 0%; + right: auto; + } + .small-pull-0 { + position: relative; + right: 0%; + left: auto; + } + .small-push-1 { + position: relative; + left: 8.33333%; + right: auto; + } + .small-pull-1 { + position: relative; + right: 8.33333%; + left: auto; + } + .small-push-2 { + position: relative; + left: 16.66667%; + right: auto; + } + .small-pull-2 { + position: relative; + right: 16.66667%; + left: auto; + } + .small-push-3 { + position: relative; + left: 25%; + right: auto; + } + .small-pull-3 { + position: relative; + right: 25%; + left: auto; + } + .small-push-4 { + position: relative; + left: 33.33333%; + right: auto; + } + .small-pull-4 { + position: relative; + right: 33.33333%; + left: auto; + } + .small-push-5 { + position: relative; + left: 41.66667%; + right: auto; + } + .small-pull-5 { + position: relative; + right: 41.66667%; + left: auto; + } + .small-push-6 { + position: relative; + left: 50%; + right: auto; + } + .small-pull-6 { + position: relative; + right: 50%; + left: auto; + } + .small-push-7 { + position: relative; + left: 58.33333%; + right: auto; + } + .small-pull-7 { + position: relative; + right: 58.33333%; + left: auto; + } + .small-push-8 { + position: relative; + left: 66.66667%; + right: auto; + } + .small-pull-8 { + position: relative; + right: 66.66667%; + left: auto; + } + .small-push-9 { + position: relative; + left: 75%; + right: auto; + } + .small-pull-9 { + position: relative; + right: 75%; + left: auto; + } + .small-push-10 { + position: relative; + left: 83.33333%; + right: auto; + } + .small-pull-10 { + position: relative; + right: 83.33333%; + left: auto; + } + .small-push-11 { + position: relative; + left: 91.66667%; + right: auto; + } + .small-pull-11 { + position: relative; + right: 91.66667%; + left: auto; + } + .column, .columns { + position: relative; + padding-left: 0.9375em; + padding-right: 0.9375em; + float: left; + } + .small-1 { + width: 8.33333%; + } + .small-2 { + width: 16.66667%; + } + .small-3 { + width: 25%; + } + .small-4 { + width: 33.33333%; + } + .small-5 { + width: 41.66667%; + } + .small-6 { + width: 50%; + } + .small-7 { + width: 58.33333%; + } + .small-8 { + width: 66.66667%; + } + .small-9 { + width: 75%; + } + .small-10 { + width: 83.33333%; + } + .small-11 { + width: 91.66667%; + } + .small-12 { + width: 100%; + } + [class*="column"] + [class*="column"] { + &:last-child { + float: right; + } + &.end { + float: left; + } + } + .small-offset-0 { + margin-left: 0% !important; + } + .small-offset-1 { + margin-left: 8.33333% !important; + } + .small-offset-2 { + margin-left: 16.66667% !important; + } + .small-offset-3 { + margin-left: 25% !important; + } + .small-offset-4 { + margin-left: 33.33333% !important; + } + .small-offset-5 { + margin-left: 41.66667% !important; + } + .small-offset-6 { + margin-left: 50% !important; + } + .small-offset-7 { + margin-left: 58.33333% !important; + } + .small-offset-8 { + margin-left: 66.66667% !important; + } + .small-offset-9 { + margin-left: 75% !important; + } + .small-offset-10 { + margin-left: 83.33333% !important; + } + .small-offset-11 { + margin-left: 91.66667% !important; + } + .small-reset-order { + margin-left: 0; + margin-right: 0; + left: auto; + right: auto; + float: left; + } + .column.small-centered, .columns.small-centered { + margin-left: auto; + margin-right: auto; + float: none !important; + } + .column.small-uncentered, .columns.small-uncentered { + margin-left: 0; + margin-right: 0; + float: left !important; + } + .column.small-uncentered.opposite, .columns.small-uncentered.opposite { + float: right; + } +} + +@media only screen and (min-width: 40.063em) { + .medium-push-0 { + position: relative; + left: 0%; + right: auto; + } + .medium-pull-0 { + position: relative; + right: 0%; + left: auto; + } + .medium-push-1 { + position: relative; + left: 8.33333%; + right: auto; + } + .medium-pull-1 { + position: relative; + right: 8.33333%; + left: auto; + } + .medium-push-2 { + position: relative; + left: 16.66667%; + right: auto; + } + .medium-pull-2 { + position: relative; + right: 16.66667%; + left: auto; + } + .medium-push-3 { + position: relative; + left: 25%; + right: auto; + } + .medium-pull-3 { + position: relative; + right: 25%; + left: auto; + } + .medium-push-4 { + position: relative; + left: 33.33333%; + right: auto; + } + .medium-pull-4 { + position: relative; + right: 33.33333%; + left: auto; + } + .medium-push-5 { + position: relative; + left: 41.66667%; + right: auto; + } + .medium-pull-5 { + position: relative; + right: 41.66667%; + left: auto; + } + .medium-push-6 { + position: relative; + left: 50%; + right: auto; + } + .medium-pull-6 { + position: relative; + right: 50%; + left: auto; + } + .medium-push-7 { + position: relative; + left: 58.33333%; + right: auto; + } + .medium-pull-7 { + position: relative; + right: 58.33333%; + left: auto; + } + .medium-push-8 { + position: relative; + left: 66.66667%; + right: auto; + } + .medium-pull-8 { + position: relative; + right: 66.66667%; + left: auto; + } + .medium-push-9 { + position: relative; + left: 75%; + right: auto; + } + .medium-pull-9 { + position: relative; + right: 75%; + left: auto; + } + .medium-push-10 { + position: relative; + left: 83.33333%; + right: auto; + } + .medium-pull-10 { + position: relative; + right: 83.33333%; + left: auto; + } + .medium-push-11 { + position: relative; + left: 91.66667%; + right: auto; + } + .medium-pull-11 { + position: relative; + right: 91.66667%; + left: auto; + } + .column, .columns { + position: relative; + padding-left: 0.9375em; + padding-right: 0.9375em; + float: left; + } + .medium-1 { + width: 8.33333%; + } + .medium-2 { + width: 16.66667%; + } + .medium-3 { + width: 25%; + } + .medium-4 { + width: 33.33333%; + } + .medium-5 { + width: 41.66667%; + } + .medium-6 { + width: 50%; + } + .medium-7 { + width: 58.33333%; + } + .medium-8 { + width: 66.66667%; + } + .medium-9 { + width: 75%; + } + .medium-10 { + width: 83.33333%; + } + .medium-11 { + width: 91.66667%; + } + .medium-12 { + width: 100%; + } + [class*="column"] + [class*="column"] { + &:last-child { + float: right; + } + &.end { + float: left; + } + } + .medium-offset-0 { + margin-left: 0% !important; + } + .medium-offset-1 { + margin-left: 8.33333% !important; + } + .medium-offset-2 { + margin-left: 16.66667% !important; + } + .medium-offset-3 { + margin-left: 25% !important; + } + .medium-offset-4 { + margin-left: 33.33333% !important; + } + .medium-offset-5 { + margin-left: 41.66667% !important; + } + .medium-offset-6 { + margin-left: 50% !important; + } + .medium-offset-7 { + margin-left: 58.33333% !important; + } + .medium-offset-8 { + margin-left: 66.66667% !important; + } + .medium-offset-9 { + margin-left: 75% !important; + } + .medium-offset-10 { + margin-left: 83.33333% !important; + } + .medium-offset-11 { + margin-left: 91.66667% !important; + } + .medium-reset-order { + margin-left: 0; + margin-right: 0; + left: auto; + right: auto; + float: left; + } + .column.medium-centered, .columns.medium-centered { + margin-left: auto; + margin-right: auto; + float: none !important; + } + .column.medium-uncentered, .columns.medium-uncentered { + margin-left: 0; + margin-right: 0; + float: left !important; + } + .column.medium-uncentered.opposite, .columns.medium-uncentered.opposite { + float: right; + } + .push-0 { + position: relative; + left: 0%; + right: auto; + } + .pull-0 { + position: relative; + right: 0%; + left: auto; + } + .push-1 { + position: relative; + left: 8.33333%; + right: auto; + } + .pull-1 { + position: relative; + right: 8.33333%; + left: auto; + } + .push-2 { + position: relative; + left: 16.66667%; + right: auto; + } + .pull-2 { + position: relative; + right: 16.66667%; + left: auto; + } + .push-3 { + position: relative; + left: 25%; + right: auto; + } + .pull-3 { + position: relative; + right: 25%; + left: auto; + } + .push-4 { + position: relative; + left: 33.33333%; + right: auto; + } + .pull-4 { + position: relative; + right: 33.33333%; + left: auto; + } + .push-5 { + position: relative; + left: 41.66667%; + right: auto; + } + .pull-5 { + position: relative; + right: 41.66667%; + left: auto; + } + .push-6 { + position: relative; + left: 50%; + right: auto; + } + .pull-6 { + position: relative; + right: 50%; + left: auto; + } + .push-7 { + position: relative; + left: 58.33333%; + right: auto; + } + .pull-7 { + position: relative; + right: 58.33333%; + left: auto; + } + .push-8 { + position: relative; + left: 66.66667%; + right: auto; + } + .pull-8 { + position: relative; + right: 66.66667%; + left: auto; + } + .push-9 { + position: relative; + left: 75%; + right: auto; + } + .pull-9 { + position: relative; + right: 75%; + left: auto; + } + .push-10 { + position: relative; + left: 83.33333%; + right: auto; + } + .pull-10 { + position: relative; + right: 83.33333%; + left: auto; + } + .push-11 { + position: relative; + left: 91.66667%; + right: auto; + } + .pull-11 { + position: relative; + right: 91.66667%; + left: auto; + } +} + +@media only screen and (min-width: 64.063em) { + .large-push-0 { + position: relative; + left: 0%; + right: auto; + } + .large-pull-0 { + position: relative; + right: 0%; + left: auto; + } + .large-push-1 { + position: relative; + left: 8.33333%; + right: auto; + } + .large-pull-1 { + position: relative; + right: 8.33333%; + left: auto; + } + .large-push-2 { + position: relative; + left: 16.66667%; + right: auto; + } + .large-pull-2 { + position: relative; + right: 16.66667%; + left: auto; + } + .large-push-3 { + position: relative; + left: 25%; + right: auto; + } + .large-pull-3 { + position: relative; + right: 25%; + left: auto; + } + .large-push-4 { + position: relative; + left: 33.33333%; + right: auto; + } + .large-pull-4 { + position: relative; + right: 33.33333%; + left: auto; + } + .large-push-5 { + position: relative; + left: 41.66667%; + right: auto; + } + .large-pull-5 { + position: relative; + right: 41.66667%; + left: auto; + } + .large-push-6 { + position: relative; + left: 50%; + right: auto; + } + .large-pull-6 { + position: relative; + right: 50%; + left: auto; + } + .large-push-7 { + position: relative; + left: 58.33333%; + right: auto; + } + .large-pull-7 { + position: relative; + right: 58.33333%; + left: auto; + } + .large-push-8 { + position: relative; + left: 66.66667%; + right: auto; + } + .large-pull-8 { + position: relative; + right: 66.66667%; + left: auto; + } + .large-push-9 { + position: relative; + left: 75%; + right: auto; + } + .large-pull-9 { + position: relative; + right: 75%; + left: auto; + } + .large-push-10 { + position: relative; + left: 83.33333%; + right: auto; + } + .large-pull-10 { + position: relative; + right: 83.33333%; + left: auto; + } + .large-push-11 { + position: relative; + left: 91.66667%; + right: auto; + } + .large-pull-11 { + position: relative; + right: 91.66667%; + left: auto; + } + .column, .columns { + position: relative; + padding-left: 0.9375em; + padding-right: 0.9375em; + float: left; + } + .large-1 { + width: 8.33333%; + } + .large-2 { + width: 16.66667%; + } + .large-3 { + width: 25%; + } + .large-4 { + width: 33.33333%; + } + .large-5 { + width: 41.66667%; + } + .large-6 { + width: 50%; + } + .large-7 { + width: 58.33333%; + } + .large-8 { + width: 66.66667%; + } + .large-9 { + width: 75%; + } + .large-10 { + width: 83.33333%; + } + .large-11 { + width: 91.66667%; + } + .large-12 { + width: 100%; + } + [class*="column"] + [class*="column"] { + &:last-child { + float: right; + } + &.end { + float: left; + } + } + .large-offset-0 { + margin-left: 0% !important; + } + .large-offset-1 { + margin-left: 8.33333% !important; + } + .large-offset-2 { + margin-left: 16.66667% !important; + } + .large-offset-3 { + margin-left: 25% !important; + } + .large-offset-4 { + margin-left: 33.33333% !important; + } + .large-offset-5 { + margin-left: 41.66667% !important; + } + .large-offset-6 { + margin-left: 50% !important; + } + .large-offset-7 { + margin-left: 58.33333% !important; + } + .large-offset-8 { + margin-left: 66.66667% !important; + } + .large-offset-9 { + margin-left: 75% !important; + } + .large-offset-10 { + margin-left: 83.33333% !important; + } + .large-offset-11 { + margin-left: 91.66667% !important; + } + .large-reset-order { + margin-left: 0; + margin-right: 0; + left: auto; + right: auto; + float: left; + } + .column.large-centered, .columns.large-centered { + margin-left: auto; + margin-right: auto; + float: none !important; + } + .column.large-uncentered, .columns.large-uncentered { + margin-left: 0; + margin-right: 0; + float: left !important; + } + .column.large-uncentered.opposite, .columns.large-uncentered.opposite { + float: right; + } + .push-0 { + position: relative; + left: 0%; + right: auto; + } + .pull-0 { + position: relative; + right: 0%; + left: auto; + } + .push-1 { + position: relative; + left: 8.33333%; + right: auto; + } + .pull-1 { + position: relative; + right: 8.33333%; + left: auto; + } + .push-2 { + position: relative; + left: 16.66667%; + right: auto; + } + .pull-2 { + position: relative; + right: 16.66667%; + left: auto; + } + .push-3 { + position: relative; + left: 25%; + right: auto; + } + .pull-3 { + position: relative; + right: 25%; + left: auto; + } + .push-4 { + position: relative; + left: 33.33333%; + right: auto; + } + .pull-4 { + position: relative; + right: 33.33333%; + left: auto; + } + .push-5 { + position: relative; + left: 41.66667%; + right: auto; + } + .pull-5 { + position: relative; + right: 41.66667%; + left: auto; + } + .push-6 { + position: relative; + left: 50%; + right: auto; + } + .pull-6 { + position: relative; + right: 50%; + left: auto; + } + .push-7 { + position: relative; + left: 58.33333%; + right: auto; + } + .pull-7 { + position: relative; + right: 58.33333%; + left: auto; + } + .push-8 { + position: relative; + left: 66.66667%; + right: auto; + } + .pull-8 { + position: relative; + right: 66.66667%; + left: auto; + } + .push-9 { + position: relative; + left: 75%; + right: auto; + } + .pull-9 { + position: relative; + right: 75%; + left: auto; + } + .push-10 { + position: relative; + left: 83.33333%; + right: auto; + } + .pull-10 { + position: relative; + right: 83.33333%; + left: auto; + } + .push-11 { + position: relative; + left: 91.66667%; + right: auto; + } + .pull-11 { + position: relative; + right: 91.66667%; + left: auto; + } +} + +.inline-list { + margin: 0 auto 1.0625rem auto; + margin-left: -1.375rem; + margin-right: 0; + padding: 0; + list-style: none; + overflow: hidden; + > li { + list-style: none; + float: left; + margin-left: 1.375rem; + display: block; + > * { + display: block; + } + } +} + +.text-left { + text-align: left !important; +} + +.text-right { + text-align: right !important; +} + +.text-center { + text-align: center !important; +} + +.text-justify { + text-align: justify !important; +} + +@media only screen and (max-width: 40em) { + .small-only-text-left { + text-align: left !important; + } + .small-only-text-right { + text-align: right !important; + } + .small-only-text-center { + text-align: center !important; + } + .small-only-text-justify { + text-align: justify !important; + } +} + +@media only screen { + .small-text-left { + text-align: left !important; + } + .small-text-right { + text-align: right !important; + } + .small-text-center { + text-align: center !important; + } + .small-text-justify { + text-align: justify !important; + } +} + +@media only screen and (min-width: 40.063em) and (max-width: 64em) { + .medium-only-text-left { + text-align: left !important; + } + .medium-only-text-right { + text-align: right !important; + } + .medium-only-text-center { + text-align: center !important; + } + .medium-only-text-justify { + text-align: justify !important; + } +} + +@media only screen and (min-width: 40.063em) { + .medium-text-left { + text-align: left !important; + } + .medium-text-right { + text-align: right !important; + } + .medium-text-center { + text-align: center !important; + } + .medium-text-justify { + text-align: justify !important; + } +} + +@media only screen and (min-width: 64.063em) and (max-width: 90em) { + .large-only-text-left { + text-align: left !important; + } + .large-only-text-right { + text-align: right !important; + } + .large-only-text-center { + text-align: center !important; + } + .large-only-text-justify { + text-align: justify !important; + } +} + +@media only screen and (min-width: 64.063em) { + .large-text-left { + text-align: left !important; + } + .large-text-right { + text-align: right !important; + } + .large-text-center { + text-align: center !important; + } + .large-text-justify { + text-align: justify !important; + } +} + +@media only screen and (min-width: 90.063em) and (max-width: 120em) { + .xlarge-only-text-left { + text-align: left !important; + } + .xlarge-only-text-right { + text-align: right !important; + } + .xlarge-only-text-center { + text-align: center !important; + } + .xlarge-only-text-justify { + text-align: justify !important; + } +} + +@media only screen and (min-width: 90.063em) { + .xlarge-text-left { + text-align: left !important; + } + .xlarge-text-right { + text-align: right !important; + } + .xlarge-text-center { + text-align: center !important; + } + .xlarge-text-justify { + text-align: justify !important; + } +} + +@media only screen and (min-width: 120.063em) and (max-width: 99999999em) { + .xxlarge-only-text-left { + text-align: left !important; + } + .xxlarge-only-text-right { + text-align: right !important; + } + .xxlarge-only-text-center { + text-align: center !important; + } + .xxlarge-only-text-justify { + text-align: justify !important; + } +} + +@media only screen and (min-width: 120.063em) { + .xxlarge-text-left { + text-align: left !important; + } + .xxlarge-text-right { + text-align: right !important; + } + .xxlarge-text-center { + text-align: center !important; + } + .xxlarge-text-justify { + text-align: justify !important; + } +} + +/* Typography resets */ + +div, dl, dt, dd, ul, ol, li, h1, h2, h3, h4, h5, h6, pre, form, p, blockquote, th, td { + margin: 0; + padding: 0; +} + +/* Default Link Styles */ + +a { + color: #2ba6cb; + text-decoration: none; + line-height: inherit; + &:hover, &:focus { + color: #258faf; + outline: none; + } + img { + border: none; + } +} + +/* Default paragraph styles */ + +p { + font-family: inherit; + font-weight: normal; + font-size: 0.9rem; + line-height: 1.4; + margin-bottom: 1.25rem; + text-rendering: optimizeLegibility; + &.lead { + font-size: 1.21875rem; + line-height: 1.4; + } + aside { + font-size: 0.875rem; + line-height: 1.35; + font-style: italic; + } +} + +/* Default header styles */ + +h1, h2, h3, h4, h5, h6 { + font-weight: normal; + font-style: normal; + color: #222; + text-rendering: optimizeLegibility; + margin-top: 0.2rem; + margin-bottom: 0.5rem; + line-height: 1.2; +} + +h1 small, h2 small, h3 small, h4 small, h5 small, h6 small { + font-size: 60%; + color: #6f6f6f; + line-height: 0; +} + +h1 { + font-size: 2.125rem; +} + +h2 { + font-size: 1.6875rem; +} + +h3 { + font-size: 1.375rem; +} + +h4, h5 { + font-size: 1.125rem; +} + +h6 { + font-size: 1rem; +} + +.subheader { + line-height: 1.4; + color: #6f6f6f; + font-weight: normal; + margin-top: 0.2rem; + margin-bottom: 0.5rem; +} + +hr { + border: solid #dddddd; + border-width: 1px 0 0; + clear: both; + margin: 1.25rem 0 1.1875rem; + height: 0; +} + +/* Helpful Typography Defaults */ + +em, i { + font-style: italic; + line-height: inherit; +} + +strong, b { + font-weight: bold; + line-height: inherit; +} + +small { + font-size: 60%; + line-height: inherit; +} + +code { + font-family: Consolas, "Liberation Mono", Courier, monospace; + font-weight: bold; + color: #910b0e; +} + +/* Lists */ + +ul, ol, dl { + font-size: 0.9rem; + line-height: 1.6; + margin-bottom: 1.25rem; + list-style-position: outside; + font-family: inherit; +} + +ul { + margin-left: 0; + &.bullets { + margin-left: 1.1rem; + li { + margin-left: 1.25rem; + margin-bottom: 0; + list-style: circle; + } + } + li { + margin-bottom: 0; + list-style: none; + } +} + +/* Abbreviations */ + +abbr, acronym { + text-transform: uppercase; + font-size: 90%; + color: #222222; + border-bottom: 1px dotted #dddddd; + cursor: help; +} + +abbr { + text-transform: none; +} + +/* Blockquotes */ + +blockquote { + margin: 0 0 1.25rem; + padding: 0.5625rem 1.25rem 0 1.1875rem; + border-left: 1px solid #dddddd; + cite { + display: block; + font-size: 0.8125rem; + color: #555555; + &:before { + content: "\2014 \0020"; + } + a { + color: #555555; + &:visited { + color: #555555; + } + } + } + line-height: 1.6; + color: #6f6f6f; + p { + line-height: 1.6; + color: #6f6f6f; + } +} + +/* Microformats */ + +.vcard { + display: inline-block; + margin: 0 0 1.25rem 0; + border: 1px solid #dddddd; + padding: 0.625rem 0.75rem; + li { + margin: 0; + display: block; + } + .fn { + font-weight: bold; + font-size: 0.9375rem; + } +} + +.vevent { + .summary { + font-weight: bold; + } + abbr { + cursor: default; + text-decoration: none; + font-weight: bold; + border: none; + padding: 0 0.0625rem; + } +} + +@media only screen and (min-width: 40.063em) { + h1, h2, h3, h4, h5, h6 { + line-height: 1.2; + } + h1 { + font-size: 2.55rem; + } + h2 { + font-size: 2.3125rem; + } + h3 { + font-size: 1.4875rem; + } + h4 { + font-size: 1.1375rem; + } +} + +/* + * Print styles. + * + * Inlined to avoid required HTTP connection: www.phpied.com/delay-loading-your-print-css/ + * Credit to Paul Irish and HTML5 Boilerplate (html5boilerplate.com) +*/ + +.print-only { + display: none !important; +} + +@media print { + * { + background: transparent !important; + color: black !important; + /* Black prints faster: h5bp.com/s */ + box-shadow: none !important; + text-shadow: none !important; + } + a { + text-decoration: underline; + &:visited { + text-decoration: underline; + } + &[href]:after { + content: " (" attr(href) ")"; + } + } + abbr[title]:after { + content: " (" attr(title) ")"; + } + .ir a:after { + content: ""; + } + a { + &[href^="javascript:"]:after, &[href^="#"]:after { + content: ""; + } + } + pre, blockquote { + border: 1px solid #999999; + page-break-inside: avoid; + } + thead { + display: table-header-group; + /* h5bp.com/t */ + } + tr { + page-break-inside: avoid; + } + img { + page-break-inside: avoid; + max-width: 100% !important; + } + @page { + margin: 0.5cm; + } + + p, h2, h3 { + orphans: 3; + widows: 3; + } + h2, h3 { + page-break-after: avoid; + } + .hide-on-print { + display: none !important; + } + .print-only { + display: block !important; + } + .hide-for-print { + display: none !important; + } + .show-for-print { + display: inherit !important; + } +} + +.reveal-modal-bg { + position: fixed; + height: 100%; + width: 100%; + background: black; + background: rgba(0, 0, 0, 0.45); + z-index: 99; + display: none; + top: 0; + left: 0; +} + +dialog, .reveal-modal { + visibility: hidden; + display: none; + position: absolute; + z-index: 100; + width: 100vw; + top: 0; + left: 0; + background-color: white; + padding: 1.25rem; + border: solid 1px #666666; + box-shadow: 0 0 10px rgba(0, 0, 0, 0.4); +} + +@media only screen and (max-width: 40em) { + dialog, .reveal-modal { + min-height: 100vh; + } +} + +@media only screen and (min-width: 40.063em) { + dialog, .reveal-modal { + left: 50%; + } +} + +dialog { + .column, .columns { + min-width: 0; + } +} + +.reveal-modal { + .column, .columns { + min-width: 0; + } +} + +dialog > :first-child, .reveal-modal > :first-child { + margin-top: 0; +} + +dialog > :last-child, .reveal-modal > :last-child { + margin-bottom: 0; +} + +@media only screen and (min-width: 40.063em) { + dialog, .reveal-modal { + margin-left: -26%; + width: 50%; + } +} + +@media only screen and (min-width: 40.063em) { + dialog, .reveal-modal { + top: 6.25rem; + } +} + +dialog .close-reveal-modal, .reveal-modal .close-reveal-modal { + font-size: 2.5rem; + line-height: 1; + position: absolute; + top: 0.5rem; + right: 0.6875rem; + color: #aaaaaa; + font-weight: bold; + cursor: pointer; +} + +dialog[open] { + display: block; + visibility: visible; +} + +@media only screen and (min-width: 40.063em) { + dialog, .reveal-modal { + padding: 1.875rem; + } + dialog.radius, .reveal-modal.radius { + border-radius: 3px; + } + dialog.round, .reveal-modal.round { + border-radius: 1000px; + } + dialog.collapse, .reveal-modal.collapse { + padding: 0; + } + dialog.full, .reveal-modal.full { + top: 0; + left: 0; + height: 100vh; + min-height: 100vh; + margin-left: 0 !important; + } +} + +@media only screen and (min-width: 40.063em) and (min-width: 40.063em) { + dialog.tiny, .reveal-modal.tiny { + margin-left: -15%; + width: 30%; + } +} + +@media only screen and (min-width: 40.063em) and (min-width: 40.063em) { + dialog.small, .reveal-modal.small { + margin-left: -20%; + width: 40%; + } +} + +@media only screen and (min-width: 40.063em) and (min-width: 40.063em) { + dialog.medium, .reveal-modal.medium { + margin-left: -30%; + width: 60%; + } +} + +@media only screen and (min-width: 40.063em) and (min-width: 40.063em) { + dialog.large, .reveal-modal.large { + margin-left: -35%; + width: 70%; + } +} + +@media only screen and (min-width: 40.063em) and (min-width: 40.063em) { + dialog.xlarge, .reveal-modal.xlarge { + margin-left: -47.5%; + width: 95%; + } +} + +@media only screen and (min-width: 40.063em) and (min-width: 40.063em) { + dialog.full, .reveal-modal.full { + margin-left: -50vw; + width: 100vw; + } +} + +@media print { + dialog, .reveal-modal { + background: white !important; + } +} + +.label { + font-weight: normal; + text-align: center; + text-decoration: none; + line-height: 1; + white-space: nowrap; + display: inline-block; + position: relative; + margin-bottom: inherit; + padding: 0.25rem 0.5rem 0.375rem; + font-size: 0.6875rem; + background-color: #2ba6cb; + color: white; + &.radius { + border-radius: 3px; + } + &.round { + border-radius: 1000px; + } + &.alert { + background-color: #c60f13; + color: white; + } + &.success { + background-color: #5da423; + color: white; + } + &.secondary { + background-color: #e9e9e9; + color: #333333; + } +} + +button, .button, input[type=button] { + cursor: pointer; + margin: 0 0 1.25rem; + border: none; + position: relative; + text-decoration: none; + text-align: center; + -webkit-appearance: none; + display: inline-block; + padding: 0.4rem 1.1rem; + font-size: 0.9rem; + background-color: #2ba6cb; + border-color: #2285a2; + color: white; + transition: background-color 150ms ease-out; + @include border-radius(2px); + &:hover, &:focus { + background-color: #2285a2; + outline: none; + color: white; + } + &.large { + padding-top: 1.125rem; + padding-right: 2.25rem; + padding-bottom: 1.1875rem; + padding-left: 2.25rem; + font-size: 1.25rem; + } + + &.small { + padding-top: 0.875rem; + padding-right: 1.75rem; + padding-bottom: 0.9375rem; + padding-left: 1.75rem; + font-size: 0.8125rem; + } + + &.tiny { + padding-top: 0.625rem; + padding-right: 1.25rem; + padding-bottom: 0.6875rem; + padding-left: 1.25rem; + font-size: 0.6875rem; + } + + &.expand { + padding-right: 0; + padding-left: 0; + width: 100%; + } + + &.left-align { + text-align: left; + text-indent: 0.75rem; + } + + &.right-align { + text-align: right; + padding-right: 0.75rem; + } + + &.round { + border-radius: 1000px; + } + + &.disabled, &[disabled] { + background-color: #2285a2; + border-color: #2285a2; + color: white; + cursor: default; + opacity: 0.5; + box-shadow: none; + &:hover, &:focus { + background-color: #2285a2; + opacity: 0.5; + } + } +} + + +@media only screen and (min-width: 40.063em) { + button, .button { + display: inline-block; + } +} + +.keystroke, kbd { + background-color: #ededed; + border-color: #dddddd; + color: #222222; + border-style: solid; + border-width: 1px; + margin: 0; + font-family: "Consolas", "Menlo", "Courier", monospace; + font-size: inherit; + padding: 0.125rem 0.25rem 0; + border-radius: 3px; +} + + + +/* We use this to get basic styling on all basic form elements */ +input[type="text"], +input[type="password"], +input[type="date"], +input[type="datetime"], +input[type="datetime-local"], +input[type="month"], +input[type="week"], +input[type="email"], +input[type="number"], +input[type="search"], +input[type="tel"], +input[type="time"], +input[type="url"], +textarea { + -webkit-appearance: none; + background-color: white; + font-family: inherit; + border: 1px solid #cccccc; + color: rgba(0, 0, 0, 0.75); + display: block; + font-size: 0.875rem; + margin: 0 0 1rem 0; + padding: 0.4rem; + width: 100%; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} + input[type="text"]:focus, + input[type="password"]:focus, + input[type="date"]:focus, + input[type="datetime"]:focus, + input[type="datetime-local"]:focus, + input[type="month"]:focus, + input[type="week"]:focus, + input[type="email"]:focus, + input[type="number"]:focus, + input[type="search"]:focus, + input[type="tel"]:focus, + input[type="time"]:focus, + input[type="url"]:focus, + textarea:focus {} + input[type="text"]:focus, + input[type="password"]:focus, + input[type="date"]:focus, + input[type="datetime"]:focus, + input[type="datetime-local"]:focus, + input[type="month"]:focus, + input[type="week"]:focus, + input[type="email"]:focus, + input[type="number"]:focus, + input[type="search"]:focus, + input[type="tel"]:focus, + input[type="time"]:focus, + input[type="url"]:focus, + textarea:focus { + background: #fafafa; + border-color: #999999; + outline: none; } + input[type="text"][disabled], fieldset[disabled] input[type="text"], + input[type="password"][disabled], fieldset[disabled] + input[type="password"], + input[type="date"][disabled], fieldset[disabled] + input[type="date"], + input[type="datetime"][disabled], fieldset[disabled] + input[type="datetime"], + input[type="datetime-local"][disabled], fieldset[disabled] + input[type="datetime-local"], + input[type="month"][disabled], fieldset[disabled] + input[type="month"], + input[type="week"][disabled], fieldset[disabled] + input[type="week"], + input[type="email"][disabled], fieldset[disabled] + input[type="email"], + input[type="number"][disabled], fieldset[disabled] + input[type="number"], + input[type="search"][disabled], fieldset[disabled] + input[type="search"], + input[type="tel"][disabled], fieldset[disabled] + input[type="tel"], + input[type="time"][disabled], fieldset[disabled] + input[type="time"], + input[type="url"][disabled], fieldset[disabled] + input[type="url"], + textarea[disabled], fieldset[disabled] + textarea { + background-color: #dddddd; } + input[type="text"].radius, + input[type="password"].radius, + input[type="date"].radius, + input[type="datetime"].radius, + input[type="datetime-local"].radius, + input[type="month"].radius, + input[type="week"].radius, + input[type="email"].radius, + input[type="number"].radius, + input[type="search"].radius, + input[type="tel"].radius, + input[type="time"].radius, + input[type="url"].radius, + textarea.radius { + border-radius: 3px; } + +input[type="submit"] { + -webkit-appearance: none; } + +/* Respect enforced amount of rows for textarea */ +textarea[rows] { + height: auto; } + +/* Add height value for select elements to match text input height */ +select { + -webkit-appearance: none !important; + background-color: #fafafa; + background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZlcnNpb249IjEuMSIgeD0iMHB4IiB5PSIwcHgiIHdpZHRoPSI2cHgiIGhlaWdodD0iM3B4IiB2aWV3Qm94PSIwIDAgNiAzIiBlbmFibGUtYmFja2dyb3VuZD0ibmV3IDAgMCA2IDMiIHhtbDpzcGFjZT0icHJlc2VydmUiPjxwb2x5Z29uIHBvaW50cz0iNS45OTIsMCAyLjk5MiwzIC0wLjAwOCwwICIvPjwvc3ZnPg=="); + background-repeat: no-repeat; + background-position: 97% center; + border: 1px solid #cccccc; + padding: 0.5rem; + font-size: 0.875rem; + color: rgba(0, 0, 0, 0.75); + line-height: normal; + border-radius: 0; +} + select.radius { + border-radius: 3px; } + select:hover { + background-color: #f3f3f3; + border-color: #999999; } + +/* Adjust margin for form elements below */ +input[type="file"], +input[type="checkbox"], +input[type="radio"], +select { + margin: 0 0 1rem 0; } + +input[type="checkbox"] + label, +input[type="radio"] + label { + display: inline-block; + + margin-left: 0.5rem; + margin-right: 1rem; + margin-bottom: 0; + vertical-align: baseline; } + +/* Normalize file input width */ +input[type="file"] { + width: 100%; } diff --git a/web-ui/app/scss/vendor/_reset.scss b/web-ui/app/scss/vendor/_reset.scss new file mode 100644 index 00000000..55f8d054 --- /dev/null +++ b/web-ui/app/scss/vendor/_reset.scss @@ -0,0 +1,421 @@ +/*! normalize.css v3.0.1 | MIT License | git.io/normalize */ + +/** + * 1. Set default font family to sans-serif. + * 2. Prevent iOS text size adjust after orientation change, without disabling + * user zoom. + */ + +html { + font-family: sans-serif; + /* 1 */ + -ms-text-size-adjust: 100%; + /* 2 */ + -webkit-text-size-adjust: 100%; + /* 2 */ +} + +/** + * Remove default margin. + */ + +body { + margin: 0; +} + +/* HTML5 display definitions + ========================================================================== */ + +/** + * Correct `block` display not defined for any HTML5 element in IE 8/9. + * Correct `block` display not defined for `details` or `summary` in IE 10/11 and Firefox. + * Correct `block` display not defined for `main` in IE 11. + */ + +article, aside, details, figcaption, figure, footer, header, hgroup, main, nav, section, summary { + display: block; +} + +/** + * 1. Correct `inline-block` display not defined in IE 8/9. + * 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera. + */ + +audio, canvas, progress, video { + display: inline-block; + /* 1 */ + vertical-align: baseline; + /* 2 */ +} + +/** + * Prevent modern browsers from displaying `audio` without controls. + * Remove excess height in iOS 5 devices. + */ + +audio:not([controls]) { + display: none; + height: 0; +} + +/** + * Address `[hidden]` styling not present in IE 8/9/10. + * Hide the `template` element in IE 8/9/11, Safari, and Firefox < 22. + */ + +[hidden], template { + display: none; +} + +/* Links + ========================================================================== */ + +/** + * Remove the gray background color from active links in IE 10. + */ + +a { + background: transparent; + &:active, &:hover { + outline: 0; + } +} + +/** + * Improve readability when focused and also mouse hovered in all browsers. + */ + +/* Text-level semantics + ========================================================================== */ + +/** + * Address styling not present in IE 8/9/10/11, Safari, and Chrome. + */ + +abbr[title] { + border-bottom: 1px dotted; +} + +/** + * Address style set to `bolder` in Firefox 4+, Safari, and Chrome. + */ + +b, strong { + font-weight: bold; +} + +/** + * Address styling not present in Safari and Chrome. + */ + +dfn { + font-style: italic; +} + +/** + * Address variable `h1` font-size and margin within `section` and `article` + * contexts in Firefox 4+, Safari, and Chrome. + */ + +h1 { + font-size: 2em; + margin: 0.67em 0; +} + +/** + * Address styling not present in IE 8/9. + */ + +mark { + background: #ff0; + color: #000; +} + +/** + * Address inconsistent and variable font size in all browsers. + */ + +small { + font-size: 80%; +} + +/** + * Prevent `sub` and `sup` affecting `line-height` in all browsers. + */ + +sub { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; +} + +sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; + top: -0.5em; +} + +sub { + bottom: -0.25em; +} + +/* Embedded content + ========================================================================== */ + +/** + * Remove border when inside `a` element in IE 8/9/10. + */ + +img { + border: 0; +} + +/** + * Correct overflow not hidden in IE 9/10/11. + */ + +svg:not(:root) { + overflow: hidden; +} + +/* Grouping content + ========================================================================== */ + +/** + * Address margin not present in IE 8/9 and Safari. + */ + +figure { + margin: 1em 40px; +} + +/** + * Address differences between Firefox and other browsers. + */ + +hr { + -moz-box-sizing: content-box; + box-sizing: content-box; + height: 0; +} + +/** + * Contain overflow in all browsers. + */ + +pre { + overflow: auto; +} + +/** + * Address odd `em`-unit font size rendering in all browsers. + */ + +code, kbd, pre, samp { + font-family: monospace, monospace; + font-size: 1em; +} + +/* Forms + ========================================================================== */ + +/** + * Known limitation: by default, Chrome and Safari on OS X allow very limited + * styling of `select`, unless a `border` property is set. + */ + +/** + * 1. Correct color not being inherited. + * Known issue: affects color of disabled elements. + * 2. Correct font properties not being inherited. + * 3. Address margins set differently in Firefox 4+, Safari, and Chrome. + */ + +button, input, optgroup, select, textarea { + color: inherit; + /* 1 */ + font: inherit; + /* 2 */ + margin: 0; + /* 3 */ +} + +/** + * Address `overflow` set to `hidden` in IE 8/9/10/11. + */ + +button { + overflow: visible; + text-transform: none; +} + +/** + * Address inconsistent `text-transform` inheritance for `button` and `select`. + * All other form control elements do not inherit `text-transform` values. + * Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera. + * Correct `select` style inheritance in Firefox. + */ + +select { + text-transform: none; +} + +/** + * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio` + * and `video` controls. + * 2. Correct inability to style clickable `input` types in iOS. + * 3. Improve usability and consistency of cursor style between image-type + * `input` and others. + */ + +button, html input[type="button"] { + -webkit-appearance: button; + /* 2 */ + cursor: pointer; + /* 3 */ +} + +input { + &[type="reset"], &[type="submit"] { + -webkit-appearance: button; + /* 2 */ + cursor: pointer; + /* 3 */ + } +} + +/** + * Re-set default cursor for disabled elements. + */ + +button[disabled], html input[disabled] { + cursor: default; +} + +/** + * Remove inner padding and border in Firefox 4+. + */ + +button::-moz-focus-inner { + border: 0; + padding: 0; +} + +input { + &::-moz-focus-inner { + border: 0; + padding: 0; + } + line-height: normal; + &[type="checkbox"], &[type="radio"] { + box-sizing: border-box; + /* 1 */ + padding: 0; + /* 2 */ + } + &[type="number"] { + &::-webkit-inner-spin-button, &::-webkit-outer-spin-button { + height: auto; + } + } + &[type="search"] { + -webkit-appearance: textfield; + /* 1 */ + -moz-box-sizing: content-box; + -webkit-box-sizing: content-box; + /* 2 */ + box-sizing: content-box; + &::-webkit-search-cancel-button, &::-webkit-search-decoration { + -webkit-appearance: none; + } + } +} + +/** + * Address Firefox 4+ setting `line-height` on `input` using `!important` in + * the UA stylesheet. + */ + +/** + * It's recommended that you don't attempt to style these elements. + * Firefox's implementation doesn't respect box-sizing, padding, or width. + * + * 1. Address box sizing set to `content-box` in IE 8/9/10. + * 2. Remove excess padding in IE 8/9/10. + */ + +/** + * Fix the cursor style for Chrome's increment/decrement buttons. For certain + * `font-size` values of the `input`, it causes the cursor style of the + * decrement button to change from `default` to `text`. + */ + +/** + * 1. Address `appearance` set to `searchfield` in Safari and Chrome. + * 2. Address `box-sizing` set to `border-box` in Safari and Chrome + * (include `-moz` to future-proof). + */ + +/** + * Remove inner padding and search cancel button in Safari and Chrome on OS X. + * Safari (but not Chrome) clips the cancel button when the search input has + * padding (and `textfield` appearance). + */ + +/** + * Define consistent border, margin, and padding. + */ + +fieldset { + border: 1px solid #c0c0c0; + margin: 0 2px; + padding: 0.35em 0.625em 0.75em; +} + +/** + * 1. Correct `color` not being inherited in IE 8/9/10/11. + * 2. Remove padding so people aren't caught out if they zero out fieldsets. + */ + +legend { + border: 0; + /* 1 */ + padding: 0; + /* 2 */ +} + +/** + * Remove default vertical scrollbar in IE 8/9/10/11. + */ + +textarea { + overflow: auto; +} + +/** + * Don't inherit the `font-weight` (applied by a rule above). + * NOTE: the default cannot safely be changed in Chrome and Safari on OS X. + */ + +optgroup { + font-weight: bold; +} + +/* Tables + ========================================================================== */ + +/** + * Remove most spacing between table cells. + */ + +table { + border-collapse: collapse; + border-spacing: 0; +} + +td, th { + padding: 0; +} diff --git a/web-ui/app/scss/views/_message-panel.scss b/web-ui/app/scss/views/_message-panel.scss new file mode 100644 index 00000000..4a0a7a6b --- /dev/null +++ b/web-ui/app/scss/views/_message-panel.scss @@ -0,0 +1,26 @@ +.message-panel { + width: 100%; + margin: 10px auto; + position: fixed; + z-index: 10000; + text-align: center; + + &__growl { + padding: 5px 60px; + + &--success { + background: $warning; + color: darken($warning, 50%); + border: 1px solid darken($warning, 10%); + @include box-shadow(1px 1px 3px darken($warning, 60%)); + } + + &--error { + font-weight: bold; + color: white; + background: $error; + border: 1px solid darken($error, 10%); + @include box-shadow(1px 1px 3px darken($error, 60%)); + } + } +} diff --git a/web-ui/app/templates/user_alerts/message.hbs b/web-ui/app/templates/user_alerts/message.hbs index 3a0055eb..abba1f91 100644 --- a/web-ui/app/templates/user_alerts/message.hbs +++ b/web-ui/app/templates/user_alerts/message.hbs @@ -1 +1 @@ -{{ message.content }} +{{ message.content }} -- cgit v1.2.3 From 3621742b1bbd5c96c10f15a66043bbec238ba7c1 Mon Sep 17 00:00:00 2001 From: Felix Hammerl Date: Mon, 7 Mar 2016 18:00:24 +0100 Subject: Issue #620: Remove former main css file --- web-ui/app/scss/_main.scss | 37 ------------------------------------- 1 file changed, 37 deletions(-) delete mode 100644 web-ui/app/scss/_main.scss diff --git a/web-ui/app/scss/_main.scss b/web-ui/app/scss/_main.scss deleted file mode 100644 index b582a5d5..00000000 --- a/web-ui/app/scss/_main.scss +++ /dev/null @@ -1,37 +0,0 @@ -@import "compass/css3"; -@import "reset"; -@import "foundation"; -@import "colors"; -@import "mixins"; -@import "alerts"; -@import "read"; -@import "reply"; -@import "compose"; -@import "security"; -@import "mascot"; -@import "styles"; - -html { - height:100%; -} -body { - min-height:100%; - overflow: hidden; - background: $white; -} -header#main { - overflow: hidden; - position: fixed; - top: 0; - width: 100%; - position: relative; - margin-bottom: 0; -} - -.no-padding { - padding: 0; -} - -.text-right { - text-align: right; -} -- cgit v1.2.3 From f4f41812b90edebfda97ade61269f44a3c00323b Mon Sep 17 00:00:00 2001 From: Felix Hammerl Date: Mon, 7 Mar 2016 18:05:29 +0100 Subject: Issue #620: Refactor palceholder --- web-ui/app/scss/_mascot.scss | 47 ---------------------- web-ui/app/scss/mixins/_position-helpers.scss | 9 +++++ web-ui/app/scss/style.scss | 12 +++--- .../scss/templates/_no-content-placeholder.scss | 5 +++ web-ui/app/scss/views/_no-mails-available.scss | 3 ++ web-ui/app/scss/views/_no-message-selected.scss | 14 +++++++ .../app/templates/compose/no_mails_available.hbs | 6 +-- .../app/templates/compose/no_message_selected.hbs | 4 +- 8 files changed, 42 insertions(+), 58 deletions(-) delete mode 100644 web-ui/app/scss/_mascot.scss create mode 100644 web-ui/app/scss/mixins/_position-helpers.scss create mode 100644 web-ui/app/scss/templates/_no-content-placeholder.scss create mode 100644 web-ui/app/scss/views/_no-mails-available.scss create mode 100644 web-ui/app/scss/views/_no-message-selected.scss diff --git a/web-ui/app/scss/_mascot.scss b/web-ui/app/scss/_mascot.scss deleted file mode 100644 index 74279063..00000000 --- a/web-ui/app/scss/_mascot.scss +++ /dev/null @@ -1,47 +0,0 @@ -#no-message-selected-pane { - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100vh; - - z-index: -100; - background: $contrast; - padding: 30px; - vertical-align:middle; - text-align:center; - -webkit-transform: translate3d(0, 0, 0); - &:before{ - content: ''; - display: inline-block; - height: 100%; - vertical-align: middle; - margin-right: -0.25em; - } - .scene{ - display:inline-block; - vertical-align:middle; - } - - .text{ - color:$medium_dark_grey; - margin-bottom: 40px; - } -} - -#no-mails-available-pane { - text-align: center; - line-height: 100vh; - margin-top: -130px; - - .scene{ - display:inline-block; - vertical-align:middle; - } - - .text{ - color:$medium_dark_grey; - margin-bottom: 40px; - } - -} diff --git a/web-ui/app/scss/mixins/_position-helpers.scss b/web-ui/app/scss/mixins/_position-helpers.scss new file mode 100644 index 00000000..254bfc6c --- /dev/null +++ b/web-ui/app/scss/mixins/_position-helpers.scss @@ -0,0 +1,9 @@ +@mixin absolute-center-unknown-height-width() { + margin: auto; + position: absolute; + left: 50%; + top: 50%; + -ms-transform: translate(-50%, -50%); + -webkit-transform: translate(-50%, -50%); + transform: translate(-50%, -50%); +} diff --git a/web-ui/app/scss/style.scss b/web-ui/app/scss/style.scss index eeadd662..d27b3031 100644 --- a/web-ui/app/scss/style.scss +++ b/web-ui/app/scss/style.scss @@ -8,26 +8,26 @@ @import "base/colors"; @import "base/scaffolding"; -// templates - - // mixins +@import "mixins/position-helpers"; @import "mixins"; +// templates +@import "templates/no-content-placeholder"; // layout @import "layout/message-panel"; -// modules +// views @import "views/message-panel"; - +@import "views/no-message-selected"; +@import "views/no-mails-available"; // misc stuff @import "others"; // TODO @import "compose"; -@import "mascot"; @import "read"; @import "reply"; @import "security"; diff --git a/web-ui/app/scss/templates/_no-content-placeholder.scss b/web-ui/app/scss/templates/_no-content-placeholder.scss new file mode 100644 index 00000000..c6807011 --- /dev/null +++ b/web-ui/app/scss/templates/_no-content-placeholder.scss @@ -0,0 +1,5 @@ +.no-content-placeholder { + @include absolute-center-unknown-height-width; + + color: $medium_dark_grey; +} diff --git a/web-ui/app/scss/views/_no-mails-available.scss b/web-ui/app/scss/views/_no-mails-available.scss new file mode 100644 index 00000000..bf5d256a --- /dev/null +++ b/web-ui/app/scss/views/_no-mails-available.scss @@ -0,0 +1,3 @@ +.no-mails-available-pane { + @extend .no-content-placeholder; +} diff --git a/web-ui/app/scss/views/_no-message-selected.scss b/web-ui/app/scss/views/_no-message-selected.scss new file mode 100644 index 00000000..0e367bf2 --- /dev/null +++ b/web-ui/app/scss/views/_no-message-selected.scss @@ -0,0 +1,14 @@ +.no-message-selected-pane { + background: $contrast; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + + &__text { + @extend .no-content-placeholder; + + margin-bottom: 40px; // aligns label with "no results for XYZ" + } +} diff --git a/web-ui/app/templates/compose/no_mails_available.hbs b/web-ui/app/templates/compose/no_mails_available.hbs index 6388d7db..147f3533 100644 --- a/web-ui/app/templates/compose/no_mails_available.hbs +++ b/web-ui/app/templates/compose/no_mails_available.hbs @@ -1,7 +1,7 @@ -
+
{{#if forSearch }} -
{{t 'NO RESULTS FOR'}}: '{{ forSearch }}'.
+ {{t 'NO RESULTS FOR'}}: '{{ forSearch }}'. {{else}} -
{{t 'NO EMAILS IN'}} '{{ tag }}'.
+ {{t 'NO EMAILS IN'}} '{{ tag }}'. {{/if}}
diff --git a/web-ui/app/templates/compose/no_message_selected.hbs b/web-ui/app/templates/compose/no_message_selected.hbs index 0442192d..71aa6267 100644 --- a/web-ui/app/templates/compose/no_message_selected.hbs +++ b/web-ui/app/templates/compose/no_message_selected.hbs @@ -1,3 +1,3 @@ -
-
{{t 'NOTHING SELECTED'}}.
+
+
{{t 'NOTHING SELECTED'}}.
-- cgit v1.2.3 From 62ff59cbbb2aa4c4af378b6d0fc9dd853c8867e3 Mon Sep 17 00:00:00 2001 From: Felix Hammerl Date: Wed, 9 Mar 2016 17:22:57 +0100 Subject: Issue #620: Adapt unit tests to CSS changes --- web-ui/test/spec/mail_view/ui/no_mails_available_pane.spec.js | 6 +++--- web-ui/test/spec/user_alerts/ui/user_alerts.spec.js | 6 ++---- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/web-ui/test/spec/mail_view/ui/no_mails_available_pane.spec.js b/web-ui/test/spec/mail_view/ui/no_mails_available_pane.spec.js index 157e6c47..1bf79b96 100644 --- a/web-ui/test/spec/mail_view/ui/no_mails_available_pane.spec.js +++ b/web-ui/test/spec/mail_view/ui/no_mails_available_pane.spec.js @@ -4,17 +4,17 @@ describeComponent('mail_view/ui/no_mails_available_pane', function () { describe('after initialization', function () { it('renders template', function () { this.setupComponent({tag: 'inbox'}); - expect(this.$node.html()).toMatch('
NO EMAILS IN \'INBOX\'.
'); + expect(this.$node.html()).toMatch('
\n NO EMAILS IN \'INBOX\'.\n
'); }); it('show different message for search with no results', function () { this.setupComponent({tag: 'all', forSearch: 'search'}); - expect(this.$node.html()).toMatch('
NO RESULTS FOR: \'SEARCH\'.
'); + expect(this.$node.html()).toMatch('
\n NO RESULTS FOR: \'SEARCH\'.\n
'); }); it('show only tag information when listing all mails', function () { this.setupComponent({tag: 'all', forSearch: 'in:all'}); - expect(this.$node.html()).toMatch('
NO EMAILS IN \'ALL\'.
'); + expect(this.$node.html()).toMatch('
\n NO EMAILS IN \'ALL\'.\n
'); }); }); }); diff --git a/web-ui/test/spec/user_alerts/ui/user_alerts.spec.js b/web-ui/test/spec/user_alerts/ui/user_alerts.spec.js index bde3b7fa..f15cda81 100644 --- a/web-ui/test/spec/user_alerts/ui/user_alerts.spec.js +++ b/web-ui/test/spec/user_alerts/ui/user_alerts.spec.js @@ -8,13 +8,13 @@ describeComponent('user_alerts/ui/user_alerts', function () { it('should render message when ui:user_alerts:displayMessage is triggered', function () { this.component.trigger(Pixelated.events.ui.userAlerts.displayMessage, { message: 'a message' }); - expect(this.component.$node.html()).toEqual('a message\n'); + expect(this.component.$node.html()).toEqual('a message\n'); }); it('should render error message', function () { this.component.trigger(Pixelated.events.ui.userAlerts.displayMessage, { message: 'send failed', class: 'error' }); - expect(this.component.$node.html()).toEqual('send failed\n'); + expect(this.component.$node.html()).toEqual('send failed\n'); }); it('should be emptied and hidden when hide is called', function() { @@ -24,6 +24,4 @@ describeComponent('user_alerts/ui/user_alerts', function () { expect(this.$node.html()).toEqual(''); }); - - }); -- cgit v1.2.3 From 0313e643e30cfe202a100a0b69e7ff3c3875fff5 Mon Sep 17 00:00:00 2001 From: Thais Siqueira Date: Fri, 11 Mar 2016 10:57:34 -0300 Subject: Update locust test to run after xsrf token implementation. - Adds port 8089 to vagrant file to be able to run inside vm. - Update requests version to 2.4.1, the minimum required version by locust. - Adds the xsrf token on locust post request headers. Issue #213 --- Vagrantfile | 1 + service/requirements.txt | 2 +- service/test/load/locustfile.py | 21 ++++++++++++++------- 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/Vagrantfile b/Vagrantfile index ba925079..828382b9 100644 --- a/Vagrantfile +++ b/Vagrantfile @@ -30,5 +30,6 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| config.vm.provider "virtualbox" do |v, override| v.memory = 1024 override.vm.network :forwarded_port, guest: 3333, host: 3333 # do NOT add host_ip in this line. It is not necessary + override.vm.network :forwarded_port, guest: 8089, host: 8089 end end diff --git a/service/requirements.txt b/service/requirements.txt index 95a0f4f8..7c9ee87c 100644 --- a/service/requirements.txt +++ b/service/requirements.txt @@ -4,7 +4,7 @@ https://launchpad.net/dirspec/stable-13-10/13.10/+download/dirspec-13.10.tar.gz --allow-external dirspec --allow-unverified dirspec https://launchpad.net/u1db/stable-13-10/13.10/+download/u1db-13.10.tar.bz2 pyasn1==0.1.8 -requests==2.0.0 +requests==2.4.1 srp==1.0.4 whoosh==2.5.7 pycryptopp diff --git a/service/test/load/locustfile.py b/service/test/load/locustfile.py index 68e39433..23142eee 100644 --- a/service/test/load/locustfile.py +++ b/service/test/load/locustfile.py @@ -1,6 +1,5 @@ import os import json -import time from random import randint from leap.auth import SRPAuth @@ -11,7 +10,7 @@ from pixelated.resources.login_resource import LoginResource LEAP_PROVIDER = os.environ.get('LEAP_PROVIDER', 'dev.pixelated-project.org') LEAP_SERVER_HOST = os.environ.get('LEAP_SERVER_HOST', 'https://api.%s:4430' % LEAP_PROVIDER) LEAP_VERIFY_CERTIFICATE = os.environ.get('LEAP_VERIFY_CERTIFICATE', '~/.leap/ca.crt') -MAX_NUMBER_USER = os.environ.get('MAX_NUMBER_USER', 10000) +MAX_NUMBER_USER = os.environ.get('MAX_NUMBER_USER', 100) INVITES_FILENAME = os.environ.get('INVITES_FILENAME', '/tmp/invite_codes.txt') INVITES_ENABLED = os.environ.get('INVITES_ENABLED', 'true') == 'true' @@ -23,6 +22,10 @@ def load_invite_from_number(number): class UserBehavior(TaskSet): + def __init__(self, *args, **kwargs): + super(UserBehavior, self).__init__(*args, **kwargs) + self.cookies = {} + def on_start(self): """ on_start is called when a Locust start before any task is scheduled """ self.login() @@ -40,9 +43,11 @@ class UserBehavior(TaskSet): def login(self): number = randint(1, int(MAX_NUMBER_USER)) username, password = self._get_or_create_user(number) - self.client.post("/%s" % LoginResource.BASE_URL, {"username": username, "password": password}) + response = self.client.post("/%s" % LoginResource.BASE_URL, {"username": username, "password": password}) + self.cookies.update(response.cookies.get_dict()) + resp = self.client.get("/") + self.cookies.update(resp.cookies.get_dict()) self.username = username - time.sleep(5) @task(1) def index(self): @@ -56,7 +61,9 @@ class UserBehavior(TaskSet): def send_mail(self): payload = {"tags": ["drafts"], "body": "some text lorem ipsum", "attachments": [], "ident": "", "header": {"to": ["%s@%s" % (self.username, LEAP_PROVIDER)], "cc": [], "bcc": [], "subject": "load testing"}} - with self.client.post('/mails', json=payload, catch_response=True) as email_response: + self.cookies.update(self.client.get("/").cookies.get_dict()) + print(self.cookies) + with self.client.post('/mails', json=payload, catch_response=True, cookies=self.cookies, headers={'X-Requested-With': 'XMLHttpRequest', 'X-XSRF-TOKEN':self.cookies['XSRF-TOKEN']}) as email_response: if email_response.status_code == 201: email_id = json.loads(email_response.content)['ident'] print email_id @@ -66,10 +73,10 @@ class UserBehavior(TaskSet): def delete_mail(self, ident): payload = {"idents": [ident]} - self.client.post('/mails/delete', json=payload) + self.client.post('/mails/delete', json=payload, cookies=self.cookies, headers={'X-Requested-With': 'XMLHttpRequest', 'X-XSRF-TOKEN':self.cookies['XSRF-TOKEN']}) class WebsiteUser(HttpLocust): task_set = UserBehavior - min_wait = 3000 + min_wait = 5000 max_wait = 15000 -- cgit v1.2.3 From 918ae543d94ea2c359c8608807fc251ac16ef1cc Mon Sep 17 00:00:00 2001 From: Thais Siqueira Date: Fri, 11 Mar 2016 14:46:06 -0300 Subject: Fixes pep8 errors and update requests to 2.9.1. Issue #213 --- service/requirements.txt | 2 +- service/test/load/locustfile.py | 63 ++++++++++++++++++++++++++++++++--------- 2 files changed, 50 insertions(+), 15 deletions(-) diff --git a/service/requirements.txt b/service/requirements.txt index 7c9ee87c..b74b7f94 100644 --- a/service/requirements.txt +++ b/service/requirements.txt @@ -4,7 +4,7 @@ https://launchpad.net/dirspec/stable-13-10/13.10/+download/dirspec-13.10.tar.gz --allow-external dirspec --allow-unverified dirspec https://launchpad.net/u1db/stable-13-10/13.10/+download/u1db-13.10.tar.bz2 pyasn1==0.1.8 -requests==2.4.1 +requests==2.9.1 srp==1.0.4 whoosh==2.5.7 pycryptopp diff --git a/service/test/load/locustfile.py b/service/test/load/locustfile.py index 23142eee..138f13db 100644 --- a/service/test/load/locustfile.py +++ b/service/test/load/locustfile.py @@ -8,8 +8,12 @@ from locust import HttpLocust, TaskSet, task from pixelated.resources.login_resource import LoginResource LEAP_PROVIDER = os.environ.get('LEAP_PROVIDER', 'dev.pixelated-project.org') -LEAP_SERVER_HOST = os.environ.get('LEAP_SERVER_HOST', 'https://api.%s:4430' % LEAP_PROVIDER) -LEAP_VERIFY_CERTIFICATE = os.environ.get('LEAP_VERIFY_CERTIFICATE', '~/.leap/ca.crt') +LEAP_SERVER_HOST = os.environ.get( + 'LEAP_SERVER_HOST', + 'https://api.%s:4430' % LEAP_PROVIDER) +LEAP_VERIFY_CERTIFICATE = os.environ.get( + 'LEAP_VERIFY_CERTIFICATE', + '~/.leap/ca.crt') MAX_NUMBER_USER = os.environ.get('MAX_NUMBER_USER', 100) INVITES_FILENAME = os.environ.get('INVITES_FILENAME', '/tmp/invite_codes.txt') INVITES_ENABLED = os.environ.get('INVITES_ENABLED', 'true') == 'true' @@ -23,27 +27,33 @@ def load_invite_from_number(number): class UserBehavior(TaskSet): def __init__(self, *args, **kwargs): - super(UserBehavior, self).__init__(*args, **kwargs) - self.cookies = {} + super(UserBehavior, self).__init__(*args, **kwargs) + self.cookies = {} def on_start(self): - """ on_start is called when a Locust start before any task is scheduled """ self.login() def _get_or_create_user(self, number): - srp_auth = SRPAuth(LEAP_SERVER_HOST, os.path.expanduser(LEAP_VERIFY_CERTIFICATE)) + srp_auth = SRPAuth( + LEAP_SERVER_HOST, + os.path.expanduser(LEAP_VERIFY_CERTIFICATE)) username, password = ('loadtest%d' % number), ('password_%d' % number) try: srp_auth.authenticate(username, password) except SRPAuthenticationError: - invite_code = load_invite_from_number(number) if INVITES_ENABLED else None + invite_code = None + if INVITES_ENABLED: + invite_code = load_invite_from_number(number) + srp_auth.register(username, password, invite_code) return username, password def login(self): number = randint(1, int(MAX_NUMBER_USER)) username, password = self._get_or_create_user(number) - response = self.client.post("/%s" % LoginResource.BASE_URL, {"username": username, "password": password}) + response = self.client.post( + "/%s" % LoginResource.BASE_URL, + {"username": username, "password": password}) self.cookies.update(response.cookies.get_dict()) resp = self.client.get("/") self.cookies.update(resp.cookies.get_dict()) @@ -59,21 +69,46 @@ class UserBehavior(TaskSet): @task(3) def send_mail(self): - payload = {"tags": ["drafts"], "body": "some text lorem ipsum", "attachments": [], "ident": "", - "header": {"to": ["%s@%s" % (self.username, LEAP_PROVIDER)], "cc": [], "bcc": [], "subject": "load testing"}} - self.cookies.update(self.client.get("/").cookies.get_dict()) + payload = { + "tags": ["drafts"], + "body": "some text lorem ipsum", + "attachments": [], + "ident": "", + "header": { + "to": ["%s@%s" % (self.username, LEAP_PROVIDER)], + "cc": [], + "bcc": [], + "subject": "load testing"}} + + self.cookies.update( + self.client.get("/").cookies.get_dict()) print(self.cookies) - with self.client.post('/mails', json=payload, catch_response=True, cookies=self.cookies, headers={'X-Requested-With': 'XMLHttpRequest', 'X-XSRF-TOKEN':self.cookies['XSRF-TOKEN']}) as email_response: + with self.client.post( + '/mails', + json=payload, + catch_response=True, + cookies=self.cookies, + headers={ + 'X-Requested-With': 'XMLHttpRequest', + 'X-XSRF-TOKEN': self.cookies['XSRF-TOKEN']}) as email_response: if email_response.status_code == 201: email_id = json.loads(email_response.content)['ident'] print email_id self.delete_mail(email_id) else: - email_response.failure('Error: email not Sent, status code: %s' % email_response.status_code) + email_response.failure( + 'Error: email not Sent, status code: %s' % ( + email_response.status_code)) def delete_mail(self, ident): payload = {"idents": [ident]} - self.client.post('/mails/delete', json=payload, cookies=self.cookies, headers={'X-Requested-With': 'XMLHttpRequest', 'X-XSRF-TOKEN':self.cookies['XSRF-TOKEN']}) + self.client.post( + '/mails/delete', + json=payload, + cookies=self.cookies, + headers={ + 'X-Requested-With': 'XMLHttpRequest', + 'X-XSRF-TOKEN': self.cookies['XSRF-TOKEN']}) class WebsiteUser(HttpLocust): -- cgit v1.2.3 From cf32471caf75b817b23339166002987726d3d6d8 Mon Sep 17 00:00:00 2001 From: Thais Siqueira Date: Fri, 11 Mar 2016 16:30:45 -0300 Subject: Sets SSL certifications to false. Issue #213 --- service/test/load/locustfile.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/service/test/load/locustfile.py b/service/test/load/locustfile.py index 138f13db..0c2ed518 100644 --- a/service/test/load/locustfile.py +++ b/service/test/load/locustfile.py @@ -53,19 +53,20 @@ class UserBehavior(TaskSet): username, password = self._get_or_create_user(number) response = self.client.post( "/%s" % LoginResource.BASE_URL, - {"username": username, "password": password}) + {"username": username, "password": password}, + verify=False) self.cookies.update(response.cookies.get_dict()) - resp = self.client.get("/") + resp = self.client.get("/", verify=False) self.cookies.update(resp.cookies.get_dict()) self.username = username @task(1) def index(self): - self.client.get("/") + self.client.get("/", verify=False) @task(2) def mail_box(self): - self.client.get("/mails?q=tag:'inbox'&p=1&w=25") + self.client.get("/mails?q=tag:'inbox'&p=1&w=25", verify=False) @task(3) def send_mail(self): @@ -81,7 +82,7 @@ class UserBehavior(TaskSet): "subject": "load testing"}} self.cookies.update( - self.client.get("/").cookies.get_dict()) + self.client.get("/", verify=False).cookies.get_dict()) print(self.cookies) with self.client.post( '/mails', @@ -106,6 +107,7 @@ class UserBehavior(TaskSet): '/mails/delete', json=payload, cookies=self.cookies, + verify=False, headers={ 'X-Requested-With': 'XMLHttpRequest', 'X-XSRF-TOKEN': self.cookies['XSRF-TOKEN']}) -- cgit v1.2.3