From 14678de8566a90c799f93fd2969ae7d08df11cfe Mon Sep 17 00:00:00 2001 From: agronkabashi Date: Fri, 5 Feb 2016 08:50:40 +0100 Subject: [PATCH 01/15] Added missing viewport meta --- src/index.html | 1 + 1 file changed, 1 insertion(+) diff --git a/src/index.html b/src/index.html index e3c39e6..74eac99 100644 --- a/src/index.html +++ b/src/index.html @@ -2,6 +2,7 @@ + From c9feddbd3bb20ec9d24d4fc10843caeb500e3ccf Mon Sep 17 00:00:00 2001 From: agronkabashi Date: Fri, 5 Feb 2016 08:52:39 +0100 Subject: [PATCH 02/15] Bumped angular version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index fde4d92..284ed66 100644 --- a/package.json +++ b/package.json @@ -45,7 +45,7 @@ }, "license": "MIT", "dependencies": { - "angular": "^1.4.8", + "angular": "^1.5.0-rc.0", "angular-sanitize": "^1.4.8", "angular-ui-router": "^0.2.15", "jquery": "^2.1.4", From 11a7843198b36ce5fb1ab188ac1990dc38b75ead Mon Sep 17 00:00:00 2001 From: agronkabashi Date: Fri, 5 Feb 2016 08:56:00 +0100 Subject: [PATCH 03/15] Code cleanup --- grunt-tasks/connect.js | 2 +- grunt-tasks/eslint.js | 2 +- src/templateeditor/css/_componentPlugins.scss | 1 - src/templateeditor/css/_components.scss | 9 +++++++++ src/templateeditor/directive/componentPlugins.js | 6 +++--- src/templateeditor/directive/componentProperties.js | 10 +++++++--- src/templateeditor/directive/componentSelection.js | 2 +- src/templateeditor/helper/templateEditor.js | 12 ++++++------ src/templateeditor/model/unit.js | 2 +- src/templateeditor/service/styleSetting.js | 11 ++++++----- src/templateengine/css/templateengine.scss | 9 +++++++++ src/templateengine/utility.js | 5 +++++ tests/templateengine/service/event.test.js | 4 ++-- 13 files changed, 51 insertions(+), 24 deletions(-) diff --git a/grunt-tasks/connect.js b/grunt-tasks/connect.js index d923177..ba34519 100644 --- a/grunt-tasks/connect.js +++ b/grunt-tasks/connect.js @@ -21,7 +21,7 @@ module.exports = function (grunt) { hostname: "localhost", livereload: false, open: true, - port: 9001, + port: 9000, base: "<%= config.dest %>", keepalive: true } diff --git a/grunt-tasks/eslint.js b/grunt-tasks/eslint.js index 98059b0..dea6f43 100644 --- a/grunt-tasks/eslint.js +++ b/grunt-tasks/eslint.js @@ -16,7 +16,7 @@ module.exports = function (grunt) { "browser", "jquery" ], - globals: ["angular", "tryParseInt"] + globals: ["angular", "tryParseInt", "tryParseFloat"] }, src: [ "src/**/*.js", diff --git a/src/templateeditor/css/_componentPlugins.scss b/src/templateeditor/css/_componentPlugins.scss index 9da561f..fb6b053 100644 --- a/src/templateeditor/css/_componentPlugins.scss +++ b/src/templateeditor/css/_componentPlugins.scss @@ -50,7 +50,6 @@ z-index: $layer-3; } - &:hover > img, &.ui-draggable-dragging { &::before { content: ""; diff --git a/src/templateeditor/css/_components.scss b/src/templateeditor/css/_components.scss index b81b573..b42f53b 100644 --- a/src/templateeditor/css/_components.scss +++ b/src/templateeditor/css/_components.scss @@ -6,6 +6,11 @@ pointer-events: none; } + // TODO: Outline when hovering a component + // &:hover { + // outline: solid 1px #bdbdbd; + // } + &:hover::before, &.ui-resizable-resizing::before { background-color: #eaeaea; @@ -43,4 +48,8 @@ &[friendly-name=""].ui-resizable-resizing::before { content: attr(component-name); } + + &[style*="overflow"] { + display: block; + } } diff --git a/src/templateeditor/directive/componentPlugins.js b/src/templateeditor/directive/componentPlugins.js index dd34435..8aca890 100644 --- a/src/templateeditor/directive/componentPlugins.js +++ b/src/templateeditor/directive/componentPlugins.js @@ -1,4 +1,4 @@ -(function (angular, $) { +(function (angular) { "use strict"; angular @@ -23,7 +23,7 @@ helper: "clone", cursorAt: cursorAt, start: function () { - var componentPluginElement = $(this); + var componentPluginElement = angular.element(this); componentPluginElement.data("component-plugin-info", { componentInfo: { componentType: componentPluginElement.attr("data-control-type"), @@ -58,4 +58,4 @@ }; } ]); -})(window.angular, window.jQuery); \ No newline at end of file +})(window.angular); \ No newline at end of file diff --git a/src/templateeditor/directive/componentProperties.js b/src/templateeditor/directive/componentProperties.js index 00d9960..0adff64 100644 --- a/src/templateeditor/directive/componentProperties.js +++ b/src/templateeditor/directive/componentProperties.js @@ -142,9 +142,13 @@ var viewPath = PathResolverService.resolve(String.format("view/componentEditor/{0}/{1}.html", component.category, component.name)); var componentEditoryId = String.format("Cerberus.TemplateEditor.Controller.ComponentEditor.{0}.{1}", _.capitalize(component.category), _.capitalize(component.name)); - $scope.editorController = $controller(componentEditoryId, { "$scope": $scope }); - $scope.editorViewPath = viewPath; - $scope.hasEditor = true; + // TODO: Find a better way of detecting if a component has an associated editor + try { + $scope.editorController = $controller(componentEditoryId, { "$scope": $scope }); + $scope.editorViewPath = viewPath; + $scope.hasEditor = true; + } + catch (e) { } } } } diff --git a/src/templateeditor/directive/componentSelection.js b/src/templateeditor/directive/componentSelection.js index 90b58e0..7f100a2 100644 --- a/src/templateeditor/directive/componentSelection.js +++ b/src/templateeditor/directive/componentSelection.js @@ -27,7 +27,7 @@ var clickedElement = angular.element(event.target); var elementTagName = event.target.tagName.toLowerCase(); - //Do not deselect components if the user is switching between resolutions + // Do not deselect components if the user is switching between resolutions if (clickedElement.hasClass("resolution")) { return; } diff --git a/src/templateeditor/helper/templateEditor.js b/src/templateeditor/helper/templateEditor.js index 493864d..b0e9c08 100644 --- a/src/templateeditor/helper/templateEditor.js +++ b/src/templateeditor/helper/templateEditor.js @@ -138,7 +138,7 @@ //Horizontal Positioning if (isHorizontalInPercent) { //Percentage based positioning - horizontal = tryParseInt(element.css("left")); + horizontal = tryParseFloat(element.css("left")); element.css("left", String.format("{0}%", (100.0 * horizontal / templateWidth).toFixed(1))); if (isTransposedHorizontal) { @@ -150,7 +150,7 @@ } else { //Pixel based positioning - value = tryParseInt(nativeElement.style.left); + value = tryParseFloat(nativeElement.style.left); nativeElement.style.left = value + "px"; if (isTransposedHorizontal) { @@ -164,7 +164,7 @@ //Vertical Positioning if (isVerticalInPercent) { //Percentage based positioning - vertical = tryParseInt(element.css("top")); + vertical = tryParseFloat(element.css("top")); element.css("top", String.format("{0}%", (100.0 * vertical / templateHeight).toFixed(1))); if (isTransposedVertical) { @@ -176,7 +176,7 @@ } else { //Pixel based positioning - value = tryParseInt(nativeElement.style.top); + value = tryParseFloat(nativeElement.style.top); nativeElement.style.top = value + "px"; if (isTransposedVertical) { @@ -201,12 +201,12 @@ //Dimensions if (isWidthInPercent) { - width = tryParseInt(element.css("width")); + width = tryParseFloat(element.css("width")); element.css("width", String.format("{0}%", (100.0 * width / templateWidth).toFixed(1))); } if (isHeightInPercent) { - height = tryParseInt(element.css("height")); + height = tryParseFloat(element.css("height")); element.css("height", String.format("{0}%", (100.0 * height / templateHeight).toFixed(1))); } } diff --git a/src/templateeditor/model/unit.js b/src/templateeditor/model/unit.js index f44b4cf..f3c2fc2 100644 --- a/src/templateeditor/model/unit.js +++ b/src/templateeditor/model/unit.js @@ -4,7 +4,7 @@ angular .module("Cerberus.ModelFactory") .registerModel("Cerberus.TemplateEditor.Model.Unit", function (value) { - this.value = parseInt(value); + this.value = parseFloat(value); this.unitType = undefined; if (isNaN(this.value)) { diff --git a/src/templateeditor/service/styleSetting.js b/src/templateeditor/service/styleSetting.js index b016147..b489005 100644 --- a/src/templateeditor/service/styleSetting.js +++ b/src/templateeditor/service/styleSetting.js @@ -25,15 +25,16 @@ { name: localization.componentProperties.browserDefault, value: undefined }, { name: "Arial", value: "Arial" }, { name: "Courier New", value: "Courier New" }, + { name: "Droid Sans", value: "Droid Sans" }, { name: "Impact", value: "Impact" }, { name: "Lucida Console", value: "Lucida Console" }, - { name: "Tahoma", value: "Tahoma" }, - { name: "Times New Roman", value: "Times New Roman" }, - { name: "Verdana", value: "Verdana" }, { name: "Roboto", value: "Roboto" }, { name: "Ropa Sans", value: "Ropa Sans" }, - { name: "Droid Sans", value: "Droid Sans" }, - { name: "Rouge Script", value: "Rouge Script" } + { name: "Rouge Script", value: "Rouge Script" }, + { name: "Sans-serif", value: "sans-serif" }, + { name: "Tahoma", value: "Tahoma" }, + { name: "Times New Roman", value: "Times New Roman" }, + { name: "Verdana", value: "Verdana" } ]; }; diff --git a/src/templateengine/css/templateengine.scss b/src/templateengine/css/templateengine.scss index 976d7ae..8fef75a 100644 --- a/src/templateengine/css/templateengine.scss +++ b/src/templateengine/css/templateengine.scss @@ -3,7 +3,16 @@ @import "component"; +html, +body { + height: 100%; + margin: 0; + padding: 0; +} + cs-template { display: block; position: relative; + + height: 100%; } diff --git a/src/templateengine/utility.js b/src/templateengine/utility.js index 4bf0c0c..3609c81 100644 --- a/src/templateengine/utility.js +++ b/src/templateengine/utility.js @@ -18,6 +18,11 @@ return isNaN(result) ? 0 : result; }; + window.tryParseFloat = function (value) { + var result = parseFloat(value); + return isNaN(result) ? 0 : result; + }; + /****************************************** JSON ******************************************/ diff --git a/tests/templateengine/service/event.test.js b/tests/templateengine/service/event.test.js index 563766d..15aabb3 100644 --- a/tests/templateengine/service/event.test.js +++ b/tests/templateengine/service/event.test.js @@ -29,7 +29,7 @@ describe("Cerberus.TemplateEngine.Service.Event", function () { describe("unSubscribe()", function () { it("should unsubscribe from an event registered with a specific callback method", function () { eventManager.subscribe("eventId", target.callback); - eventManager.unSubscribe("eventId", target.callback); + eventManager.unsubscribe("eventId", target.callback); expect(eventManager.hasEventsOfType("eventId")).toBeFalsy(); }); }); @@ -37,7 +37,7 @@ describe("Cerberus.TemplateEngine.Service.Event", function () { describe("unSubscribeAll()", function () { it("should unsubscribe from all events of a certain type", function () { eventManager.subscribe(["eventId", "eventId", "eventId"], target.callback); - eventManager.unSubscribe("eventId", target.callback); + eventManager.unsubscribe("eventId", target.callback); expect(eventManager.hasEventsOfType("eventId")).toBeFalsy(); }); }); From 223595272d40e9f3b33cd8ecff3aa68826ec613c Mon Sep 17 00:00:00 2001 From: agronkabashi Date: Fri, 5 Feb 2016 08:56:29 +0100 Subject: [PATCH 04/15] Added Gmail components, editors and apis --- grunt-tasks/watch.js | 2 +- src/demo.js | 7 +- src/template-presets.json | 65 ++++++ .../componentEditor/gmail/messageList.js | 14 ++ src/templateeditor/css/templateeditor.scss | 4 + .../directive/templateResolutions.js | 1 + src/templateeditor/localization/en-us.js | 39 ++-- .../componentEditor/gmail/messageList.html | 14 ++ .../view/componentProperties/generic.html | 10 +- .../view/componentProperties/layout.html | 9 + .../component/gmail/authorization.js | 53 +++++ .../controller/component/gmail/labelList.js | 35 +++ .../component/gmail/messageContent.js | 26 +++ .../controller/component/gmail/messageList.js | 45 ++++ src/templateengine/css/_component.scss | 6 +- src/templateengine/css/component/_gmail.scss | 169 ++++++++++++++ src/templateengine/filter/trustedHtml.js | 13 ++ .../model/component/gmail/messageList.js | 12 + src/templateengine/service/AsyncLoader.js | 16 ++ src/templateengine/service/event.js | 4 +- src/templateengine/service/google/api.js | 119 ++++++++++ src/templateengine/service/google/gmail.js | 221 ++++++++++++++++++ .../service/templateLocalStorageProvider.js | 28 +++ .../view/component/gmail/authorization.html | 13 ++ .../view/component/gmail/labelList.html | 6 + .../view/component/gmail/messageContent.html | 7 + .../view/component/gmail/messageList.html | 11 + 27 files changed, 917 insertions(+), 32 deletions(-) create mode 100644 src/templateeditor/controller/componentEditor/gmail/messageList.js create mode 100644 src/templateeditor/view/componentEditor/gmail/messageList.html create mode 100644 src/templateengine/controller/component/gmail/authorization.js create mode 100644 src/templateengine/controller/component/gmail/labelList.js create mode 100644 src/templateengine/controller/component/gmail/messageContent.js create mode 100644 src/templateengine/controller/component/gmail/messageList.js create mode 100644 src/templateengine/css/component/_gmail.scss create mode 100644 src/templateengine/filter/trustedHtml.js create mode 100644 src/templateengine/model/component/gmail/messageList.js create mode 100644 src/templateengine/service/AsyncLoader.js create mode 100644 src/templateengine/service/google/api.js create mode 100644 src/templateengine/service/google/gmail.js create mode 100644 src/templateengine/view/component/gmail/authorization.html create mode 100644 src/templateengine/view/component/gmail/labelList.html create mode 100644 src/templateengine/view/component/gmail/messageContent.html create mode 100644 src/templateengine/view/component/gmail/messageList.html diff --git a/grunt-tasks/watch.js b/grunt-tasks/watch.js index 5789f9b..c327e74 100644 --- a/grunt-tasks/watch.js +++ b/grunt-tasks/watch.js @@ -21,7 +21,7 @@ module.exports = function (grunt) { }, markup: { files: ["<%= config.src %>/**/*.html"], - tasks: ["concat", "ngtemplates"] + tasks: ["buildLibraries", "concat", "ngtemplates"] }, demoMarkup: { files: ["<%= config.src %>/*.html"], diff --git a/src/demo.js b/src/demo.js index c73876d..4848c8a 100644 --- a/src/demo.js +++ b/src/demo.js @@ -140,8 +140,13 @@ generatedCSS += String.format("@media(min-width:{0}px) and (max-width:{1}px){", previousResolution.resolutionValue + 1, resolution.resolutionValue); } + var isFixedHeight = false; _.forIn(resolution.componentVisualProperties, function (visualProperties, componentId) { - generatedCSS += String.format("#TC{0}{{1}}", componentId, visualProperties); + // Special case - Fixed height containers must be rendered as blocks + // to allow for scrollbars + isFixedHeight = visualProperties.indexOf("overflow:") >= 0; + + generatedCSS += String.format("#TC{0}{{1};{2}}", componentId, isFixedHeight ? "display:block" : "", visualProperties); }); generatedCSS += "}"; diff --git a/src/template-presets.json b/src/template-presets.json index af71511..5385701 100644 --- a/src/template-presets.json +++ b/src/template-presets.json @@ -271,6 +271,71 @@ ] } }, + { + "name": "Gmail", + "data": { + "name": "Gmail", + "id": 0, + "visualProperties": "", + "createdDateAsString": "", + "lastModifiedDateAsString": "", + "components": [ + { + "category": "gmail", + "class": "", + "content": { }, + "name": "labelList", + "componentType": "Cerberus.TemplateEngine.Controller.Component.Gmail.LabelList", + "friendlyName": "", + "id": 1, + "visualProperties": "" + }, + { + "category": "gmail", + "class": "", + "content": { }, + "name": "messageList", + "componentType": "Cerberus.TemplateEngine.Controller.Component.Gmail.MessageList", + "friendlyName": "", + "id": 2, + "visualProperties": "" + }, + { + "category": "gmail", + "class": "", + "content": { }, + "name": "messageContent", + "componentType": "Cerberus.TemplateEngine.Controller.Component.Gmail.MessageContent", + "friendlyName": "", + "id": 3, + "visualProperties": "" + } + , + { + "category": "gmail", + "class": "", + "content": { }, + "name": "authorization", + "componentType": "Cerberus.TemplateEngine.Controller.Component.Gmail.Authorization", + "friendlyName": "", + "id": 4, + "visualProperties": "" + } + ], + "resolutions": [ + { + "id": 0, + "resolutionValue": 10000, + "componentVisualProperties": { + "1": "left:0px;top:0px;width:300px;height:600px", + "2": "left:300px;top:0px;width:400px;height:300px", + "3": "left:300px;top:300px;width:400px;height:300px", + "4": "left:600px;top:0px;width:400px" + } + } + ] + } + }, { "name": "Sample Start Page", "data": { diff --git a/src/templateeditor/controller/componentEditor/gmail/messageList.js b/src/templateeditor/controller/componentEditor/gmail/messageList.js new file mode 100644 index 0000000..24f4479 --- /dev/null +++ b/src/templateeditor/controller/componentEditor/gmail/messageList.js @@ -0,0 +1,14 @@ +(function (angular) { + "use strict"; + + angular + .module("Cerberus.TemplateEditor") + .controller("Cerberus.TemplateEditor.Controller.ComponentEditor.Gmail.MessageList", [ + "$scope", + MessageListEditorController + ]); + + function MessageListEditorController($scope) { + + } +})(window.angular); \ No newline at end of file diff --git a/src/templateeditor/css/templateeditor.scss b/src/templateeditor/css/templateeditor.scss index 719799a..b181238 100644 --- a/src/templateeditor/css/templateeditor.scss +++ b/src/templateeditor/css/templateeditor.scss @@ -108,4 +108,8 @@ cs-template.animatable > cs-component { opacity: 0.5; z-index: $layer-2; } +} + +.edit-design cs-component.authorization .authorizeContainer { + display: none; } \ No newline at end of file diff --git a/src/templateeditor/directive/templateResolutions.js b/src/templateeditor/directive/templateResolutions.js index 024b2ee..d281ec8 100644 --- a/src/templateeditor/directive/templateResolutions.js +++ b/src/templateeditor/directive/templateResolutions.js @@ -111,6 +111,7 @@ if ($scope.currentResolution) { EventService.notify("ResolutionSelected", $scope.currentResolution.resolutionValue); + $scope.setDocumentWidth($scope.currentResolution.resolutionValue, $scope.currentResolution); } }, diff --git a/src/templateeditor/localization/en-us.js b/src/templateeditor/localization/en-us.js index 8c7398a..a10bfe8 100644 --- a/src/templateeditor/localization/en-us.js +++ b/src/templateeditor/localization/en-us.js @@ -44,7 +44,7 @@ componentProperties: { class: "Class", visible: "Visible", - render: "Render", + renderAs: "Render", hidden: "Hidden", generic: "Generic", zIndex: "Render Order", @@ -130,18 +130,18 @@ componentPluginNames: { text: "Text", link: "Link", - menu: "Menu", sharer: "Sharer", - tableOfContents: "Table of Contents", youTube: "YouTube", rtf: "Rich Text Format", rss: "RSS", - articleList: "Article List", video: "Video", - carousel: "Carousel", - album: "Album" + labelList: "Gmail Labels", + messageList: "Gmail Messages", + messageContent: "Gmail Message", + authorization: "Gmail Authorization Handler" }, + // Editor localizations for the components component: { link: { text: "Content", @@ -156,6 +156,22 @@ textPlaceHolder: "Enter text", urlPlaceHolder: "Enter a link to navigate to" }, + messageLink: { + emptyMessagePlaceHolder: "Text to show when there are no messages", + loadingClass: "CSS class to apply when fetching messages", + loadingPlaceHolder: "Text to show when fetching messages" + }, + rss: { + url: "Url", + showTitle: "Title", + showDescription: "Description", + showStoryDescription: "Story Description", + showStoryDate: "Story Date", + maxStories: "Max Stories" + }, + tableOfContents: { + source: "Source" + }, video: { mp4Source: "MP4 Source", oggSource: "Ogg Source", @@ -173,17 +189,6 @@ disableKeyboard: "Disable keyboard shortcuts", hideYouTubeBrand: "Hide YouTube Brand", showInfo: "Show Video Info" - }, - tableOfContents: { - source: "Source" - }, - rss: { - url: "Url", - showTitle: "Title", - showDescription: "Description", - showStoryDescription: "Story Description", - showStoryDate: "Story Date", - maxStories: "Max Stories" } } }; diff --git a/src/templateeditor/view/componentEditor/gmail/messageList.html b/src/templateeditor/view/componentEditor/gmail/messageList.html new file mode 100644 index 0000000..26bce47 --- /dev/null +++ b/src/templateeditor/view/componentEditor/gmail/messageList.html @@ -0,0 +1,14 @@ +
+ + +
+ +
+ + +
+ +
+ + +
\ No newline at end of file diff --git a/src/templateeditor/view/componentProperties/generic.html b/src/templateeditor/view/componentProperties/generic.html index 73954dd..451389f 100644 --- a/src/templateeditor/view/componentProperties/generic.html +++ b/src/templateeditor/view/componentProperties/generic.html @@ -8,12 +8,10 @@ -
+
+ + + -
- -
- -
\ No newline at end of file diff --git a/src/templateeditor/view/componentProperties/layout.html b/src/templateeditor/view/componentProperties/layout.html index 4fa8ca3..48809ae 100644 --- a/src/templateeditor/view/componentProperties/layout.html +++ b/src/templateeditor/view/componentProperties/layout.html @@ -20,4 +20,13 @@ +
+ + +
+ +
\ No newline at end of file diff --git a/src/templateengine/controller/component/gmail/authorization.js b/src/templateengine/controller/component/gmail/authorization.js new file mode 100644 index 0000000..8cc8794 --- /dev/null +++ b/src/templateengine/controller/component/gmail/authorization.js @@ -0,0 +1,53 @@ +(function (angular) { + "use strict"; + + angular + .module("Cerberus.TemplateEngine") + .controller("Cerberus.TemplateEngine.Controller.Component.Gmail.Authorization", [ + "$scope", + "Cerberus.TemplateEngine.Service.Event", + "Cerberus.TemplateEngine.Service.Gmail", + AuthorizationController + ]); + + function AuthorizationController($scope, EventService, GmailService) { + var hasBeenLoggedInOnce = false; + refresh(); + + EventService.subscribe(["Gmail.Reauthorized", "Gmail.RequestFailed"], refresh); + + $scope.authorize = function () { + GmailService.authorizeUser(); + }; + + $scope.$on("$destroy", function () { + EventService.unsubscribe("Gmail.Reauthorized", refresh); + EventService.unsubscribe("Gmail.RequestFailed", refresh); + }); + + function refresh() { + GmailService.whenIsAuthorized() + .then(function () { + hasBeenLoggedInOnce = true; + $scope.authorizationFailed = false; + }) + .catch(function (error) { + $scope.authorizationFailed = true; + setErrorMessage(error) + }); + } + + function setErrorMessage(error) { + var status = error.status; + $scope.isAuthorizationError = false; + + if (status <= 0) { + $scope.message = "There seems to be a problem with your internet connection."; + } + else if (status >= 400 && status < 500) { + $scope.isAuthorizationError = true; + $scope.message = hasBeenLoggedInOnce ? "You seem to have been logged out due to inactivity." : "You need to be signed in to use Gmail features."; + } + } + } +})(window.angular); \ No newline at end of file diff --git a/src/templateengine/controller/component/gmail/labelList.js b/src/templateengine/controller/component/gmail/labelList.js new file mode 100644 index 0000000..b29a5b3 --- /dev/null +++ b/src/templateengine/controller/component/gmail/labelList.js @@ -0,0 +1,35 @@ +(function (angular) { + "use strict"; + + angular + .module("Cerberus.TemplateEngine") + .controller("Cerberus.TemplateEngine.Controller.Component.Gmail.LabelList", [ + "$scope", + "Cerberus.TemplateEngine.Constant.Gmail.Labels", + "Cerberus.TemplateEngine.Service.Event", + "Cerberus.TemplateEngine.Service.Gmail", + LabelListController + ]); + + function LabelListController($scope, labels, EventService, GmailService) { + refreshLabels(); + + $scope.selectedLabelId = labels.INBOX; + $scope.onClickLabel = function (label) { + $scope.selectedLabelId = label.id; + EventService.notify("Gmail.ViewLabel", label); + }; + + EventService.subscribe("Gmail.Reauthorized", refreshLabels); + + $scope.$on("$destroy", function () { + EventService.unsubscribe("Gmail.Reauthorized", refreshLabels); + }); + + function refreshLabels() { + GmailService.getUserLabels().then(function (userLabels) { + $scope.labels = GmailService.getSystemLabels().concat(userLabels); + }); + } + } +})(window.angular); \ No newline at end of file diff --git a/src/templateengine/controller/component/gmail/messageContent.js b/src/templateengine/controller/component/gmail/messageContent.js new file mode 100644 index 0000000..44e053e --- /dev/null +++ b/src/templateengine/controller/component/gmail/messageContent.js @@ -0,0 +1,26 @@ +(function (angular) { + "use strict"; + + angular + .module("Cerberus.TemplateEngine") + .controller("Cerberus.TemplateEngine.Controller.Component.Gmail.MessageContent", [ + "$scope", + "Cerberus.TemplateEngine.Service.Event", + "Cerberus.TemplateEngine.Service.Gmail", + MessageContentController + ]); + + function MessageContentController($scope, EventService, GmailService) { + EventService.subscribe("Gmail.ViewMessage", onViewMessage); + + $scope.$on("$destroy", function () { + EventService.unsubscribe("Gmail.ViewMessage", onViewMessage); + }); + + function onViewMessage(messageId) { + GmailService.getMessage(messageId).then(function (message) { + $scope.message = message; + }); + } + } +})(window.angular); \ No newline at end of file diff --git a/src/templateengine/controller/component/gmail/messageList.js b/src/templateengine/controller/component/gmail/messageList.js new file mode 100644 index 0000000..e2045bb --- /dev/null +++ b/src/templateengine/controller/component/gmail/messageList.js @@ -0,0 +1,45 @@ +(function (angular) { + "use strict"; + + angular + .module("Cerberus.TemplateEngine") + .controller("Cerberus.TemplateEngine.Controller.Component.Gmail.MessageList", [ + "$scope", + "Cerberus.TemplateEngine.Constant.Gmail.Labels", + "Cerberus.TemplateEngine.Service.Event", + "Cerberus.TemplateEngine.Service.Gmail", + MessageListController + ]); + + function MessageListController($scope, labels, EventService, GmailService) { + refreshMessages(labels.INBOX); + + EventService.subscribe("Gmail.ViewLabel", onViewLabel); + EventService.subscribe("Gmail.Reauthorized", refreshMessages); + + $scope.onClickMessage = function (message) { + EventService.notify("Gmail.ViewMessage", message.id); + }; + + $scope.$on("$destroy", function () { + EventService.unsubscribe("Gmail.Reauthorized", refreshMessages); + EventService.unsubscribe("Gmail.ViewLabel", onViewLabel); + }); + + function refreshMessages(labelId) { + $scope.isLoading = true; + GmailService.getMessages(labelId) + .then(function (messages) { + $scope.isLoading = false; + $scope.messages = messages; + }) + .catch(function () { + $scope.isLoading = false; + }); + } + + function onViewLabel(label) { + refreshMessages(label.id); + } + } +})(window.angular); \ No newline at end of file diff --git a/src/templateengine/css/_component.scss b/src/templateengine/css/_component.scss index 25b1817..f151404 100644 --- a/src/templateengine/css/_component.scss +++ b/src/templateengine/css/_component.scss @@ -4,6 +4,7 @@ @import "component/sharer"; @import "component/video"; @import "component/youTube"; +@import "component/gmail"; cs-component { @include transform-origin(top left); @@ -24,9 +25,4 @@ cs-component { width: 100%; text-decoration: inherit; }*/ - - /*&[style*="overflow"] > div:first-child { - overflow: auto; - display: block; - }*/ } diff --git a/src/templateengine/css/component/_gmail.scss b/src/templateengine/css/component/_gmail.scss new file mode 100644 index 0000000..50343d6 --- /dev/null +++ b/src/templateengine/css/component/_gmail.scss @@ -0,0 +1,169 @@ +/** + Components: + LabelList + MessageList + Message + Authorization +*/ +cs-component.labellist > ul, +cs-component.messagelist > ul { + list-style: none; + margin: 0; + padding: 0; + + li { + cursor: pointer; + } +} + +cs-component.labellist > ul { + li { + &:hover { + background-color: silver; + } + } + + .selected { + color: #dd4b39; + } +} + +cs-component.messagelist { + > ul { + height: inherit; + + &.loading::before { + @include transform(translateX(-50%)); + background-color: #f9edbe; + border: rem(1) solid #f0c36d; + border-radius: rem(2); + box-shadow: 0 rem(2) rem(4) rgba(0,0,0,0.2); + content: attr(loading); + padding: rem(6) rem(10); + position: absolute; + text-align: center; + margin: 0 auto; + left: 50%; + } + } + + li { + @include display(flex); + + .avatar { + @include flex-grow(1); + min-width: rem(22); + max-width: rem(72); + + &::before { + background-color: beige; // TODO + border-radius: 50%; + content: ""; + display: block; + margin-top: rem(16); + padding-top: 75%; + width: 75%; + } + } + + .meta-info { + @include flex-grow(0); + border-top: rem(1) solid #bdbdbd; + padding-top: rem(16); + width: 87%; + } + + &:first-child .meta-info { + border-top: none; + } + + } + + .from { + display: block; + font-weight: bolder; + } + + .subject { + color: silver; + display: block; + } +} + +cs-component.messagecontent { + .subject { + margin: 0; + } + + .from, + .to, + .date { + display: block; + } +} + +cs-component.authorization { + .authorizeContainer { + background-color: rgba(0, 0, 0, 0.3); + height: 100%; + left: 0; + position: fixed; + text-align: center; + top: 0; + width: 100%; + } + + .authorizeDialog { + @include transform(translateY(-50%)); + + background-color: white; + border: 1px solid #bdbdbd; + border-radius: 5px; + box-shadow: 0 3px 3px 0 rgba(0,0,0,0.2); + display: inline-block; + margin: auto; + padding: 1rem; + position: relative; + top: 50%; + } + + .info { + display: block; + margin-bottom: 1rem; + } + + button { + background-color: #df4a32; + border: none; + border-radius: rem(2); + box-shadow: 0 rem(3) rem(3) 0 rgba(0, 0, 0, 0.1); + color: #fff; + cursor: pointer; + display: block; + height: rem(40); + margin: auto; + padding: 0 rem(8); + position: relative; + + &::before { + border-left: rem(1) solid #be3f2b; + content: ""; + height: inherit; + left: rem(42); + position: absolute; + top: 0; + } + + span, + svg { + display: inline-block; + vertical-align: middle; + color: white; + fill: currentColor; + } + + span { + margin-left: rem(16); + } + } +} \ No newline at end of file diff --git a/src/templateengine/filter/trustedHtml.js b/src/templateengine/filter/trustedHtml.js new file mode 100644 index 0000000..0b4ef9e --- /dev/null +++ b/src/templateengine/filter/trustedHtml.js @@ -0,0 +1,13 @@ +(function (angular) { + "use strict"; + + angular.module("Cerberus.TemplateEngine") + .filter("trustedHtml", [ + "$sce", + function ($sce) { + return function (html) { + return $sce.trustAsHtml(html); + }; + } + ]); +})(window.angular); \ No newline at end of file diff --git a/src/templateengine/model/component/gmail/messageList.js b/src/templateengine/model/component/gmail/messageList.js new file mode 100644 index 0000000..deb5663 --- /dev/null +++ b/src/templateengine/model/component/gmail/messageList.js @@ -0,0 +1,12 @@ +(function (angular) { + "use strict"; + + angular + .module("Cerberus.ModelFactory") + .registerModel("Cerberus.TemplateEngine.Model.Component.Gmail.MessageList", function () { + this.localization = { + emptyList: "", + loading: "" + }; + }); +})(window.angular); \ No newline at end of file diff --git a/src/templateengine/service/AsyncLoader.js b/src/templateengine/service/AsyncLoader.js new file mode 100644 index 0000000..6079239 --- /dev/null +++ b/src/templateengine/service/AsyncLoader.js @@ -0,0 +1,16 @@ +(function (angular) { + "use strict"; + + angular.module("Cerberus.TemplateEngine") + .service("Cerberus.TemplateEngine.Service.AsyncLoader", [AsyncLoaderService]); + + function AsyncLoaderService() { + this.load = function (src, successCallback, errorCallback) { + var script = document.createElement("script"); + script.onload = script.onreadystatechanged = successCallback; + script.onerror = errorCallback; + script.src = src; + document.head.appendChild(script); + }; + } +})(window.angular); \ No newline at end of file diff --git a/src/templateengine/service/event.js b/src/templateengine/service/event.js index 6c8084b..3071f08 100644 --- a/src/templateengine/service/event.js +++ b/src/templateengine/service/event.js @@ -29,7 +29,7 @@ }); }; - this.unSubscribe = function (eventType, callback) { + this.unsubscribe = function (eventType, callback) { var eventCollection = events[eventType]; if (!eventCollection) { return; @@ -44,7 +44,7 @@ } }; - this.unSubscribeAll = function (eventType) { + this.unsubscribeAll = function (eventType) { delete events[eventType]; }; diff --git a/src/templateengine/service/google/api.js b/src/templateengine/service/google/api.js new file mode 100644 index 0000000..40d8402 --- /dev/null +++ b/src/templateengine/service/google/api.js @@ -0,0 +1,119 @@ +(function (angular) { + "use strict"; + + angular.module("Cerberus.TemplateEngine") + .service("Google.API", [ + "$q", + "Cerberus.TemplateEngine.Service.AsyncLoader", + function ($q, AsyncLoaderService) { + var apiUrl = "https://apis.google.com/js/client.js?onload=googleApiLoaderHook"; + var isAuthorized = $q.defer(); + var isReady = $q.defer(); + + // Global hook for the Google API loaded event + window.googleApiLoaderHook = function () { + isReady.resolve(); + + // Since the client library has been loaded we no longer need the global hook + delete window.googleApiLoaderHook; + }; + + // Authorizes the user by calling the Google API + this.authorize = function (options) { + if (options.reissuePromise) { + isAuthorized.reject(); + isAuthorized = $q.defer(); + } + + window.gapi.auth.authorize({ + client_id: options.clientId, + scope: options.scopes, + immediate: options.immediate + }, onAuthorize); + }; + + // Prepares a batch of Google API requests + this.createBatch = function () { + return window.gapi.client.newBatch(); + }; + + this.request = function (path, options) { + options = options || {}; + var apiRequest = window.gapi.client.request({ + path: path, + method: options.body ? "POST" : "GET", + params: options.params, + body: options.body + }); + + // We can't attach an error handler for the request + // if it is part of a batch. The .then method triggers + // an actual request. An error handler is attached + // to the batch request instead + if (!options.isBatchRequest) { + apiRequest.then(null, onRequestFailed); + } + + return apiRequest; + }; + + // Reports whether the API is loaded or not + this.whenIsReady = function () { + return isReady.promise; + }; + + // Puts the service in an unauthorized state + this.dropAuthorization = function () { + isAuthorized && isAuthorized.reject(); + isAuthorized = $q.defer(); + isAuthorized.reject({ + status: 401, + statusText: "Authorization failed. Could not authorize user." + }); + }; + + // Used for determining when the API is loaded and the user is authorized + this.whenIsAuthorized = function () { + return isAuthorized.promise; + }; + + // Load the Google API + AsyncLoaderService.load(apiUrl, null, function () { + isReady.reject({ + status: -1, + statusMessage: "Network unavailable. Check your internet connection." + }); + }); + + // Callback method for handling the authorization result + function onAuthorize(result) { + if (result && !result.error) { + isAuthorized.resolve(window.gapi); + } + else { + isAuthorized.reject({ + status: 401, + statusText: "Authorization failed. Could not authorize user." + }); + } + } + + function onRequestFailed(response) { + var status = response.result.error.code; + var statusMessage = response.result.error.message; + + // Since we want to pass on the error to the caller without exposing + // the raw response we mutate it by clearing and reforming it to our + // structure + Object.getOwnPropertyNames(response).forEach(function (propertyName) { + delete response[propertyName]; + }); + + angular.extend(response, { + status: status, + statusMessage: statusMessage + }); + } + } + ]); +})(window.angular); \ No newline at end of file diff --git a/src/templateengine/service/google/gmail.js b/src/templateengine/service/google/gmail.js new file mode 100644 index 0000000..37630a0 --- /dev/null +++ b/src/templateengine/service/google/gmail.js @@ -0,0 +1,221 @@ +(function (angular, _) { + "use strict"; + + var clientId = "847658075745-leq2ks7v2ambuq8tj18v4c7qpkg17mln.apps.googleusercontent.com"; + var scopes = [ + "https://www.googleapis.com/auth/gmail.readonly" + ]; + + angular.module("Cerberus.TemplateEngine") + .constant("Cerberus.TemplateEngine.Constant.Gmail.Labels", { + INBOX: "INBOX", + SENT: "SENT", + DRAFT: "DRAFT", + TRASH: "TRASH" + }) + .service("Cerberus.TemplateEngine.Service.Gmail", [ + "$q", + "Cerberus.TemplateEngine.Constant.Gmail.Labels", + "Google.API", + "Cerberus.TemplateEngine.Service.Event", + function ($q, labels, GoogleApiService, EventService) { + // Let the API know what scopes we need for using the GMAIL features + GoogleApiService.whenIsReady().then(function () { + GoogleApiService.authorize({ + clientId: clientId, + scopes: scopes, + immediate: true + }); + }); + + this.authorizeUser = function () { + GoogleApiService.authorize({ + clientId: clientId, + scopes: scopes, + reissuePromise: true + }); + + GoogleApiService.whenIsAuthorized() + .then(function () { + EventService.notify("Gmail.Reauthorized"); + }, onRequestFailed); + }; + + this.getSystemLabels = function () { + return [ + { + id: labels.INBOX, + name: "Inbox" + }, + { + id: labels.SENT, + name: "Sent" + }, + { + id: labels.DRAFT, + name: "Draft" + }, + { + id: labels.TRASH, + name: "Trash" + }]; + }; + + this.getUserLabels = function () { + return this.whenIsAuthorized().then(function () { + return GoogleApiService + .request("/gmail/v1/users/me/labels") + .then(function (response) { + // Filter out labels that are not visible + return _.filter(response.result.labels, function (label) { + return label.type === "user" && + (label.labelListVisibility === undefined || + label.labelListVisibility === "labelShow"); + }); + }, onRequestFailed); + }); + }; + + this.getMessage = function (messageId) { + return this.whenIsAuthorized().then(function () { + return GoogleApiService + .request("/gmail/v1/users/me/messages/" + messageId, { + params: { + format: "full" + } + }) + .then(function (response) { + return getMessageDetails(response.result.id, response.result.payload); + }, onRequestFailed); + }); + }; + + this.getMessages = function (labelIds, options) { + options = options || {}; + return this.whenIsAuthorized().then(function () { + return GoogleApiService + .request("/gmail/v1/users/me/messages", { + params: { + labelIds: labelIds, + maxResults: options.maxResults, + pageToken: options.pageToken, + query: options.query + } + }) + .then(batchMessageFetch, onRequestFailed); + }); + }; + + this.whenIsAuthorized = function () { + return $q.all([GoogleApiService.whenIsReady(), GoogleApiService.whenIsAuthorized()]); + }; + + // Batches several message requests into one + function batchMessageFetch(response) { + var messages = response.result.messages; + if (response.result.resultSizeEstimate === 0) { + return []; + } + + var batch = GoogleApiService.createBatch(); + var messageParams = { + isBatchRequest: true, + params: { + format: "metadata" + } + }; + + messages.forEach(function (message) { + batch.add(GoogleApiService.request("/gmail/v1/users/me/messages/" + message.id, messageParams), { id: message.id }); + }); + + return batch.then(function (batchResponse) { + var batchMessages = []; + for (var i in batchResponse.result) { + batchMessages.push(getMessageDetails(i, batchResponse.result[i].result.payload)); + } + + return batchMessages; + }); + } + + function onRequestFailed(error) { + GoogleApiService.dropAuthorization(); + EventService.notify("Gmail.RequestFailed", error); + } + + function getMessageDetails(messageId, payload) { + var message = { + id: messageId, + plainText: "", + htmlText: "" + }; + + var i; + if (payload.parts) { + for (i = 0; i < payload.parts.length; i++) { + if (payload.parts[i].mimeType === "text/plain") { + message.plainText += payload.parts[i].body.data; + } + + if (payload.parts[i].mimeType === "text/html") { + message.htmlText += payload.parts[i].body.data; + } + } + } + else if (payload.body) { + message.htmlText = payload.body.data; + } + + if (message.htmlText) { + message.htmlText = message.htmlText.replace(/-/g, "+").replace(/_/g, "/"); + message.htmlText = decodeURIComponent(escape(window.atob(message.htmlText))); + var contentStartIndex = message.htmlText.indexOf("= 0) { + contentStartIndex += 5; + message.htmlText = ""; + } + } + + var header; + var emailInfo; + for (i = 0; i < payload.headers.length; i++) { + header = payload.headers[i]; + + switch (header.name) { + case "Subject": + message.subject = header.value; + break; + + case "Received": + message.received = header.value; + break; + + case "Date": + message.date = new Date(header.value).toLocaleString(); + break; + + case "From": + message.from = parseEmailInfo(header.value); + break; + + case "To": + message.to = parseEmailInfo(header.value); + break; + } + } + + return message; + } + + function parseEmailInfo(emailString) { + var leftTagIndex = emailString.indexOf("<"); + return { + address: emailString.substring(leftTagIndex, emailString.length - 1), + name: emailString.substring(0, leftTagIndex) + }; + } + } + ]); +})(window.angular, window._); \ No newline at end of file diff --git a/src/templateengine/service/templateLocalStorageProvider.js b/src/templateengine/service/templateLocalStorageProvider.js index 2da6ff9..e5791b4 100644 --- a/src/templateengine/service/templateLocalStorageProvider.js +++ b/src/templateengine/service/templateLocalStorageProvider.js @@ -156,6 +156,34 @@ category: "socialMedia", componentType: "Cerberus.TemplateEngine.Controller.Component.SocialMedia.Sharer", imageUrl: "sharer.png" + }, + { + id: 7, + name: "labelList", + category: "gmail", + componentType: "Cerberus.TemplateEngine.Controller.Component.Gmail.LabelList", + imageUrl: "blank.png" + }, + { + id: 8, + name: "messageList", + category: "gmail", + componentType: "Cerberus.TemplateEngine.Controller.Component.Gmail.MessageList", + imageUrl: "blank.png" + }, + { + id: 9, + name: "messageContent", + category: "gmail", + componentType: "Cerberus.TemplateEngine.Controller.Component.Gmail.MessageContent", + imageUrl: "blank.png" + }, + { + id: 10, + name: "authorization", + category: "gmail", + componentType: "Cerberus.TemplateEngine.Controller.Component.Gmail.Authorization", + imageUrl: "blank.png" } ]); }; diff --git a/src/templateengine/view/component/gmail/authorization.html b/src/templateengine/view/component/gmail/authorization.html new file mode 100644 index 0000000..3e1b957 --- /dev/null +++ b/src/templateengine/view/component/gmail/authorization.html @@ -0,0 +1,13 @@ +
+
+ + + +
+
\ No newline at end of file diff --git a/src/templateengine/view/component/gmail/labelList.html b/src/templateengine/view/component/gmail/labelList.html new file mode 100644 index 0000000..9f99872 --- /dev/null +++ b/src/templateengine/view/component/gmail/labelList.html @@ -0,0 +1,6 @@ +
    {{selectedlabelName}} +
  • +
\ No newline at end of file diff --git a/src/templateengine/view/component/gmail/messageContent.html b/src/templateengine/view/component/gmail/messageContent.html new file mode 100644 index 0000000..aeba364 --- /dev/null +++ b/src/templateengine/view/component/gmail/messageContent.html @@ -0,0 +1,7 @@ +

+ + + + + +
\ No newline at end of file diff --git a/src/templateengine/view/component/gmail/messageList.html b/src/templateengine/view/component/gmail/messageList.html new file mode 100644 index 0000000..0a5c931 --- /dev/null +++ b/src/templateengine/view/component/gmail/messageList.html @@ -0,0 +1,11 @@ +
+
    +
  • +
    +
    + + +
    +
  • +
From 4648b787c7a1ff39a41ffe67c4e10321513ed3ff Mon Sep 17 00:00:00 2001 From: agronkabashi Date: Fri, 5 Feb 2016 18:06:25 +0100 Subject: [PATCH 05/15] Fixed eslint errors --- .../controller/componentEditor/gmail/messageList.js | 6 +----- src/templateeditor/directive/componentProperties.js | 4 +++- .../controller/component/gmail/authorization.js | 2 +- src/templateengine/service/google/gmail.js | 1 - 4 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/templateeditor/controller/componentEditor/gmail/messageList.js b/src/templateeditor/controller/componentEditor/gmail/messageList.js index 24f4479..363cbda 100644 --- a/src/templateeditor/controller/componentEditor/gmail/messageList.js +++ b/src/templateeditor/controller/componentEditor/gmail/messageList.js @@ -5,10 +5,6 @@ .module("Cerberus.TemplateEditor") .controller("Cerberus.TemplateEditor.Controller.ComponentEditor.Gmail.MessageList", [ "$scope", - MessageListEditorController + function () {} ]); - - function MessageListEditorController($scope) { - - } })(window.angular); \ No newline at end of file diff --git a/src/templateeditor/directive/componentProperties.js b/src/templateeditor/directive/componentProperties.js index 0adff64..8ae3887 100644 --- a/src/templateeditor/directive/componentProperties.js +++ b/src/templateeditor/directive/componentProperties.js @@ -148,7 +148,9 @@ $scope.editorViewPath = viewPath; $scope.hasEditor = true; } - catch (e) { } + catch (e) { + $scope.hasEditor = true; + } } } } diff --git a/src/templateengine/controller/component/gmail/authorization.js b/src/templateengine/controller/component/gmail/authorization.js index 8cc8794..2b682cd 100644 --- a/src/templateengine/controller/component/gmail/authorization.js +++ b/src/templateengine/controller/component/gmail/authorization.js @@ -33,7 +33,7 @@ }) .catch(function (error) { $scope.authorizationFailed = true; - setErrorMessage(error) + setErrorMessage(error); }); } diff --git a/src/templateengine/service/google/gmail.js b/src/templateengine/service/google/gmail.js index 37630a0..10ffc90 100644 --- a/src/templateengine/service/google/gmail.js +++ b/src/templateengine/service/google/gmail.js @@ -179,7 +179,6 @@ } var header; - var emailInfo; for (i = 0; i < payload.headers.length; i++) { header = payload.headers[i]; From abebcdff9a6bf0faca85bc9f3caef8a5561720a1 Mon Sep 17 00:00:00 2001 From: agronkabashi Date: Thu, 11 Feb 2016 21:31:01 +0100 Subject: [PATCH 06/15] Updated meta tag --- src/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/index.html b/src/index.html index 74eac99..13d3c5b 100644 --- a/src/index.html +++ b/src/index.html @@ -2,7 +2,7 @@ - + From 6e333d9aa1e4b4888c47be1cc420af969689e968 Mon Sep 17 00:00:00 2001 From: agronkabashi Date: Thu, 11 Feb 2016 21:31:50 +0100 Subject: [PATCH 07/15] Introduced max-width & height Cleaned up markup --- src/templateeditor/css/_unitField.scss | 17 +-- src/templateeditor/css/_variables.scss | 3 +- src/templateeditor/helper/css.js | 2 + src/templateeditor/localization/en-us.js | 4 +- .../view/componentProperties/layout.html | 20 +-- .../controller/component/gmail/labelList.js | 8 +- src/templateengine/css/_responsive.scss | 1 + src/templateengine/css/component/_gmail.scss | 118 +++++++++++++----- src/templateengine/css/templateengine.scss | 1 + .../view/component/gmail/labelList.html | 18 ++- .../view/component/gmail/messageList.html | 2 +- 11 files changed, 139 insertions(+), 55 deletions(-) create mode 100644 src/templateengine/css/_responsive.scss diff --git a/src/templateeditor/css/_unitField.scss b/src/templateeditor/css/_unitField.scss index 360be74..661890a 100644 --- a/src/templateeditor/css/_unitField.scss +++ b/src/templateeditor/css/_unitField.scss @@ -1,21 +1,22 @@ cs-unitfield { $unitFieldTypeWidth: rem(50); font-size: 0; - width: 100%; - //min-width: rem(80); - //max-width: rem(175); + position: relative; white-space: nowrap; + width: 100%; input[type="text"] { - @include calc("width", "100% - #{$unitFieldTypeWidth}"); - - //min-width: $unitFieldTypeWidth; padding: 0 rem(10); + width: 100%; + padding-right: $unitFieldTypeWidth; } select { - width: $unitFieldTypeWidth; - padding: 0; + background-color: $input-background-color; border-radius: 0; + padding: 0; + position: absolute; + right: 0; + width: $unitFieldTypeWidth; } } \ No newline at end of file diff --git a/src/templateeditor/css/_variables.scss b/src/templateeditor/css/_variables.scss index 9cd1f6e..94d6f8d 100644 --- a/src/templateeditor/css/_variables.scss +++ b/src/templateeditor/css/_variables.scss @@ -10,4 +10,5 @@ $layer-5: 5; $defaultFontSize: rem(12); $inputHeight: rem(30); -$swift-out-easing: cubic-bezier(0.55, 0, 0.1, 1); \ No newline at end of file +$swift-out-easing: cubic-bezier(0.55, 0, 0.1, 1); +$input-background-color: white; \ No newline at end of file diff --git a/src/templateeditor/helper/css.js b/src/templateeditor/helper/css.js index d2a6f36..e574b0a 100644 --- a/src/templateeditor/helper/css.js +++ b/src/templateeditor/helper/css.js @@ -12,6 +12,8 @@ left: true, width: true, height: true, + maxHeight: true, + maxWidth: true, minHeight: true, minWidth: true, fontSize: true, diff --git a/src/templateeditor/localization/en-us.js b/src/templateeditor/localization/en-us.js index a10bfe8..9205107 100644 --- a/src/templateeditor/localization/en-us.js +++ b/src/templateeditor/localization/en-us.js @@ -57,8 +57,8 @@ bottom: "Bottom", width: "Width", height: "Height", - minWidth: "Minimum Width", - minHeight: "Minimum Height", + min: "Min", + max: "Max", center: "Center", rotateZ: "Rotate", diff --git a/src/templateeditor/view/componentProperties/layout.html b/src/templateeditor/view/componentProperties/layout.html index 48809ae..9c65bc2 100644 --- a/src/templateeditor/view/componentProperties/layout.html +++ b/src/templateeditor/view/componentProperties/layout.html @@ -6,20 +6,26 @@ -
+
- - + + + + +
-
- - +
+ + - + + + +
diff --git a/src/templateengine/controller/component/gmail/labelList.js b/src/templateengine/controller/component/gmail/labelList.js index b29a5b3..2a69688 100644 --- a/src/templateengine/controller/component/gmail/labelList.js +++ b/src/templateengine/controller/component/gmail/labelList.js @@ -14,9 +14,13 @@ function LabelListController($scope, labels, EventService, GmailService) { refreshLabels(); - $scope.selectedLabelId = labels.INBOX; + $scope.selectedLabel = { + name: "Inbox", + id: labels.INBOX + }; + $scope.onClickLabel = function (label) { - $scope.selectedLabelId = label.id; + $scope.selectedLabel = label; EventService.notify("Gmail.ViewLabel", label); }; diff --git a/src/templateengine/css/_responsive.scss b/src/templateengine/css/_responsive.scss new file mode 100644 index 0000000..eee1ec0 --- /dev/null +++ b/src/templateengine/css/_responsive.scss @@ -0,0 +1 @@ +$phone: new-breakpoint(max-width 767px); \ No newline at end of file diff --git a/src/templateengine/css/component/_gmail.scss b/src/templateengine/css/component/_gmail.scss index 50343d6..7badc75 100644 --- a/src/templateengine/css/component/_gmail.scss +++ b/src/templateengine/css/component/_gmail.scss @@ -5,19 +5,32 @@ Message Authorization */ -cs-component.labellist > ul, -cs-component.messagelist > ul { +cs-component.labellist .list, +cs-component.messagelist > .list { list-style: none; margin: 0; padding: 0; - li { + .list-item { cursor: pointer; } } -cs-component.labellist > ul { - li { +// Component: Label List +cs-component.labellist { + label { + display: inline-block; + } + + input[type="checkbox"] { + z-index: -1; + position: absolute; + visibility: hidden; + } + + .list-item { + font-size: smaller; + &:hover { background-color: silver; } @@ -28,8 +41,54 @@ cs-component.labellist > ul { } } +@include media($phone) { + cs-component.labellist.phone-burger { + label { + display: inline-block; + margin: 6px; + + &::before { + @include transform(translateY(-50%)); + content: attr(label); + left: 0; + position: absolute; + width: 100%; + text-align: center; + top: 50%; + } + } + + svg { + display: inline-block; + fill: currentColor; + height: 100%; + max-height: 100%; + } + + .list { + display: none; + } + + .list-item { + border-top: rem(1) solid #bdbdbd; + padding-top: rem(16); + } + + input[type="checkbox"]:checked + label > .list { + display: block; + position: fixed; + left: 0; + top: 32px; + bottom: 0; + width: 100%; + background-color: rgba(0,0,0,0.1); + } + } +} + +// Component: Message List cs-component.messagelist { - > ul { + > .list { height: inherit; &.loading::before { @@ -47,36 +106,35 @@ cs-component.messagelist { } } - li { + .list-item { @include display(flex); - .avatar { - @include flex-grow(1); - min-width: rem(22); - max-width: rem(72); - - &::before { - background-color: beige; // TODO - border-radius: 50%; - content: ""; - display: block; - margin-top: rem(16); - padding-top: 75%; - width: 75%; - } + &:first-child .meta-info { + border-top: none; } + } - .meta-info { - @include flex-grow(0); - border-top: rem(1) solid #bdbdbd; - padding-top: rem(16); - width: 87%; - } + .avatar { + @include flex-grow(1); + min-width: rem(22); + max-width: rem(72); - &:first-child .meta-info { - border-top: none; + &::before { + background-color: beige; // TODO + border-radius: 50%; + content: ""; + display: block; + margin-top: rem(16); + padding-top: 75%; + width: 75%; } + } + .meta-info { + @include flex-grow(0); + border-top: rem(1) solid #bdbdbd; + padding-top: rem(16); + width: 87%; } .from { @@ -90,6 +148,7 @@ cs-component.messagelist { } } +// Component: Message Content cs-component.messagecontent { .subject { margin: 0; @@ -102,6 +161,7 @@ cs-component.messagecontent { } } +// Component: Authorization cs-component.authorization { .authorizeContainer { background-color: rgba(0, 0, 0, 0.3); diff --git a/src/templateengine/css/templateengine.scss b/src/templateengine/css/templateengine.scss index 8fef75a..4a382ce 100644 --- a/src/templateengine/css/templateengine.scss +++ b/src/templateengine/css/templateengine.scss @@ -1,6 +1,7 @@ @import "bourbon"; @import "neat"; +@import "responsive"; @import "component"; html, diff --git a/src/templateengine/view/component/gmail/labelList.html b/src/templateengine/view/component/gmail/labelList.html index 9f99872..ada57d9 100644 --- a/src/templateengine/view/component/gmail/labelList.html +++ b/src/templateengine/view/component/gmail/labelList.html @@ -1,6 +1,14 @@ -
    {{selectedlabelName}} -
  • + +
+ \ No newline at end of file diff --git a/src/templateengine/view/component/gmail/messageList.html b/src/templateengine/view/component/gmail/messageList.html index 0a5c931..b88ba58 100644 --- a/src/templateengine/view/component/gmail/messageList.html +++ b/src/templateengine/view/component/gmail/messageList.html @@ -1,5 +1,5 @@
-
    +
    • From a1aa8677c82d250aec26ba60e3f024a9097056c3 Mon Sep 17 00:00:00 2001 From: agronkabashi Date: Sat, 20 Feb 2016 13:00:51 +0100 Subject: [PATCH 08/15] Cleanup --- src/demo.html | 3 + src/demo.scss | 4 + .../component/gmail/messageContent.js | 5 + .../controller/component/gmail/messageList.js | 3 +- src/templateengine/css/component/_gmail.scss | 144 ++++++++++-------- src/templateengine/service/google/gmail.js | 12 +- .../view/component/gmail/labelList.html | 13 +- .../view/component/gmail/messageList.html | 8 +- 8 files changed, 115 insertions(+), 77 deletions(-) diff --git a/src/demo.html b/src/demo.html index 1aab7f3..d2c28f9 100644 --- a/src/demo.html +++ b/src/demo.html @@ -13,6 +13,9 @@

      TemplateEngine Demo

      For ideas on how TemplateEngine can be applied in real world applications, please check out the wiki pages on GitHub.

      +

      + Please note: this demo application uses localStorage for storing the templates so the they will only be accessible from your browser. +

diff --git a/src/demo.scss b/src/demo.scss index ab510d9..8bba510 100644 --- a/src/demo.scss +++ b/src/demo.scss @@ -34,6 +34,10 @@ h1 { display: none !important; } +.warning { + color: red; +} + .list { border: 1px solid #ddd; border-radius: 5px; diff --git a/src/templateengine/controller/component/gmail/messageContent.js b/src/templateengine/controller/component/gmail/messageContent.js index 44e053e..ca1e3e8 100644 --- a/src/templateengine/controller/component/gmail/messageContent.js +++ b/src/templateengine/controller/component/gmail/messageContent.js @@ -18,6 +18,11 @@ }); function onViewMessage(messageId) { + if (messageId === undefined) { + $scope.message = undefined; + return; + } + GmailService.getMessage(messageId).then(function (message) { $scope.message = message; }); diff --git a/src/templateengine/controller/component/gmail/messageList.js b/src/templateengine/controller/component/gmail/messageList.js index e2045bb..9423353 100644 --- a/src/templateengine/controller/component/gmail/messageList.js +++ b/src/templateengine/controller/component/gmail/messageList.js @@ -18,7 +18,7 @@ EventService.subscribe("Gmail.Reauthorized", refreshMessages); $scope.onClickMessage = function (message) { - EventService.notify("Gmail.ViewMessage", message.id); + EventService.notify("Gmail.ViewMessage", message && message.id); }; $scope.$on("$destroy", function () { @@ -32,6 +32,7 @@ .then(function (messages) { $scope.isLoading = false; $scope.messages = messages; + messages && $scope.onClickMessage(messages[0]); }) .catch(function () { $scope.isLoading = false; diff --git a/src/templateengine/css/component/_gmail.scss b/src/templateengine/css/component/_gmail.scss index 7badc75..03d9366 100644 --- a/src/templateengine/css/component/_gmail.scss +++ b/src/templateengine/css/component/_gmail.scss @@ -20,69 +20,58 @@ cs-component.messagelist > .list { cs-component.labellist { label { display: inline-block; + + &:after { + content: attr(current-label); + display: inline-block; + pointer-events: none; + vertical-align: middle; + } + } + + .hamburger-icon { + cursor: pointer; + display: inline-block; + fill: currentColor; + height: rem(46); + padding: rem(14); + width: rem(46); + vertical-align: middle; } input[type="checkbox"] { - z-index: -1; position: absolute; visibility: hidden; + z-index: -1; + } + + .list { + background-color: #f2f2f2; + display: none; } .list-item { + border-top: rem(1) solid #bdbdbd; + color: #000; font-size: smaller; + padding: rem(16); &:hover { - background-color: silver; + background-color: rgba(0, 0, 0, 0.03); } } - .selected { - color: #dd4b39; + input[type="checkbox"]:checked + label > .list { + display: block; + height: calc(100vh - 100%); + left: 0; + position: absolute; + top: 100%; + width: 100%; } -} -@include media($phone) { - cs-component.labellist.phone-burger { - label { - display: inline-block; - margin: 6px; - - &::before { - @include transform(translateY(-50%)); - content: attr(label); - left: 0; - position: absolute; - width: 100%; - text-align: center; - top: 50%; - } - } - - svg { - display: inline-block; - fill: currentColor; - height: 100%; - max-height: 100%; - } - - .list { - display: none; - } - - .list-item { - border-top: rem(1) solid #bdbdbd; - padding-top: rem(16); - } - - input[type="checkbox"]:checked + label > .list { - display: block; - position: fixed; - left: 0; - top: 32px; - bottom: 0; - width: 100%; - background-color: rgba(0,0,0,0.1); - } + .selected { + color: #dd4b39; } } @@ -98,54 +87,79 @@ cs-component.messagelist { border-radius: rem(2); box-shadow: 0 rem(2) rem(4) rgba(0,0,0,0.2); content: attr(loading); + left: 50%; + margin: 0 auto; padding: rem(6) rem(10); position: absolute; text-align: center; - margin: 0 auto; - left: 50%; } } + .empty-list { + padding: rem(16); + } + .list-item { @include display(flex); + border-top: rem(1) solid #eaeaea; + padding: rem(8) 0; - &:first-child .meta-info { + &:first-child { border-top: none; } } .avatar { @include flex-grow(1); - min-width: rem(22); - max-width: rem(72); + max-width: rem(60); + min-width: rem(38); + padding: rem(8); + position: relative; &::before { - background-color: beige; // TODO + background-color: rgb(76, 190, 246); // TODO border-radius: 50%; content: ""; display: block; - margin-top: rem(16); - padding-top: 75%; - width: 75%; + padding-top: 100%; // Turns the this into a square since padding is relative to width } + + &::after { + color: rgb(190, 232, 253); + content: attr(initial); + display: inline-block; + font-weight: bold; + left: 0; + padding-top: 50%; + position: absolute; + text-align: center; + top: 0; + width: 100%; + } } .meta-info { @include flex-grow(0); - border-top: rem(1) solid #bdbdbd; - padding-top: rem(16); width: 87%; } + .is-read .from { + font-weight: bolder; + } + .from { display: block; - font-weight: bolder; } - .subject { + .subject, + .snippet { color: silver; display: block; } + + .snippet { + font-size: smaller; + } } // Component: Message Content @@ -177,19 +191,19 @@ cs-component.authorization { @include transform(translateY(-50%)); background-color: white; - border: 1px solid #bdbdbd; - border-radius: 5px; - box-shadow: 0 3px 3px 0 rgba(0,0,0,0.2); + border: rem(1) solid #bdbdbd; + border-radius: rem(5); + box-shadow: 0 rem(3) rem(3) 0 rgba(0,0,0,0.2); display: inline-block; margin: auto; - padding: 1rem; + padding: rem(16); position: relative; top: 50%; } .info { display: block; - margin-bottom: 1rem; + margin-bottom: rem(16); } button { diff --git a/src/templateengine/service/google/gmail.js b/src/templateengine/service/google/gmail.js index 10ffc90..04c980b 100644 --- a/src/templateengine/service/google/gmail.js +++ b/src/templateengine/service/google/gmail.js @@ -85,7 +85,7 @@ } }) .then(function (response) { - return getMessageDetails(response.result.id, response.result.payload); + return getMessageDetails(response.result.id, response.result); }, onRequestFailed); }); }; @@ -132,7 +132,7 @@ return batch.then(function (batchResponse) { var batchMessages = []; for (var i in batchResponse.result) { - batchMessages.push(getMessageDetails(i, batchResponse.result[i].result.payload)); + batchMessages.push(getMessageDetails(i, batchResponse.result[i].result)); } return batchMessages; @@ -144,11 +144,15 @@ EventService.notify("Gmail.RequestFailed", error); } - function getMessageDetails(messageId, payload) { + function getMessageDetails(messageId, rawMessage) { + var payload = rawMessage.payload; var message = { id: messageId, plainText: "", - htmlText: "" + htmlText: "", + snippet: rawMessage.snippet, + isRead: rawMessage.labelIds.indexOf("UNREAD") < 0, + isStarred: rawMessage.labelIds.indexOf("STARRED") >= 0 }; var i; diff --git a/src/templateengine/view/component/gmail/labelList.html b/src/templateengine/view/component/gmail/labelList.html index ada57d9..1be5876 100644 --- a/src/templateengine/view/component/gmail/labelList.html +++ b/src/templateengine/view/component/gmail/labelList.html @@ -1,14 +1,17 @@ - - \ No newline at end of file diff --git a/src/templateengine/view/component/gmail/messageList.html b/src/templateengine/view/component/gmail/messageList.html index b88ba58..1ec4eb2 100644 --- a/src/templateengine/view/component/gmail/messageList.html +++ b/src/templateengine/view/component/gmail/messageList.html @@ -1,11 +1,15 @@
    -
  • -
    +
    +
From 10385a172536723372f713110ec6ae4daecf147d Mon Sep 17 00:00:00 2001 From: agronkabashi Date: Tue, 23 Feb 2016 18:14:46 +0100 Subject: [PATCH 09/15] Updated template preset to include gmail --- src/template-presets.json | 199 +++++++++++++++++++++----------------- 1 file changed, 111 insertions(+), 88 deletions(-) diff --git a/src/template-presets.json b/src/template-presets.json index 5385701..7bb1689 100644 --- a/src/template-presets.json +++ b/src/template-presets.json @@ -153,7 +153,7 @@ "category": "basic", "friendlyName": "", "name": "text", - "content": { }, + "content": {}, "visualProperties": "left:0px;top:0px;", "class": "", "creationGUID": "" @@ -164,7 +164,7 @@ "category": "basic", "friendlyName": "", "name": "text", - "content": { }, + "content": {}, "visualProperties": "left:0px;top:0px;", "class": "", "creationGUID": "" @@ -175,7 +175,7 @@ "category": "basic", "friendlyName": "", "name": "text", - "content": { }, + "content": {}, "visualProperties": "left:0px;top:0px;", "class": "", "creationGUID": "" @@ -186,7 +186,7 @@ "category": "basic", "friendlyName": "", "name": "text", - "content": { }, + "content": {}, "visualProperties": "left:0px;top:0px;", "class": "", "creationGUID": "" @@ -197,7 +197,7 @@ "category": "basic", "friendlyName": "", "name": "text", - "content": { }, + "content": {}, "visualProperties": "left:0px;top:0px;", "class": "", "creationGUID": "" @@ -208,7 +208,7 @@ "category": "basic", "friendlyName": "", "name": "text", - "content": { }, + "content": {}, "visualProperties": "left:0px;top:0px;", "class": "", "creationGUID": "" @@ -219,7 +219,7 @@ "category": "basic", "friendlyName": "", "name": "text", - "content": { }, + "content": {}, "visualProperties": "left:0px;top:0px;", "class": "", "creationGUID": "" @@ -230,7 +230,7 @@ "category": "basic", "friendlyName": "", "name": "text", - "content": { }, + "content": {}, "visualProperties": "left:0px;top:0px;", "class": "", "creationGUID": "" @@ -241,7 +241,7 @@ "category": "basic", "friendlyName": "", "name": "text", - "content": { }, + "content": {}, "visualProperties": "left:0px;top:0px;", "class": "", "creationGUID": "" @@ -252,7 +252,7 @@ "category": "basic", "friendlyName": "", "name": "text", - "content": { }, + "content": {}, "visualProperties": "left:0px;top:0px;", "class": "", "creationGUID": "" @@ -263,7 +263,7 @@ "category": "basic", "friendlyName": "", "name": "text", - "content": { }, + "content": {}, "visualProperties": "left:0px;top:0px;", "class": "", "creationGUID": "" @@ -271,71 +271,6 @@ ] } }, - { - "name": "Gmail", - "data": { - "name": "Gmail", - "id": 0, - "visualProperties": "", - "createdDateAsString": "", - "lastModifiedDateAsString": "", - "components": [ - { - "category": "gmail", - "class": "", - "content": { }, - "name": "labelList", - "componentType": "Cerberus.TemplateEngine.Controller.Component.Gmail.LabelList", - "friendlyName": "", - "id": 1, - "visualProperties": "" - }, - { - "category": "gmail", - "class": "", - "content": { }, - "name": "messageList", - "componentType": "Cerberus.TemplateEngine.Controller.Component.Gmail.MessageList", - "friendlyName": "", - "id": 2, - "visualProperties": "" - }, - { - "category": "gmail", - "class": "", - "content": { }, - "name": "messageContent", - "componentType": "Cerberus.TemplateEngine.Controller.Component.Gmail.MessageContent", - "friendlyName": "", - "id": 3, - "visualProperties": "" - } - , - { - "category": "gmail", - "class": "", - "content": { }, - "name": "authorization", - "componentType": "Cerberus.TemplateEngine.Controller.Component.Gmail.Authorization", - "friendlyName": "", - "id": 4, - "visualProperties": "" - } - ], - "resolutions": [ - { - "id": 0, - "resolutionValue": 10000, - "componentVisualProperties": { - "1": "left:0px;top:0px;width:300px;height:600px", - "2": "left:300px;top:0px;width:400px;height:300px", - "3": "left:300px;top:300px;width:400px;height:300px", - "4": "left:600px;top:0px;width:400px" - } - } - ] - } - }, { "name": "Sample Start Page", "data": { @@ -348,7 +283,7 @@ { "category": "basic", "class": "", - "content": { }, + "content": {}, "name": "text", "componentType": "Cerberus.TemplateEngine.Controller.Component.Basic.Text", "friendlyName": "", @@ -358,7 +293,7 @@ { "category": "basic", "class": "", - "content": { }, + "content": {}, "name": "text", "componentType": "Cerberus.TemplateEngine.Controller.Component.Basic.Text", "friendlyName": "", @@ -380,7 +315,7 @@ { "category": "basic", "class": "", - "content": { }, + "content": {}, "name": "text", "componentType": "Cerberus.TemplateEngine.Controller.Component.Basic.Text", "friendlyName": "", @@ -414,7 +349,7 @@ { "category": "socialMedia", "class": "", - "content": { }, + "content": {}, "name": "sharer", "componentType": "Cerberus.TemplateEngine.Controller.Component.SocialMedia.Sharer", "friendlyName": "", @@ -436,7 +371,7 @@ { "category": "basic", "class": "", - "content": { }, + "content": {}, "name": "text", "componentType": "Cerberus.TemplateEngine.Controller.Component.Basic.Text", "friendlyName": "Menu", @@ -470,7 +405,7 @@ { "category": "basic", "class": "RightPosIEFix", - "content": { }, + "content": {}, "name": "text", "componentType": "Cerberus.TemplateEngine.Controller.Component.Basic.Text", "friendlyName": "", @@ -480,7 +415,7 @@ { "category": "basic", "class": "", - "content": { }, + "content": {}, "name": "text", "componentType": "Cerberus.TemplateEngine.Controller.Component.Basic.Text", "friendlyName": "", @@ -490,7 +425,12 @@ { "category": "navigation", "class": "", - "content": { "url": "", "tooltip": "", "text": "CERBERUS Solutions", "target": "_self" }, + "content": { + "url": "", + "tooltip": "", + "text": "CERBERUS Solutions", + "target": "_self" + }, "name": "link", "componentType": "Cerberus.TemplateEngine.Controller.Component.Navigation.Link", "friendlyName": "", @@ -500,7 +440,7 @@ { "category": "basic", "class": "", - "content": { }, + "content": {}, "name": "text", "componentType": "Cerberus.TemplateEngine.Controller.Component.Basic.Text", "friendlyName": "", @@ -510,7 +450,9 @@ { "category": "basic", "class": "", - "content": { "text": "RESPONSIVE DESIGN" }, + "content": { + "text": "RESPONSIVE DESIGN" + }, "name": "text", "componentType": "Cerberus.TemplateEngine.Controller.Component.Basic.Text", "friendlyName": "", @@ -520,7 +462,7 @@ { "category": "basic", "class": "RightPosIEFix", - "content": { }, + "content": {}, "name": "text", "componentType": "Cerberus.TemplateEngine.Controller.Component.Basic.Text", "friendlyName": "", @@ -731,6 +673,87 @@ } ] } + }, + { + "name": "Gmail", + "data": { + "name": "Gmail", + "id": 0, + "visualProperties": "", + "createdDateAsString": "", + "lastModifiedDateAsString": "", + "components": [ + { + "category": "gmail", + "class": "", + "content": {}, + "name": "labelList", + "componentType": "Cerberus.TemplateEngine.Controller.Component.Gmail.LabelList", + "friendlyName": "", + "id": 1, + "visualProperties": "width:100%;height:46px;font-size:16px;z-index:3;font-weight:bold;font-family:sans-serif;background-color:#4285f4;color:white;box-shadow:black 0px 0px 4px 0px " + }, + { + "category": "gmail", + "class": "", + "content": { + "localization": { + "loading": "Loading...", + "noMessages": "There are no messages", + "emptyList": "There are no messages with this label." + }, + "loadingClass": "" + }, + "name": "messageList", + "componentType": "Cerberus.TemplateEngine.Controller.Component.Gmail.MessageList", + "friendlyName": "", + "id": 2, + "visualProperties": "top:46px;width:100%;height:200px;overflow:auto;font-size:12px;font-family:sans-serif;max-height:50%" + }, + { + "category": "gmail", + "class": "", + "content": {}, + "name": "messageContent", + "componentType": "Cerberus.TemplateEngine.Controller.Component.Gmail.MessageContent", + "friendlyName": "", + "id": 3, + "visualProperties": "width:100%;height:calc(100% - 246px);background-color:white;top:246px;overflow:auto;font-size:12px;font-family:sans-serif;border-top-style:solid;border-top-width:1px;border-top-color:#bdbdbd;padding-top:10px;padding-right:10px;padding-bottom:10px;padding-left:10px" + }, + { + "category": "gmail", + "class": "", + "content": {}, + "name": "authorization", + "componentType": "Cerberus.TemplateEngine.Controller.Component.Gmail.Authorization", + "friendlyName": "", + "id": 4, + "visualProperties": "width:100%;height:5px" + } + ], + "resolutions": [ + { + "id": 2, + "resolutionValue": 768, + "componentVisualProperties": { + "1": "width:100%;height:46px;font-size:16px;z-index:3;font-weight:bold;font-family:sans-serif;background-color:#4285f4;color:white;box-shadow:black 0px 0px 4px 0px ", + "2": "top:46px;width:100%;height:200px;overflow:auto;font-size:12px;font-family:sans-serif;max-height:50%", + "3": "width:100%;height:calc(100% - 246px);background-color:white;top:246px;overflow:auto;font-size:12px;font-family:sans-serif;border-top-style:solid;border-top-width:1px;border-top-color:#bdbdbd;padding-top:10px;padding-right:10px;padding-bottom:10px;padding-left:10px", + "4": "width:100%;height:5px" + } + }, + { + "id": 1, + "resolutionValue": 10000, + "componentVisualProperties": { + "1": "width:100%;height:46px;font-size:16px;z-index:3;font-weight:bold;font-family:sans-serif;background-color:#4285f4;color:white;box-shadow:black 0px 0px 4px 0px ", + "2": "width:350px;height:calc(100% - 46px);overflow:auto;font-family:sans-serif;font-size:13px;top:46px", + "3": "left:350px;width:calc(100% - 350px);height:calc(100% - 46px);background-color:white;overflow:auto;font-family:sans-serif;font-size:13px;top:46px;border-left-style:solid;border-left-width:1px;border-left-color:#bdbdbd;padding-top:10px;padding-right:10px;padding-bottom:10px;padding-left:10px", + "4": "width:100%;height:5px" + } + } + ] + } } ] -} +} \ No newline at end of file From 8bf29632ae07b878fcc49ab8a574230d52923579 Mon Sep 17 00:00:00 2001 From: agronkabashi Date: Tue, 23 Feb 2016 18:15:43 +0100 Subject: [PATCH 10/15] Fixed offset bug when dragging out a component plugin --- src/templateeditor/css/_componentPlugins.scss | 112 +++++++++--------- 1 file changed, 59 insertions(+), 53 deletions(-) diff --git a/src/templateeditor/css/_componentPlugins.scss b/src/templateeditor/css/_componentPlugins.scss index fb6b053..c286215 100644 --- a/src/templateeditor/css/_componentPlugins.scss +++ b/src/templateeditor/css/_componentPlugins.scss @@ -1,18 +1,20 @@ cs-componentplugins { + pointer-events: none; position: fixed; - bottom: 100%; + top: 0; width: 100%; z-index: $layer-5; > .container { - @include transform(translateY(100%)); + @include transform(translateY(0%)); @include transition(all 0.3s); background-color: $controlBackgroundColor; - border-bottom: 1px solid $borderColor; - padding-top: 10px; + border-bottom: rem(1) solid $borderColor; + padding-top: rem(10); + pointer-events: all; &.collapsed { - @include transform(translateY(0)); + @include transform(translateY(-100%)); } } @@ -29,61 +31,65 @@ .component-plugins { margin: 0; + } - > .component-plugin { - cursor: move; - display: inline-block; - font-size: 12px; - font-family: Arial; - margin-right: 20px; - position: relative; - text-align: center; - vertical-align: top; - width: 50px; + .component-plugin { + cursor: move; + display: inline-block; + font-size: 12px; + font-family: Arial; + margin-right: 20px; + position: relative; + text-align: center; + vertical-align: top; + width: rem(70); - > img { - @include transition(all 0.3s); - box-shadow: 0 0 5px 0 rgba(127, 127, 127, 0.5); - } + > img { + @include transition(all 0.3s); + box-shadow: 0 0 5px 0 rgba(127, 127, 127, 0.5); + } - &.ui-draggable { - z-index: $layer-3; - } + span { + display: block; + } - &.ui-draggable-dragging { - &::before { - content: ""; - padding: 0; - display: block; - position: absolute; - left: 0; - top: 0; - width: 16px; - height: 16px; - background-color: green; - border-radius: 50%; - } + &.ui-draggable { + z-index: $layer-3; + } - &::after { - content: "+"; - color: white; - font-size: 16px; - line-height: 14px; - font-family: Impact; - margin-left: 3px; - display: block; - position: absolute; - left: 0; - top: 0; - } + &.ui-draggable-dragging { + &::before { + content: ""; + padding: 0; + display: block; + position: absolute; + left: 0; + top: 0; + width: 16px; + height: 16px; + background-color: green; + border-radius: 50%; + } - img { - opacity: 1; - } + &::after { + content: "+"; + color: white; + font-size: 16px; + line-height: 14px; + font-family: Impact; + margin-left: 3px; + display: block; + position: absolute; + left: 0; + top: 0; + } + + img { + opacity: 1; + } - > span { - display: none; - } + > span { + display: none; } } } From d0976af7de8388aa2a88348664e6d4ac5d488cf8 Mon Sep 17 00:00:00 2001 From: agronkabashi Date: Tue, 23 Feb 2016 18:33:33 +0100 Subject: [PATCH 11/15] Invalid component editor was showing --- src/templateeditor/directive/componentProperties.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/templateeditor/directive/componentProperties.js b/src/templateeditor/directive/componentProperties.js index 8ae3887..f44715f 100644 --- a/src/templateeditor/directive/componentProperties.js +++ b/src/templateeditor/directive/componentProperties.js @@ -149,7 +149,7 @@ $scope.hasEditor = true; } catch (e) { - $scope.hasEditor = true; + $scope.hasEditor = false; } } } From 54febdfcea32b3daa6f7071df5bf6355237be9cc Mon Sep 17 00:00:00 2001 From: agronkabashi Date: Tue, 23 Feb 2016 18:35:03 +0100 Subject: [PATCH 12/15] Added comments for component model --- src/templateengine/model/component.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/templateengine/model/component.js b/src/templateengine/model/component.js index 204a607..76d02ad 100644 --- a/src/templateengine/model/component.js +++ b/src/templateengine/model/component.js @@ -5,15 +5,15 @@ .module("Cerberus.ModelFactory") .registerModel("Cerberus.TemplateEngine.Model.Component", function () { this.id = 0; - this.friendlyName = ""; - this.name = ""; + this.friendlyName = ""; // User defined name for the component + this.name = ""; // - this.visualProperties = ""; - this.componentType = ""; - this.category = "basic"; - this.creationGUID = ""; + this.visualProperties = ""; // + this.componentType = ""; // Determines which plugin to use + this.category = "basic"; // The category that best fits the component + this.creationGUID = ""; // Used internally by template editor - this.class = ""; + this.class = ""; // User defined class this.content = {}; }); From 6bc4823c8f15fd88ef92c813e313cf8078074cb1 Mon Sep 17 00:00:00 2001 From: agronkabashi Date: Tue, 23 Feb 2016 18:35:32 +0100 Subject: [PATCH 13/15] Added icon for gmail components --- .../images/componentPlugins/gmail.png | Bin 0 -> 3037 bytes .../service/templateLocalStorageProvider.js | 8 ++++---- 2 files changed, 4 insertions(+), 4 deletions(-) create mode 100644 src/templateeditor/images/componentPlugins/gmail.png diff --git a/src/templateeditor/images/componentPlugins/gmail.png b/src/templateeditor/images/componentPlugins/gmail.png new file mode 100644 index 0000000000000000000000000000000000000000..27b09d1eb3252b770379a803b97d564ad902d7a2 GIT binary patch literal 3037 zcmV<33nKK1P)4Tx05}naRo`#hR1`jmZ&IWdKOk5~hl<6oRa0BJ8yc;~21%2p?MfD<>DVeH z9(p*dx19w`~g7O0}n_%Aq@s%d)fBDv`JHkDym6Hd+5XuAtvnwRpGmK zVkc9?T=n|PIo~X-eVh__(Z?q}P9Z-Dj?gOW6|D%o20XmjW-qs4UjrD(li^iv8@eK9k+ZFm zVRFymFOPAzG5-%Pn|1W;U4vNroTa&AxDScmEA~{ri9gr1^c?U@uwSpaNnw8l_>cP1 zd;)kMQS_;jeRSUEM_*s96y65j1$)tOrwdK{YIQMt92l|D^(E_=$Rjw{b!QT@q!)ni zR`|5oW9X5n$Wv+HVc@|^eX5yXnsHX8PF3UX~a6)MwxDE0HaPjyrlI!;jX{6Kvuh*8ej?;85ekN$?5uuCiS zBTvvVG+XTxAO{m@bvM#Jr)z6J><&E22D|vq?Y?Vkbo_DijopiF$2PET#mZ8eu=y$(ArYkv7@Ex`GL?QCc!_*KFrd&;n1r7 zqW-CFs9&fT)ZaU5gc&=gBz-DaCw(vdOp0__x+47~U6sC(E(JNe@4cTT*n6*E zVH4eoU1-&7pEV~_PRe`a7v+@vy!^5}8?Y3)UmlaER000McNklO2cz&-&G z*jytJX>MQM+h0Af^qx*hrNZ9x64Yfvf_Fxr0_)eVgZ%gZlYV1jU(ixWGy<6pn}CFYfi zm)kP<#(VEWP*I6Pn>V3?0nFHs*=O4Bz8mu&_zB`-5qlo`F-~=NBg-I)QHWeu7rGvL z1hexCQt;9D-^0E~AI9igZ<#DNF@e^y>?cl$F#o_$5rh$T|KK|)?&wBy6rgcdxq((6 zK8(G0-GP6<@^TtL^;NC7^@%O$T-=GaVgb2q24c}tCAGTpiE-KY*OyV)zu&UjazcQ_ z(C?g53CAA%5eENxEJY2XEZQIaHKNK{nDVw7FXdM&N*^Ump;!f6b^68UnBjptA43V! z#8enH#VH(lw(->ToB51EentL;?%3Jpk>9X6ePFu3+R95X`a7htl?Yt z(r|_oi-bQ6py`GsfWE$Th;s6Y-*e+sPK}S7Pr+PDsR&V-ilKq-7gOh&RI*(C`F|AC zcD@48ml*C6mYMETg8M-vb?gq2lBam-{S+4#%yr5I&3 zsU);f^^moDUPGp077jkO8K?fZ#q3fLvY!bUKy_O?MtYAkNasu|1*rR(K}`0aP1kBt zDomoll8uZZU=Gi}zC0`UT&GR&_~=Bt4~iwsXLb2~QfS14%7KRE%Pm=T1fDU?)vHCV zrx`K91Zb23Lr2)zIG2kOM{noWN+vhF%--KPk^c>~sCo5TWNWK!fdg`DE)Ak=cAeNw zlri3W_RpzPA4Ix7*?>7$0PfHGO-HiCq$n>#$GUGjFsf1zTQto?U1z7;76Av39mUyQ zyApiuo+^t?thsxN>`DsLY!XpA1bmRhVba?VY*>#o`wqBAFik>ck|mQ8il446PonOI z&tm-C5O#m_E>xWz;5qBOy`6K#R4@#!KgT|Bo{1S3iddlhNH7(Fg0?bDwt*$T*@Wg5 zH}h8HPcxyjZ2$V#PPcf<6*|N=6*q$2N zMoUijZER(i%Fe1l5M|J^`gY7-kjK>6dG?eLHTiZd{Oev;ft^rmy2H+X7Zb38$6T34+?e&uawzIHJx>+8t?sZ|?IP(BiJ!Q5oVZt?_L`Ezt!(^PE3)>~2B_q8UD{|%)n)@L7_Ps77eyzo5 zHLm;lV`#kj#*Y<*uLf<>f=+_)exondRBse5IuHBds0187`7UzTEkXEDhbeX z+Zv!afuW;(FcC~^$TH_H>13M9G&7|M)492F4w(bg>E*NOn$Mtq;Ud(wwjx_o%L<5i zR*Hre&X1nU!bZpX4ai-4Jq|wnGnDvF=+0k9kR%t)F3t&uBQAZI?jgtfBb$C3=Wkz& zh(U}GpF{7S-5BWU!T1M*W?nhB0ZlB;4)%vgdEs|N%%MXEvHyqn+Y7CBYUQOMsB<09 zxzoKX(L~NLB%>*U(G$J#*qPJVyXkl6+xs_E@Sw8P+D8Wb6v;xioiC%mcnotp7CIWJ zleTy37QDT6tHqVpKIK;u1kDiL*?ING?f2h@3&-C9+m0(8K_?E(h&RE=dGx&SJYqI2 zH7kGRIZ fBI$XrUZd;3MSARkbHAqX00000NkvXXu0mjfB+2Af literal 0 HcmV?d00001 diff --git a/src/templateengine/service/templateLocalStorageProvider.js b/src/templateengine/service/templateLocalStorageProvider.js index e5791b4..6ed6320 100644 --- a/src/templateengine/service/templateLocalStorageProvider.js +++ b/src/templateengine/service/templateLocalStorageProvider.js @@ -162,28 +162,28 @@ name: "labelList", category: "gmail", componentType: "Cerberus.TemplateEngine.Controller.Component.Gmail.LabelList", - imageUrl: "blank.png" + imageUrl: "gmail.png" }, { id: 8, name: "messageList", category: "gmail", componentType: "Cerberus.TemplateEngine.Controller.Component.Gmail.MessageList", - imageUrl: "blank.png" + imageUrl: "gmail.png" }, { id: 9, name: "messageContent", category: "gmail", componentType: "Cerberus.TemplateEngine.Controller.Component.Gmail.MessageContent", - imageUrl: "blank.png" + imageUrl: "gmail.png" }, { id: 10, name: "authorization", category: "gmail", componentType: "Cerberus.TemplateEngine.Controller.Component.Gmail.Authorization", - imageUrl: "blank.png" + imageUrl: "gmail.png" } ]); }; From 11459006eb4c031aebfbc4524a3b78813e6a68ac Mon Sep 17 00:00:00 2001 From: agronkabashi Date: Tue, 23 Feb 2016 18:36:15 +0100 Subject: [PATCH 14/15] Cleaned up markup and added localization --- src/templateeditor/localization/en-us.js | 4 ++++ .../view/componentEditor/gmail/messageList.html | 8 ++++---- .../view/componentProperties/fontAndColors.html | 12 +----------- 3 files changed, 9 insertions(+), 15 deletions(-) diff --git a/src/templateeditor/localization/en-us.js b/src/templateeditor/localization/en-us.js index 9205107..6393b79 100644 --- a/src/templateeditor/localization/en-us.js +++ b/src/templateeditor/localization/en-us.js @@ -189,6 +189,10 @@ disableKeyboard: "Disable keyboard shortcuts", hideYouTubeBrand: "Hide YouTube Brand", showInfo: "Show Video Info" + }, + messageList: { + loadingMessage: "Loading Message", + emptyListMessage: "Empty List Message" } } }; diff --git a/src/templateeditor/view/componentEditor/gmail/messageList.html b/src/templateeditor/view/componentEditor/gmail/messageList.html index 26bce47..ed957be 100644 --- a/src/templateeditor/view/componentEditor/gmail/messageList.html +++ b/src/templateeditor/view/componentEditor/gmail/messageList.html @@ -1,14 +1,14 @@ -
+
- +
- +
\ No newline at end of file diff --git a/src/templateeditor/view/componentProperties/fontAndColors.html b/src/templateeditor/view/componentProperties/fontAndColors.html index f6078c7..b471e94 100644 --- a/src/templateeditor/view/componentProperties/fontAndColors.html +++ b/src/templateeditor/view/componentProperties/fontAndColors.html @@ -49,14 +49,4 @@
-
- \ No newline at end of file +
\ No newline at end of file From e5cb6862be0cb7924f7914ddea2ee15c6e722852 Mon Sep 17 00:00:00 2001 From: agronkabashi Date: Tue, 23 Feb 2016 18:40:44 +0100 Subject: [PATCH 15/15] Removed responsive scss --- src/templateengine/css/_responsive.scss | 1 - src/templateengine/css/templateengine.scss | 1 - 2 files changed, 2 deletions(-) delete mode 100644 src/templateengine/css/_responsive.scss diff --git a/src/templateengine/css/_responsive.scss b/src/templateengine/css/_responsive.scss deleted file mode 100644 index eee1ec0..0000000 --- a/src/templateengine/css/_responsive.scss +++ /dev/null @@ -1 +0,0 @@ -$phone: new-breakpoint(max-width 767px); \ No newline at end of file diff --git a/src/templateengine/css/templateengine.scss b/src/templateengine/css/templateengine.scss index 4a382ce..8fef75a 100644 --- a/src/templateengine/css/templateengine.scss +++ b/src/templateengine/css/templateengine.scss @@ -1,7 +1,6 @@ @import "bourbon"; @import "neat"; -@import "responsive"; @import "component"; html,