Commit ade7c078b4032f09e1e33e6c2e4c00906939724c

Authored by Francisco Júnior
2 parents 0b078626 9ab71161

Merge branch 'fix-edit-mode-state' into 'master'

Fix edit mode state

See merge request !46
src/app/admin/layout-edit/designMode.service.spec.ts
1 1 import {DesignModeService} from './designMode.service';
  2 +import {INoosferoLocalStorage} from "./../../shared/models/interfaces";
2 3  
3 4 describe('DesignMode Service', () => {
4 5 let service: DesignModeService;
5 6  
  7 + let $localStorage = <INoosferoLocalStorage>{ currentUser: null, settings: { designMode: false } };
6 8 beforeEach(() => {
7   - service = new DesignModeService();
  9 + service = new DesignModeService($localStorage);
8 10 });
9 11  
10 12 it('has the designModeOn equals false as default', () => {
... ... @@ -18,12 +20,14 @@ describe(&#39;DesignMode Service&#39;, () =&gt; {
18 20 });
19 21  
20 22 it('emits the onToggle event when changing the designModeOn property', () => {
  23 + service.setInDesignMode(false);
21 24 spyOn(service.onToggle, 'next').and.stub();
22 25 service.setInDesignMode(true);
23 26 expect(service.onToggle.next).toHaveBeenCalled();
24 27 });
25 28  
26 29 it('does not emit onToggle event when there is no change on designModeOn property', () => {
  30 + service.setInDesignMode(false);
27 31 spyOn(service.onToggle, 'next').and.stub();
28 32 service.setInDesignMode(false);
29 33 expect(service.onToggle.next).not.toHaveBeenCalled();
... ...
src/app/admin/layout-edit/designMode.service.ts
1   -import {Injectable, Output, EventEmitter} from 'ng-forward';
  1 +import {Injectable, Output, EventEmitter, Inject} from 'ng-forward';
  2 +import {INoosferoLocalStorage} from "./../../shared/models/interfaces";
2 3  
3 4 @Injectable()
  5 +@Inject("$localStorage")
4 6 export class DesignModeService {
5 7 @Output() onToggle: EventEmitter<boolean> = new EventEmitter<boolean>();
6 8  
7   - private designModeOn: boolean = false;
8   -
9 9 isInDesignMode(): boolean {
10   - return this.designModeOn;
  10 + return this.$localStorage.settings.designModeOn;
  11 + }
  12 +
  13 + destroy() {
  14 + delete this.$localStorage.settings;
  15 + this.$localStorage.settings = {};
11 16 }
12 17  
13 18 setInDesignMode(value: boolean) {
14   - if (this.designModeOn !== value) {
15   - this.designModeOn = value;
16   - this.onToggle.next(this.designModeOn);
  19 + if (this.$localStorage.settings.designModeOn !== value) {
  20 + this.$localStorage.settings.designModeOn = value;
  21 + this.onToggle.next(value);
17 22 }
18 23 }
19 24  
20   - constructor() {
  25 + constructor(private $localStorage: INoosferoLocalStorage) {
  26 + if (!this.$localStorage.settings) {
  27 + this.$localStorage.settings = {};
  28 + }
21 29 }
22 30 }
... ...
src/app/admin/layout-edit/designModeToggler.component.spec.ts
... ... @@ -2,6 +2,7 @@ import {ComponentTestHelper, createClass} from &#39;../../../spec/component-test-hel
2 2 import * as helpers from '../../../spec/helpers';
3 3 import {DesignModeTogglerComponent} from './designModeToggler.component';
4 4 import {DesignModeService} from './designMode.service';
  5 +import {INoosferoLocalStorage} from "./../../shared/models/interfaces";
5 6  
6 7 describe('DesignModeToggler Component', () => {
7 8 const htmlTemplate: string = '<noosfero-design-toggler></noosfero-design-toggler>';
... ... @@ -14,13 +15,15 @@ describe(&#39;DesignModeToggler Component&#39;, () =&gt; {
14 15 });
15 16  
16 17 let designModeService: DesignModeService;
  18 + let $localStorage = <INoosferoLocalStorage>{ currentUser: null, settings: { designMode: false } };
17 19 beforeEach((done) => {
18   - designModeService = new DesignModeService();
  20 + designModeService = new DesignModeService($localStorage);
19 21 let cls = createClass({
20 22 template: htmlTemplate,
21 23 directives: [DesignModeTogglerComponent],
22 24 providers: [
23   - helpers.createProviderToValue('DesignModeService', designModeService)
  25 + helpers.createProviderToValue('DesignModeService', designModeService),
  26 + helpers.createProviderToValue('AuthService', helpers.mocks.authService),
24 27 ]
25 28 });
26 29 helper = new ComponentTestHelper<DesignModeTogglerComponent>(cls, done);
... ... @@ -36,6 +39,7 @@ describe(&#39;DesignModeToggler Component&#39;, () =&gt; {
36 39 });
37 40  
38 41 it('emits event with value "true" when changing inDesignMode to On', (done) => {
  42 + designModeService.setInDesignMode(false);
39 43 designModeService.onToggle.subscribe((designModeOn: boolean) => {
40 44 expect(designModeOn).toBeTruthy();
41 45 done();
... ...
src/app/admin/layout-edit/designModeToggler.component.ts
1 1 import {Component, Inject} from 'ng-forward';
2 2 import {DesignModeService} from './designMode.service';
  3 +import {AuthService, AuthEvents} from '../../login'
  4 +
3 5 @Component({
4 6 selector: 'noosfero-design-toggler',
5 7 templateUrl: 'app/admin/layout-edit/designModeToggler.html'
6 8 })
7   -@Inject(DesignModeService)
  9 +@Inject(DesignModeService, AuthService)
8 10 export class DesignModeTogglerComponent {
9 11  
10 12 icon: string = "&nbsp;<i class='glyphicon glyphicon-wrench'></i>&nbsp;";
11 13  
12   - constructor(private designModeService: DesignModeService) {
  14 + constructor(private designModeService: DesignModeService, private authService: AuthService) {
  15 + this.authService.subscribe(AuthEvents[AuthEvents.logoutSuccess], () => {
  16 + this.designModeService.destroy();
  17 + });
13 18 }
14 19  
15 20 private _inDesignMode: boolean = false;
... ...
src/app/layout/blocks/block.component.spec.ts
... ... @@ -2,6 +2,7 @@ import {Component} from &#39;ng-forward&#39;;
2 2 import {BlockComponent} from './block.component';
3 3 import * as helpers from "../../../spec/helpers";
4 4 import {ComponentTestHelper, createClass} from '../../../spec/component-test-helper';
  5 +import {DesignModeService} from '../../admin/layout-edit/designMode.service';
5 6  
6 7 const htmlTemplate: string = '<noosfero-block [block]="ctrl.block" [owner]="ctrl.profile"></noosfero-block>';
7 8  
... ... @@ -32,16 +33,17 @@ describe(&quot;Boxes Component&quot;, () =&gt; {
32 33 helpers.createProviderToValue('TranslatorService', translatorService),
33 34 helpers.createProviderToValue('$uibModal', helpers.mocks.$modal),
34 35 helpers.createProviderToValue('BlockService', blockService),
35   - helpers.createProviderToValue('NotificationService', helpers.mocks.notificationService)
  36 + helpers.createProviderToValue('NotificationService', helpers.mocks.notificationService),
  37 + helpers.createProviderToValue('DesignModeService', helpers.mocks.designModeService)
36 38 ]
37 39 });
38 40 helper = new ComponentTestHelper<BlockComponent>(cls, done);
39 41 });
40   -
41 42 let translatorService = jasmine.createSpyObj("translatorService", ["currentLanguage"]);
42 43 let blockService = jasmine.createSpyObj("blockService", ["update"]);
43 44 let state = jasmine.createSpyObj("state", ["current"]);
44 45 state.current = { name: "" };
  46 +
45 47  
46 48 it("set isHomepage as false by default", () => {
47 49 expect(helper.component.isHomepage).toBeFalsy();
... ...
src/app/layout/blocks/block.component.ts
... ... @@ -11,7 +11,8 @@ import { DesignModeService } from &quot;../../admin/layout-edit/designMode.service&quot;;
11 11 templateUrl: 'app/layout/blocks/block.html',
12 12 directives: [BlockEditionComponent]
13 13 })
14   -@Inject("$uibModal", "$scope", "$state", "$rootScope", BlockService, NotificationService, AuthService, SessionService, TranslatorService, DesignModeService)
  14 +@Inject("$uibModal", "$scope", "$state", "$rootScope", BlockService, NotificationService,
  15 +AuthService, SessionService, TranslatorService, DesignModeService)
15 16 export class BlockComponent {
16 17  
17 18 @Input() block: noosfero.Block;
... ...
src/app/layout/blocks/block.html
1   -<div ng-show="ctrl.canDisplay() || ctrl.editionMode || ctrl.designMode" ng-class="{'invisible-block': !ctrl.canDisplay()}" class="noosfero-block" ng-mouseover="displayActions = true" ng-mouseleave="displayActions = false">
  1 +<div ng-show="ctrl.canDisplay() || ctrl.inEditMode() || ctrl.designMode" ng-class="{'invisible-block': !ctrl.canDisplay()}" class="noosfero-block" ng-mouseover="displayActions = true" ng-mouseleave="displayActions = false">
2 2 <div ng-show="displayActions" class="actions block-actions" permission="ctrl.block.permissions" permission-action="allow_edit">
3 3 <button type="submit" class="btn btn-xs btn-default" ng-click="ctrl.openEdit()"><i class="fa fa-edit fa-fw"></i></button>
4 4 </div>
... ...
src/app/layout/navbar/navbar.spec.ts
... ... @@ -9,6 +9,8 @@ import {SessionService, AuthService, AuthController, AuthEvents} from &quot;./../../l
9 9  
10 10 import events from 'ng-forward/cjs/events/events';
11 11  
  12 +import {DesignModeService} from '../../admin/layout-edit/designMode.service';
  13 +
12 14 describe("Components", () => {
13 15  
14 16 describe("Navbar Component", () => {
... ... @@ -22,6 +24,7 @@ describe(&quot;Components&quot;, () =&gt; {
22 24 let authService: any;
23 25 let stateService: any;
24 26 let sessionService: SessionService;
  27 + let designModeService: DesignModeService;
25 28  
26 29 let provideFunc = provide;
27 30  
... ... @@ -37,6 +40,7 @@ describe(&quot;Components&quot;, () =&gt; {
37 40 authService = helpers.mocks.authService;
38 41 stateService = jasmine.createSpyObj("$state", ["go"]);
39 42 sessionService = <any>helpers.mocks.sessionWithCurrentUser(user);
  43 + designModeService = helpers.mocks.designModeService;
40 44 });
41 45  
42 46  
... ... @@ -76,6 +80,9 @@ describe(&quot;Components&quot;, () =&gt; {
76 80 }),
77 81 provide('TranslatorService', {
78 82 useValue: helpers.mocks.translatorService
  83 + }),
  84 + provide('DesignModeService', {
  85 + useValue: helpers.mocks.designModeService
79 86 })
80 87 ].concat(helpers.provideFilters("translateFilter")),
81 88 directives: [Navbar],
... ...
src/app/layout/services/body-state-classes.service.spec.ts
... ... @@ -5,11 +5,13 @@ import {AuthEvents} from &quot;./../../login/auth-events&quot;;
5 5  
6 6 import {EventEmitter} from 'ng-forward';
7 7 import {DesignModeService} from './../../admin/layout-edit/designMode.service';
  8 +import {INoosferoLocalStorage} from "./../../shared/models/interfaces";
8 9  
9 10 describe("BodyStateClasses Service", () => {
10 11  
11 12 let currentStateName = "main";
12 13 let bodyStateClasseService: BodyStateClassesService;
  14 + let $localStorage = <INoosferoLocalStorage>{ currentUser: null, settings: { designMode: false } };
13 15 let $rootScope: ng.IRootScopeService = <any>{},
14 16 $document: ng.IDocumentService = <any>{},
15 17 $state: ng.ui.IStateService = <any>{
... ... @@ -20,7 +22,8 @@ describe(&quot;BodyStateClasses Service&quot;, () =&gt; {
20 22 authService: any = helpers.mocks.authService,
21 23 bodyEl: { className: string },
22 24 bodyElJq: any,
23   - designModeService = new DesignModeService();
  25 +
  26 + designModeService = new DesignModeService($localStorage);
24 27  
25 28  
26 29  
... ...
src/app/login/session.service.spec.ts
... ... @@ -13,7 +13,7 @@ describe(&quot;Services&quot;, () =&gt; {
13 13 let $log: any;
14 14  
15 15 beforeEach(() => {
16   - $localStorage = <INoosferoLocalStorage>{ currentUser: null };
  16 + $localStorage = <INoosferoLocalStorage>{ currentUser: null, settings: null };
17 17 $log = jasmine.createSpyObj('$log', ['debug']);
18 18 });
19 19  
... ...
src/app/login/session.service.ts
... ... @@ -16,6 +16,7 @@ export class SessionService {
16 16  
17 17 destroy() {
18 18 delete this.$localStorage.currentUser;
  19 + delete this.$localStorage.settings;
19 20 };
20 21  
21 22 currentUser(): noosfero.User {
... ...
src/app/profile/custom-content/custom-content.component.spec.ts
1 1 import {CustomContentComponent} from './custom-content.component';
2 2 import {ComponentTestHelper, createClass} from '../../../spec/component-test-helper';
3 3 import * as helpers from "../../../spec/helpers";
  4 +import {DesignModeService} from '../../admin/layout-edit/designMode.service';
4 5  
5 6 const htmlTemplate: string = '<custom-content [attribute]="\'custom_footer\'" [profile]="ctrl.profile"></custom-content>';
6 7  
... ... @@ -14,6 +15,7 @@ describe(&quot;Components&quot;, () =&gt; {
14 15 beforeEach((done) => {
15 16 let profileService = jasmine.createSpyObj("profileService", ["update"]);
16 17 let notificationService = jasmine.createSpyObj("notificationService", ["success"]);
  18 + let designModeService = { isInDesignMode: () => { return true; }};
17 19 let properties = { profile: { custom_footer: "footer" } };
18 20 let cls = createClass({
19 21 template: htmlTemplate,
... ... @@ -22,7 +24,8 @@ describe(&quot;Components&quot;, () =&gt; {
22 24 providers: [
23 25 helpers.createProviderToValue("$uibModal", helpers.mocks.$modal),
24 26 helpers.createProviderToValue("ProfileService", profileService),
25   - helpers.createProviderToValue("NotificationService", notificationService)
  27 + helpers.createProviderToValue("NotificationService", notificationService),
  28 + helpers.createProviderToValue("DesignModeService", designModeService)
26 29 ]
27 30 });
28 31 helper = new ComponentTestHelper<CustomContentComponent>(cls, done);
... ...
src/app/profile/custom-content/custom-content.component.ts
... ... @@ -20,7 +20,6 @@ export class CustomContentComponent {
20 20  
21 21 content: string;
22 22 originalContent: string;
23   - editionMode = false;
24 23 private modalInstance: any = null;
25 24  
26 25 constructor(private $uibModal: any,
... ... @@ -35,9 +34,10 @@ export class CustomContentComponent {
35 34 }, () => {
36 35 if (this.profile) this.content = (<any>this.profile)[this.attribute];
37 36 });
38   - this.designModeService.onToggle.subscribe((designModeOn: boolean) => {
39   - this.editionMode = designModeOn;
40   - });
  37 + }
  38 +
  39 + inEditMode() {
  40 + return this.designModeService.isInDesignMode();
41 41 }
42 42  
43 43 openEdit() {
... ...
src/app/profile/custom-content/custom-content.html
1 1 <div class="custom-content">
2   - <div class="actions" permission="ctrl.profile.permissions" permission-action="allow_edit" ng-show="ctrl.editionMode">
  2 + <div class="actions" permission="ctrl.profile.permissions" permission-action="allow_edit" ng-show="ctrl.inEditMode()">
3 3 <button type="submit" class="btn btn-xs btn-default" ng-click="ctrl.openEdit()"><i class="fa fa-edit fa-fw"></i> {{ctrl.label | translate}}</button>
4 4 </div>
5 5 <div class="content" ng-bind-html="ctrl.content"></div>
... ...
src/app/shared/models/interfaces.ts
... ... @@ -8,4 +8,5 @@ export interface UserResponse {
8 8  
9 9 export interface INoosferoLocalStorage extends angular.storage.ILocalStorageService {
10 10 currentUser: noosfero.User;
  11 + settings: any;
11 12 }
... ...
src/spec/mocks.ts
... ... @@ -193,6 +193,17 @@ export var mocks: any = {
193 193 currentUser: () => { return user; }
194 194 };
195 195 },
  196 + designModeService: {
  197 + modeFn: null,
  198 + onToggle: {
  199 + subscribe: (fn: Function) => {
  200 + mocks.designModeService.modeFn = fn;
  201 + },
  202 + next: (param: any) => {
  203 + mocks.designModeService.modeFn(param);
  204 + }
  205 + }
  206 + },
196 207 $translate: {
197 208 use: (lang?: string) => {
198 209 return lang ? Promise.resolve(lang) : "en";
... ...