Commit 139f17f3230455f87dee48e10314a82e7ba16ead

Authored by Ábner Oliveira
1 parent b9f6daf6

added a toolbar under the navbar to add layout change buttons

src/app/admin/designMode.service.spec.ts
... ... @@ -1,31 +0,0 @@
1   -import {DesignModeService} from './designMode.service';
2   -
3   -describe('DesignMode Service', () => {
4   - let service: DesignModeService;
5   -
6   - beforeEach(() => {
7   - service = new DesignModeService();
8   - });
9   -
10   - it('has the designModeOn equals false as default', () => {
11   - expect(service.isInDesignMode()).toBeFalsy();
12   - });
13   -
14   - it('allows set the designMode value', () => {
15   - spyOn(service.onToggle, 'next').and.stub();
16   - service.setInDesignMode(true);
17   - expect(service.isInDesignMode).toBeTruthy();
18   - });
19   -
20   - it('emits the onToggle event when changing the designModeOn property', () => {
21   - spyOn(service.onToggle, 'next').and.stub();
22   - service.setInDesignMode(true);
23   - expect(service.onToggle.next).toHaveBeenCalled();
24   - });
25   -
26   - it('does not emit onToggle event when there is no change on designModeOn property', () => {
27   - spyOn(service.onToggle, 'next').and.stub();
28   - service.setInDesignMode(false);
29   - expect(service.onToggle.next).not.toHaveBeenCalled();
30   - });
31   -});
32 0 \ No newline at end of file
src/app/admin/designMode.service.ts
... ... @@ -1,23 +0,0 @@
1   -import {Component, Injectable, Output, EventEmitter} from 'ng-forward';
2   -import {BodyStateClassesService} from './../layout/services/body-state-classes.service';
3   -
4   -@Injectable()
5   -export class DesignModeService {
6   - @Output() onToggle: EventEmitter<boolean> = new EventEmitter<boolean>();
7   -
8   - private designModeOn: boolean = false;
9   -
10   - isInDesignMode(): boolean {
11   - return this.designModeOn;
12   - }
13   -
14   - setInDesignMode(value: boolean) {
15   - if (this.designModeOn !== value) {
16   - this.designModeOn = value;
17   - this.onToggle.next(this.designModeOn);
18   - }
19   - }
20   -
21   - constructor() {
22   - }
23   -}
24 0 \ No newline at end of file
src/app/admin/designModeToggler.component.spec.ts
... ... @@ -1,59 +0,0 @@
1   -import {ComponentTestHelper, createClass} from './../../spec/component-test-helper';
2   -import * as helpers from './../../spec/helpers';
3   -import {DesignModeTogglerComponent} from './designModeToggler.component';
4   -import {DesignModeService} from './designMode.service';
5   -
6   -describe('DesignModeToggler Component', () => {
7   - const htmlTemplate: string = '<noosfero-design-toggler></noosfero-design-toggler>';
8   -
9   - let helper: ComponentTestHelper<DesignModeTogglerComponent>;
10   - beforeEach(() => {
11   - angular.mock.module('templates');
12   - angular.mock.module('ngSanitize');
13   - angular.mock.module('toggle-switch');
14   - });
15   -
16   - let designModeService: DesignModeService;
17   - beforeEach((done) => {
18   - designModeService = new DesignModeService();
19   - let cls = createClass({
20   - template: htmlTemplate,
21   - directives: [DesignModeTogglerComponent],
22   - providers: [
23   - helpers.createProviderToValue('DesignModeService', designModeService)
24   - ]
25   - });
26   - helper = new ComponentTestHelper<DesignModeTogglerComponent>(cls, done);
27   - });
28   -
29   - it('changes css classes representing the switch is on or off', () => {
30   - expect(helper.debugElement.query('div.switch-animate').hasClass('switch-off')).toBeTruthy();
31   - expect(helper.debugElement.query('div.switch-animate').hasClass('switch-on')).toBeFalsy();
32   - helper.component.inDesignMode = true;
33   - helper.detectChanges();
34   - expect(helper.debugElement.query('div.switch-animate').hasClass('switch-on')).toBeTruthy();
35   - expect(helper.debugElement.query('div.switch-animate').hasClass('switch-off')).toBeFalsy();
36   - });
37   -
38   - it('emits event with value "true" when changing inDesignMode to On', (done) => {
39   - designModeService.onToggle.subscribe((designModeOn: boolean) => {
40   - expect(designModeOn).toBeTruthy();
41   - done();
42   - });
43   - helper.component.inDesignMode = true;
44   - helper.detectChanges();
45   - });
46   -
47   - it('emits events with value "false" when changing inDesignMode to Off', (done) => {
48   - helper.component.inDesignMode = true;
49   - helper.detectChanges();
50   -
51   - designModeService.onToggle.subscribe((designModeOn: boolean) => {
52   - expect(designModeOn).toBeFalsy();
53   - done();
54   - });
55   -
56   - helper.component.inDesignMode = false;
57   - helper.detectChanges();
58   - });
59   -});
60 0 \ No newline at end of file
src/app/admin/designModeToggler.component.ts
... ... @@ -1,24 +0,0 @@
1   -import {Component, Inject} from 'ng-forward';
2   -import {DesignModeService} from './designMode.service';
3   -@Component({
4   - selector: 'noosfero-design-toggler',
5   - templateUrl: 'app/admin/designModeToggler.html'
6   -})
7   -@Inject(DesignModeService)
8   -export class DesignModeTogglerComponent {
9   -
10   - icon: string = "&nbsp;<i class='glyphicon glyphicon-wrench'></i>&nbsp;";
11   -
12   - constructor(private designModeService: DesignModeService) {
13   - }
14   -
15   - private _inDesignMode: boolean = false;
16   -
17   - get inDesignMode(): boolean {
18   - return this.designModeService.isInDesignMode();
19   - };
20   -
21   - set inDesignMode(value: boolean) {
22   - this.designModeService.setInDesignMode(value);
23   - };
24   -}
25 0 \ No newline at end of file
src/app/admin/designModeToggler.html
... ... @@ -1,8 +0,0 @@
1   -<toggle-switch
2   - html="true"
3   - ng-model="ctrl.inDesignMode"
4   - on-label="{{'designMode.toggle.ON' | translate}}"
5   - off-label="{{'designMode.toggle.OFF' | translate}}"
6   - class="switch-small"
7   - knob-label="{{ ctrl.icon + ('designMode.label' | translate) }}">
8   -</toggle-switch>
9 0 \ No newline at end of file
src/app/admin/layout-edit/designMode.service.spec.ts 0 → 100644
... ... @@ -0,0 +1,31 @@
  1 +import {DesignModeService} from './designMode.service';
  2 +
  3 +describe('DesignMode Service', () => {
  4 + let service: DesignModeService;
  5 +
  6 + beforeEach(() => {
  7 + service = new DesignModeService();
  8 + });
  9 +
  10 + it('has the designModeOn equals false as default', () => {
  11 + expect(service.isInDesignMode()).toBeFalsy();
  12 + });
  13 +
  14 + it('allows set the designMode value', () => {
  15 + spyOn(service.onToggle, 'next').and.stub();
  16 + service.setInDesignMode(true);
  17 + expect(service.isInDesignMode).toBeTruthy();
  18 + });
  19 +
  20 + it('emits the onToggle event when changing the designModeOn property', () => {
  21 + spyOn(service.onToggle, 'next').and.stub();
  22 + service.setInDesignMode(true);
  23 + expect(service.onToggle.next).toHaveBeenCalled();
  24 + });
  25 +
  26 + it('does not emit onToggle event when there is no change on designModeOn property', () => {
  27 + spyOn(service.onToggle, 'next').and.stub();
  28 + service.setInDesignMode(false);
  29 + expect(service.onToggle.next).not.toHaveBeenCalled();
  30 + });
  31 +});
0 32 \ No newline at end of file
... ...
src/app/admin/layout-edit/designMode.service.ts 0 → 100644
... ... @@ -0,0 +1,23 @@
  1 +import {Component, Injectable, Output, EventEmitter} from 'ng-forward';
  2 +import {BodyStateClassesService} from '../../layout/services/body-state-classes.service';
  3 +
  4 +@Injectable()
  5 +export class DesignModeService {
  6 + @Output() onToggle: EventEmitter<boolean> = new EventEmitter<boolean>();
  7 +
  8 + private designModeOn: boolean = false;
  9 +
  10 + isInDesignMode(): boolean {
  11 + return this.designModeOn;
  12 + }
  13 +
  14 + setInDesignMode(value: boolean) {
  15 + if (this.designModeOn !== value) {
  16 + this.designModeOn = value;
  17 + this.onToggle.next(this.designModeOn);
  18 + }
  19 + }
  20 +
  21 + constructor() {
  22 + }
  23 +}
0 24 \ No newline at end of file
... ...
src/app/admin/layout-edit/designModeToggler.component.spec.ts 0 → 100644
... ... @@ -0,0 +1,59 @@
  1 +import {ComponentTestHelper, createClass} from '../../../spec/component-test-helper';
  2 +import * as helpers from '../../../spec/helpers';
  3 +import {DesignModeTogglerComponent} from './designModeToggler.component';
  4 +import {DesignModeService} from './designMode.service';
  5 +
  6 +describe('DesignModeToggler Component', () => {
  7 + const htmlTemplate: string = '<noosfero-design-toggler></noosfero-design-toggler>';
  8 +
  9 + let helper: ComponentTestHelper<DesignModeTogglerComponent>;
  10 + beforeEach(() => {
  11 + angular.mock.module('templates');
  12 + angular.mock.module('ngSanitize');
  13 + angular.mock.module('toggle-switch');
  14 + });
  15 +
  16 + let designModeService: DesignModeService;
  17 + beforeEach((done) => {
  18 + designModeService = new DesignModeService();
  19 + let cls = createClass({
  20 + template: htmlTemplate,
  21 + directives: [DesignModeTogglerComponent],
  22 + providers: [
  23 + helpers.createProviderToValue('DesignModeService', designModeService)
  24 + ]
  25 + });
  26 + helper = new ComponentTestHelper<DesignModeTogglerComponent>(cls, done);
  27 + });
  28 +
  29 + it('changes css classes representing the switch is on or off', () => {
  30 + expect(helper.debugElement.query('div.switch-animate').hasClass('switch-off')).toBeTruthy();
  31 + expect(helper.debugElement.query('div.switch-animate').hasClass('switch-on')).toBeFalsy();
  32 + helper.component.inDesignMode = true;
  33 + helper.detectChanges();
  34 + expect(helper.debugElement.query('div.switch-animate').hasClass('switch-on')).toBeTruthy();
  35 + expect(helper.debugElement.query('div.switch-animate').hasClass('switch-off')).toBeFalsy();
  36 + });
  37 +
  38 + it('emits event with value "true" when changing inDesignMode to On', (done) => {
  39 + designModeService.onToggle.subscribe((designModeOn: boolean) => {
  40 + expect(designModeOn).toBeTruthy();
  41 + done();
  42 + });
  43 + helper.component.inDesignMode = true;
  44 + helper.detectChanges();
  45 + });
  46 +
  47 + it('emits events with value "false" when changing inDesignMode to Off', (done) => {
  48 + helper.component.inDesignMode = true;
  49 + helper.detectChanges();
  50 +
  51 + designModeService.onToggle.subscribe((designModeOn: boolean) => {
  52 + expect(designModeOn).toBeFalsy();
  53 + done();
  54 + });
  55 +
  56 + helper.component.inDesignMode = false;
  57 + helper.detectChanges();
  58 + });
  59 +});
0 60 \ No newline at end of file
... ...
src/app/admin/layout-edit/designModeToggler.component.ts 0 → 100644
... ... @@ -0,0 +1,24 @@
  1 +import {Component, Inject} from 'ng-forward';
  2 +import {DesignModeService} from './designMode.service';
  3 +@Component({
  4 + selector: 'noosfero-design-toggler',
  5 + templateUrl: 'app/admin/layout-edit/designModeToggler.html'
  6 +})
  7 +@Inject(DesignModeService)
  8 +export class DesignModeTogglerComponent {
  9 +
  10 + icon: string = "&nbsp;<i class='glyphicon glyphicon-wrench'></i>&nbsp;";
  11 +
  12 + constructor(private designModeService: DesignModeService) {
  13 + }
  14 +
  15 + private _inDesignMode: boolean = false;
  16 +
  17 + get inDesignMode(): boolean {
  18 + return this.designModeService.isInDesignMode();
  19 + };
  20 +
  21 + set inDesignMode(value: boolean) {
  22 + this.designModeService.setInDesignMode(value);
  23 + };
  24 +}
0 25 \ No newline at end of file
... ...
src/app/admin/layout-edit/designModeToggler.html 0 → 100644
... ... @@ -0,0 +1,8 @@
  1 +<toggle-switch
  2 + html="true"
  3 + ng-model="ctrl.inDesignMode"
  4 + on-label="{{'designMode.toggle.ON' | translate}}"
  5 + off-label="{{'designMode.toggle.OFF' | translate}}"
  6 + class="switch-small"
  7 + knob-label="{{ ctrl.icon + ('designMode.label' | translate) }}">
  8 +</toggle-switch>
0 9 \ No newline at end of file
... ...
src/app/article/content-viewer/content-viewer.component.ts
... ... @@ -14,7 +14,7 @@ import {ProfileService} from &quot;../../../lib/ng-noosfero-api/http/profile.service&quot;
14 14 provide('profileService', { useClass: ProfileService })
15 15 ]
16 16 })
17   -@Inject(ArticleService, ProfileService, "$log", "$stateParams")
  17 +@Inject(ArticleService, ProfileService, "$stateParams")
18 18 export class ContentViewerComponent {
19 19  
20 20 @Input()
... ... @@ -23,7 +23,10 @@ export class ContentViewerComponent {
23 23 @Input()
24 24 profile: noosfero.Profile = null;
25 25  
26   - constructor(private articleService: ArticleService, private profileService: ProfileService, private $log: ng.ILogService, private $stateParams: angular.ui.IStateParamsService) {
  26 + constructor(
  27 + private articleService: ArticleService,
  28 + private profileService: ProfileService,
  29 + private $stateParams: angular.ui.IStateParamsService) {
27 30 this.activate();
28 31 }
29 32  
... ...
src/app/layout/navbar/navbar.html
... ... @@ -26,16 +26,16 @@
26 26 <span ng-bind="ctrl.currentUser.person.name"></span> <b class="caret"></b>
27 27 </a>
28 28 <ul class="dropdown-menu" uib-dropdown-menu>
29   - <li>
30   - <a ui-sref="main.profile.info({profile: ctrl.currentUser.person.identifier})"><i class="fa fa-fw fa-user"></i> {{"navbar.profile" | translate}}</a>
31   - </li>
32   - <li>
33   - <a target="_self" ui-sref="main.profile.settings({profile: ctrl.currentUser.person.identifier})"><i class="fa fa-fw fa-gear"></i> {{"navbar.settings" | translate}}</a>
34   - </li>
35   - <li class="divider"></li>
36   - <li>
37   - <a href="#" ng-click="ctrl.logout()"><i class="fa fa-fw fa-power-off"></i> {{"navbar.logout" | translate}}</a>
38   - </li>
  29 + <li>
  30 + <a ui-sref="main.profile.info({profile: ctrl.currentUser.person.identifier})"><i class="fa fa-fw fa-user"></i> {{"navbar.profile" | translate}}</a>
  31 + </li>
  32 + <li>
  33 + <a target="_self" ui-sref="main.profile.settings({profile: ctrl.currentUser.person.identifier})"><i class="fa fa-fw fa-gear"></i> {{"navbar.settings" | translate}}</a>
  34 + </li>
  35 + <li class="divider"></li>
  36 + <li>
  37 + <a href="#" ng-click="ctrl.logout()"><i class="fa fa-fw fa-power-off"></i> {{"navbar.logout" | translate}}</a>
  38 + </li>
39 39 </ul>
40 40 </li>
41 41 </ul>
... ... @@ -43,12 +43,9 @@
43 43 <ul class="nav navbar-nav navbar-right">
44 44 <language-selector class="nav navbar-nav navbar-right"></language-selector>
45 45 </ul>
46   - <ul class="nav navbar-nav navbar-right">
47   - <li class="toggler-container">
48   - <noosfero-design-toggler></noosfero-design-toggler>
49   - </li>
50   - </ul>
51 46 <div ui-view="actions"></div>
52 47 </div>
53 48 </div>
54 49 </nav>
  50 +<div ui-view="toolbar">
  51 +</div>
55 52 \ No newline at end of file
... ...
src/app/layout/navbar/navbar.ts
... ... @@ -4,7 +4,7 @@ import {SessionService, AuthService, AuthController, AuthEvents} from &quot;./../../l
4 4 import {EnvironmentService} from "./../../../lib/ng-noosfero-api/http/environment.service";
5 5 import {SidebarNotificationService} from "../sidebar/sidebar.notification.service";
6 6 import {BodyStateClassesService} from '../services/body-state-classes.service';
7   -import {DesignModeTogglerComponent} from './../../admin/designModeToggler.component';
  7 +import {DesignModeTogglerComponent} from './../../admin/layout-edit/designModeToggler.component';
8 8 import {BootstrapSwitcherComponent, BootstrapSwitcherItem} from './../../shared/components/bootstrap-switcher/bootstrap-switcher.component';
9 9  
10 10 @Component({
... ...
src/app/layout/scss/_layout.scss
... ... @@ -47,4 +47,13 @@ body.noosfero-design-on {
47 47 ul.nav > li.toggler-container {
48 48 position: relative;
49 49 padding-top: 12px;
  50 +}
  51 +
  52 +.noosfero-main-toolbar {
  53 + padding: 5px;
  54 + @include make-row();
  55 + margin-left: 0px;
  56 + margin-right: 0px;
  57 + background-color: #eeeeee;
  58 + background: linear-gradient(top, #eeeeee 0%, #c9d4e4 100%);
50 59 }
51 60 \ No newline at end of file
... ...
src/app/layout/services/body-state-classes.service.spec.ts
... ... @@ -4,7 +4,7 @@ import {AuthService} from &quot;./../../login/auth.service&quot;;
4 4 import {AuthEvents} from "./../../login/auth-events";
5 5  
6 6 import {EventEmitter} from 'ng-forward';
7   -import {DesignModeService} from './../../admin/designMode.service';
  7 +import {DesignModeService} from './../../admin/layout-edit/designMode.service';
8 8  
9 9 describe("BodyStateClasses Service", () => {
10 10  
... ...
src/app/layout/services/body-state-classes.service.ts
... ... @@ -3,7 +3,7 @@ import {AuthEvents} from &quot;../../login/auth-events&quot;;
3 3 import {AuthService} from "./../../login/auth.service";
4 4 import {HtmlUtils} from "../html-utils";
5 5 import {INgForwardJQuery} from 'ng-forward/cjs/util/jqlite-extensions';
6   -import {DesignModeService} from './../../admin/designMode.service';
  6 +import {DesignModeService} from './../../admin/layout-edit/designMode.service';
7 7  
8 8 export interface StartParams {
9 9 skin?: string;
... ...
src/app/profile/profile-toolbar.component.ts 0 → 100644
... ... @@ -0,0 +1,21 @@
  1 +import {Component, Inject, provide} from "ng-forward";
  2 +import {ProfileService} from "../../lib/ng-noosfero-api/http/profile.service";
  3 +
  4 +@Component({
  5 + selector: "profile-toolbar",
  6 + templateUrl: "app/profile/toolbar.html",
  7 + providers: [
  8 + provide('profileService', { useClass: ProfileService })
  9 + ]
  10 +})
  11 +@Inject(ProfileService)
  12 +export class ProfileToolbarComponent {
  13 + profile: noosfero.Profile;
  14 + parentId: number;
  15 +
  16 + constructor(profileService: ProfileService) {
  17 + profileService.getCurrentProfile().then((profile: noosfero.Profile) => {
  18 + this.profile = profile;
  19 + });
  20 + }
  21 +}
... ...
src/app/profile/profile.component.ts
... ... @@ -10,7 +10,7 @@ import {ProfileService} from &quot;../../lib/ng-noosfero-api/http/profile.service&quot;;
10 10 import {NotificationService} from "../shared/services/notification.service";
11 11 import {MyProfileComponent} from "./myprofile.component";
12 12 import {ProfileActionsComponent} from "./profile-actions.component";
13   -
  13 +import {ProfileToolbarComponent} from "./profile-toolbar.component";
14 14 /**
15 15 * @ngdoc controller
16 16 * @name profile.Profile
... ... @@ -42,6 +42,11 @@ import {ProfileActionsComponent} from &quot;./profile-actions.component&quot;;
42 42 templateUrl: "app/profile/navbar-actions.html",
43 43 controller: ProfileActionsComponent,
44 44 controllerAs: "vm"
  45 + },
  46 + "toolbar@main": {
  47 + templateUrl: "app/profile/toolbar.html",
  48 + controller: ProfileToolbarComponent,
  49 + controllerAs: "vm"
45 50 }
46 51 }
47 52 },
... ... @@ -54,6 +59,11 @@ import {ProfileActionsComponent} from &quot;./profile-actions.component&quot;;
54 59 templateUrl: "app/profile/navbar-actions.html",
55 60 controller: ProfileActionsComponent,
56 61 controllerAs: "vm"
  62 + },
  63 + "toolbar@main": {
  64 + templateUrl: "app/profile/toolbar.html",
  65 + controller: ProfileToolbarComponent,
  66 + controllerAs: "vm"
57 67 }
58 68 }
59 69 },
... ... @@ -106,6 +116,11 @@ import {ProfileActionsComponent} from &quot;./profile-actions.component&quot;;
106 116 templateUrl: "app/article/content-viewer/navbar-actions.html",
107 117 controller: ContentViewerActionsComponent,
108 118 controllerAs: "vm"
  119 + },
  120 + "toolbar@main": {
  121 + templateUrl: "app/profile/toolbar.html",
  122 + controller: ProfileToolbarComponent,
  123 + controllerAs: "vm"
109 124 }
110 125 }
111 126 }
... ...
src/app/profile/toolbar.html 0 → 100644
... ... @@ -0,0 +1,4 @@
  1 +<div class="noosfero-main-toolbar" permission="vm.profile.permissions" permission-action="allow_edit">
  2 + <noosfero-design-toggler class="pull-right"></noosfero-design-toggler>
  3 +
  4 +</div>
0 5 \ No newline at end of file
... ...
src/app/shared/components/interfaces.ts 0 → 100644
... ... @@ -0,0 +1,5 @@
  1 +
  2 +
  3 +export interface IComponentWithPermissions {
  4 + permissions: () => string[];
  5 +}
0 6 \ No newline at end of file
... ...
src/app/shared/components/permission/permission.directive.ts
... ... @@ -6,7 +6,7 @@ import {Directive, Inject, Input} from &quot;ng-forward&quot;;
6 6 @Inject('$attrs', '$scope', '$element')
7 7 export class PermissionDirective {
8 8  
9   - constructor($attrs: ng.IAttributes, $scope: ng.IScope, $element: any) {
  9 + constructor($attrs: ng.IAttributes, $scope: ng.IScope, $element: ng.IAugmentedJQuery) {
10 10 $scope.$watch($attrs['permission'], () => {
11 11 let permissions = $scope.$eval($attrs['permission']);
12 12 let permissionAction = $attrs['permissionAction'];
... ...
src/lib/ng-noosfero-api/http/profile.service.ts
... ... @@ -22,7 +22,7 @@ export class ProfileService {
22 22 this._currentProfilePromise.resolve(profile);
23 23 }
24 24  
25   - setCurrentProfileByIdentifier(identifier: string) {
  25 + setCurrentProfileByIdentifier(identifier: string): ng.IPromise<noosfero.Profile> {
26 26 this.resetCurrentProfile();
27 27 return this.getByIdentifier(identifier).then((profile: noosfero.Profile) => {
28 28 this.setCurrentProfile(profile);
... ...
src/lib/ng-noosfero-api/interfaces/article.ts
... ... @@ -14,5 +14,7 @@ namespace noosfero {
14 14 start_date: string;
15 15 end_date: string;
16 16 accept_comments: boolean;
  17 +
  18 + permissions: string[];
17 19 }
18 20 }
... ...
src/lib/ng-noosfero-api/interfaces/modelWithPermissions.ts 0 → 100644
... ... @@ -0,0 +1,5 @@
  1 +namespace noosfero {
  2 + export interface ModelWithPermissions {
  3 + permissions: string[];
  4 + }
  5 +}
0 6 \ No newline at end of file
... ...
src/lib/ng-noosfero-api/interfaces/profile.ts
... ... @@ -78,5 +78,7 @@ namespace noosfero {
78 78 * @returns {string} The Profile footer
79 79 */
80 80 custom_footer: string;
  81 +
  82 + permissions: string[];
81 83 }
82 84 }
... ...