body-state-classes.service.ts 5.33 KB
import {Directive, Inject, Injectable} from "ng-forward";
import {AuthEvents} from "../../login/auth-events";
import {AuthService} from "./../../login/auth.service";
import {HtmlUtils} from "../html-utils";
import {INgForwardJQuery} from 'ng-forward/cjs/util/jqlite-extensions';
import {DesignModeService} from './../../admin/layout-edit/designMode.service';

export interface StartParams {
    skin?: string;
}

/**
 * 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
 *
 *    Show the all content in full mode:
 *         - full-content
 */
@Injectable()
@Inject("$rootScope", "$document", "$state", AuthService, DesignModeService)
export class BodyStateClassesService {

    private started: boolean = false;
    private skin: string;

    public static get DESIGN_MODE_ON_CLASSNAME(): string { return "noosfero-design-on"; }
    public static get USER_LOGGED_CLASSNAME(): string { return "noosfero-user-logged"; }
    public static get ROUTE_STATE_CLASSNAME_PREFIX(): string { return "noosfero-route-"; }
    public static get CONTENT_WRAPPER_FULL(): string { return "full-content"; }

    private bodyElement: ng.IAugmentedJQuery = null;

    constructor(
        private $rootScope: ng.IRootScopeService,
        private $document: ng.IDocumentService,
        private $state: ng.ui.IStateService,
        private authService: AuthService,
        private designModeService: DesignModeService
    ) {
    }

    start(config?: StartParams) {
        if (!this.started) {
            this.setupUserLoggedClassToggle();
            this.setupStateClassToggle();
            this.setupDesignModeClassToggle();
            if (config) {
                this.setThemeSkin(config.skin);
            }
            this.started = true;
        }
    }

    setThemeSkin(skin: string) {
        this.getBodyElement().addClass(skin);
    }

    addContentClass(addClass: boolean, className?: string): BodyStateClassesService {

        let fullContentClass: string = className || BodyStateClassesService.CONTENT_WRAPPER_FULL;
        let contentWrapper = this.getContentWrapper();

        if (contentWrapper) {
            if (addClass) {
                contentWrapper.addClass(fullContentClass);
            } else {
                contentWrapper.removeClass(fullContentClass);
            }
        }
        return this;
    }

    private 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, toState);
        };
    }

    private 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 listeners to the desigModeService to add class on the Body Element
     * indicating the user activated the designMode
     */
    private setupDesignModeClassToggle() {
        this.designModeService.onToggle.subscribe((designOn: boolean) => {
            if (designOn) {
                this.getBodyElement().addClass(BodyStateClassesService.DESIGN_MODE_ON_CLASSNAME);
            } else {
                this.getBodyElement().removeClass(BodyStateClassesService.DESIGN_MODE_ON_CLASSNAME);
            }
        });
    }

    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);
        }

        // to switch the css class which indicates user logged in
        this.authService.subscribe(AuthEvents[AuthEvents.loginSuccess], () => {
            bodyElement.addClass(BodyStateClassesService.USER_LOGGED_CLASSNAME);
        });

        this.authService.subscribe(AuthEvents[AuthEvents.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;
    }

    private getContentWrapper(selector?: string): INgForwardJQuery {
        let doc = <INgForwardJQuery>angular.element(this.$document);
        return doc.query(selector || '.content-wrapper');
    }
}