diff --git a/src/app/layout/directives/.git.keep b/src/app/layout/directives/.git.keep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/app/layout/directives/.git.keep
diff --git a/src/app/layout/html-utils.spec.ts b/src/app/layout/html-utils.spec.ts
new file mode 100644
index 0000000..3645407
--- /dev/null
+++ b/src/app/layout/html-utils.spec.ts
@@ -0,0 +1,41 @@
+import {
+HtmlUtils
+} from "./html-utils";
+
+describe("HtmlUtils", () => {
+ let element: ng.IAugmentedJQuery;
+
+ beforeEach(inject(($compile: ng.ICompileService, $rootScope: ng.IRootScopeService) => {
+ element = $compile("")($rootScope);
+ }));
+
+ it("removes a css class matching some prefix from an HTML Element", () => {
+ element.addClass("noosfero-class1");
+ element.addClass("noosfero-class2");
+ element.addClass("another-class");
+
+ HtmlUtils.removeCssClassByPrefix(element[0], "noosfero-");
+
+ // we expect classes prefixed with 'noosfero-' to be removed
+ expect(element[0].classList).not.toContain("noosfero-class1");
+ expect(element[0].classList).not.toContain("noosfero-class2");
+
+ // class not prefixed with 'noosfero-' should be there
+ expect(element[0].classList).toContain("another-class");
+ });
+
+ it("removes a css class matching some suffix from an HTML Element", () => {
+ element.addClass("class-1-noosfero");
+ element.addClass("class-2-noosfero");
+ element.addClass("another-class");
+
+ HtmlUtils.removeCssClassBySuffix(element[0], "-noosfero");
+
+ // we expect classes prefixed with 'noosfero-' to be removed
+ expect(element[0].classList).not.toContain("class-1-noosfero");
+ expect(element[0].classList).not.toContain("class-2-noosfero");
+
+ // class not suffixed with '-noosfero' should be there
+ expect(element[0].classList).toContain("another-class");
+ });
+});
\ No newline at end of file
diff --git a/src/app/layout/html-utils.ts b/src/app/layout/html-utils.ts
new file mode 100644
index 0000000..9ead755
--- /dev/null
+++ b/src/app/layout/html-utils.ts
@@ -0,0 +1,18 @@
+export namespace HtmlUtils {
+
+ /**
+ * Remove All Css Classes which matches some prefix
+ */
+ export function removeCssClassByPrefix(el: HTMLElement, prefix: string) {
+ let regx = new RegExp('\\b' + prefix + '\\S*', 'g');
+ el.className = el.className.replace(regx, '');
+ }
+
+ /**
+ * Remove All Css Classes which matches some suffix
+ */
+ export function removeCssClassBySuffix(el: HTMLElement, suffix: string) {
+ let regx = new RegExp('\\S+' + suffix + '\\S*', 'g');
+ el.className = el.className.replace(regx, '');
+ }
+}
\ No newline at end of file
diff --git a/src/app/layout/services/body-state-classes.service.spec.ts b/src/app/layout/services/body-state-classes.service.spec.ts
new file mode 100644
index 0000000..5d8c7bb
--- /dev/null
+++ b/src/app/layout/services/body-state-classes.service.spec.ts
@@ -0,0 +1,63 @@
+import {provideFilters} from '../../../spec/helpers';
+import {BodyStateClassesService} from "./body-state-classes.service";
+import {AuthService} from "./../../login/auth.service";
+
+describe("BodyStateClasses Service", () => {
+ let currentStateName = "main";
+ let bodyStateClasseService: BodyStateClassesService;
+ let $rootScope: ng.IRootScopeService = {},
+ $document: ng.IDocumentService = {},
+ $state: ng.ui.IStateService = {
+ current: {
+ name: currentStateName
+ }
+ },
+ authService: AuthService = {
+ isAuthenticated: () => false
+ },
+ bodyEl: { className: string } = { className: "" },
+ bodyElJq: any = [bodyEl];
+
+ let getService = (): BodyStateClassesService => {
+ return new BodyStateClassesService($rootScope, $document, $state, authService);
+ };
+
+ it("should add the class noosfero-user-logged to the body element if the user is authenticated", () => {
+ authService.isAuthenticated = jasmine.createSpy("isAuthenticated").and.returnValue(true);
+ $rootScope.$on = jasmine.createSpy("$on");
+
+ let service = getService();
+
+ bodyElJq.addClass = jasmine.createSpy("addClass");
+ bodyElJq.removeClass = jasmine.createSpy("removeClass");
+ service["bodyElement"] = bodyElJq;
+
+ service.start();
+ expect(bodyElJq.addClass).toHaveBeenCalledWith(BodyStateClassesService.USER_LOGGED_CLASSNAME);
+ });
+
+ it("should add the class noosfero-route-[currentStateName] the body element", () => {
+ $rootScope.$on = jasmine.createSpy("$on");
+ let service = getService();
+
+ bodyElJq.addClass = jasmine.createSpy("addClass");
+ bodyElJq.removeClass = jasmine.createSpy("removeClass");
+ service["bodyElement"] = bodyElJq;
+
+ service.start();
+ let stateClassName = BodyStateClassesService.ROUTE_STATE_CLASSNAME_PREFIX + currentStateName;
+ expect(bodyElJq.addClass).toHaveBeenCalledWith(stateClassName);
+ });
+
+ it("should capture loginSuccess event and add noosfero-user-logged class to the body element", () => {
+ pending("Test not yet implemented!");
+ });
+
+ it("should capture logoutSuccess event and remove noosfero-user-logged class to the body element", () => {
+ pending("Test not yet implemented!");
+ });
+
+ it("should capture $stateChangeSuccess event and switch route class in the body element", () => {
+ pending("Test not yet implemented!");
+ });
+});
\ No newline at end of file
diff --git a/src/app/layout/services/body-state-classes.service.ts b/src/app/layout/services/body-state-classes.service.ts
new file mode 100644
index 0000000..5b33191
--- /dev/null
+++ b/src/app/layout/services/body-state-classes.service.ts
@@ -0,0 +1,93 @@
+import {Directive, Inject, Injectable} from "ng-forward";
+import {AUTH_EVENTS} from "./../../login/auth-events";
+import {AuthService} from "./../../login/auth.service";
+import {HtmlUtils} from "../html-utils";
+
+/**
+ * This is a service which adds classes to the body element
+ * indicating some app states information as
+ * eg:
+ * User Logged:
+ * - noosfero-user-logged
+ * Route States:
+ * - noosfero-route-main
+ * - noosfero-route-main.profile.info
+ */
+@Injectable()
+@Inject("$rootScope", "$document", "$state", AuthService)
+export class BodyStateClassesService {
+
+ public static get USER_LOGGED_CLASSNAME(): string { return "noosfero-user-logged"; }
+ public static get ROUTE_STATE_CLASSNAME_PREFIX(): string { return "noosfero-route-"; }
+
+ private bodyElement: ng.IAugmentedJQuery = null;
+
+ constructor(
+ private $rootScope: ng.IRootScopeService,
+ private $document: ng.IDocumentService,
+ private $state: ng.ui.IStateService,
+ private authService: AuthService
+ ) {
+
+ }
+
+ start() {
+ this.setupUserLoggedClassToggle();
+ this.setupStateClassToggle();
+ }
+
+ getStateChangeSuccessHandlerFunction(bodyElement: ng.IAugmentedJQuery): (event: ng.IAngularEvent, toState: ng.ui.IState) => void {
+ let self = this;
+ return (event: ng.IAngularEvent, toState: ng.ui.IState) => {
+ self.switchStateClasses(bodyElement, BodyStateClassesService.ROUTE_STATE_CLASSNAME_PREFIX);
+ };
+ }
+
+ switchStateClasses(bodyElement: ng.IAugmentedJQuery, state: ng.ui.IState) {
+ HtmlUtils.removeCssClassByPrefix(bodyElement[0], BodyStateClassesService.ROUTE_STATE_CLASSNAME_PREFIX);
+ bodyElement.addClass(BodyStateClassesService.ROUTE_STATE_CLASSNAME_PREFIX + state.name);
+ }
+
+ /**
+ * Setup the initial class name on body element indicating the current route
+ * and adds event handler to swith this class when the current page/state changes
+ */
+ private setupStateClassToggle() {
+ let bodyElement = this.getBodyElement();
+ bodyElement.addClass(BodyStateClassesService.ROUTE_STATE_CLASSNAME_PREFIX + this.$state.current.name);
+ this.$rootScope.$on("$stateChangeSuccess", this.getStateChangeSuccessHandlerFunction(bodyElement));
+ }
+
+ /**
+ * Setup the initial state of the user-logged css class
+ * and adds events handlers to switch this class when the login events happens
+ */
+ private setupUserLoggedClassToggle() {
+ let bodyElement = this.getBodyElement();
+
+ // get initial logged information from the AuthService
+ // add add the css class when the user is authenticated
+ if (this.authService.isAuthenticated()) {
+ bodyElement.addClass(BodyStateClassesService.USER_LOGGED_CLASSNAME);
+ }
+
+ // listen to the AUTH_EVENTS.loginSuccess and AUTH_EVENTS.logoutSuccess
+ // to switch the css class which indicates user logged in
+ this.$rootScope.$on(AUTH_EVENTS.loginSuccess, () => {
+ bodyElement.addClass(BodyStateClassesService.USER_LOGGED_CLASSNAME);
+ });
+ this.$rootScope.$on(AUTH_EVENTS.logoutSuccess, () => {
+ bodyElement.removeClass(BodyStateClassesService.USER_LOGGED_CLASSNAME);
+ });
+ }
+
+ /**
+ * Returns the user 'body' html Element
+ */
+ private getBodyElement(): ng.IAugmentedJQuery {
+ if (this.bodyElement === null) {
+ this.bodyElement = angular.element(this.$document.find("body"));
+ }
+ return this.bodyElement;
+ }
+}
\ No newline at end of file
diff --git a/src/app/login/auth.service.spec.ts b/src/app/login/auth.service.spec.ts
index 5b417ba..0d7a3bc 100644
--- a/src/app/login/auth.service.spec.ts
+++ b/src/app/login/auth.service.spec.ts
@@ -1,5 +1,3 @@
-
-
import {AuthService, AUTH_EVENTS} from "./";
describe("Services", () => {
diff --git a/src/app/main/main.component.ts b/src/app/main/main.component.ts
index 837c567..5fda8f6 100644
--- a/src/app/main/main.component.ts
+++ b/src/app/main/main.component.ts
@@ -1,4 +1,4 @@
-import {bundle, Component, StateConfig} from "ng-forward";
+import {bundle, Component, StateConfig, Inject} from "ng-forward";
import {ArticleBlogComponent} from "./../article/types/blog/blog.component";
import {ArticleViewComponent} from "./../article/article-default-view.component";
@@ -20,6 +20,7 @@ import {SessionService} from "../login/session.service";
import {NotificationService} from "../shared/services/notification.service";
+import {BodyStateClassesService} from "./../layout/services/body-state-classes.service";
import {Navbar} from "../layout/navbar/navbar";
@@ -41,8 +42,11 @@ import {MainBlockComponent} from "../layout/blocks/main-block/main-block.compone
templateUrl: "app/main/main.html",
providers: [AuthService, SessionService]
})
+@Inject(BodyStateClassesService)
export class MainContentComponent {
-
+ constructor(private bodyStateClassesService: BodyStateClassesService) {
+ bodyStateClassesService.start();
+ }
}
/**
@@ -67,7 +71,7 @@ export class MainContentComponent {
MainBlockComponent, RecentDocumentsBlockComponent, Navbar, ProfileImageBlockComponent,
MembersBlockComponent, NoosferoTemplate, DateFormat, RawHTMLBlockComponent
],
- providers: [AuthService, SessionService, NotificationService]
+ providers: [AuthService, SessionService, NotificationService, BodyStateClassesService]
})
@StateConfig([
{
@@ -90,5 +94,4 @@ export class MainContentComponent {
}
])
export class MainComponent {
-
}
--
libgit2 0.21.2