Compare View
Commits (8)
-
…designModeToggler Component
-
The use of bootstrap to start the application broke the startup process.
Showing
27 changed files
Show diff stats
bower.json
@@ -35,9 +35,10 @@ | @@ -35,9 +35,10 @@ | ||
35 | "angular-i18n": "^1.5.0", | 35 | "angular-i18n": "^1.5.0", |
36 | "angular-load": "^0.4.1", | 36 | "angular-load": "^0.4.1", |
37 | "angular-translate-interpolation-messageformat": "^2.10.0", | 37 | "angular-translate-interpolation-messageformat": "^2.10.0", |
38 | - "angular-bind-html-compile": "^1.2.1", | ||
39 | - "angular-click-outside": "^2.7.1", | ||
40 | - "ng-ckeditor": "^0.2.1" | 38 | + "angular-bind-html-compile": "^1.2.1", |
39 | + "angular-click-outside": "^2.7.1", | ||
40 | + "ng-ckeditor": "^0.2.1", | ||
41 | + "angular-bootstrap-toggle-switch": "^0.5.6" | ||
41 | }, | 42 | }, |
42 | "devDependencies": { | 43 | "devDependencies": { |
43 | "angular-mocks": "~1.5.0" | 44 | "angular-mocks": "~1.5.0" |
@@ -0,0 +1,31 @@ | @@ -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 | \ No newline at end of file | 32 | \ No newline at end of file |
@@ -0,0 +1,23 @@ | @@ -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 | \ No newline at end of file | 24 | \ No newline at end of file |
src/app/admin/layout-edit/designModeToggler.component.spec.ts
0 → 100644
@@ -0,0 +1,59 @@ | @@ -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 | \ No newline at end of file | 60 | \ No newline at end of file |
src/app/admin/layout-edit/designModeToggler.component.ts
0 → 100644
@@ -0,0 +1,24 @@ | @@ -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 = " <i class='glyphicon glyphicon-wrench'></i> "; | ||
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 | \ No newline at end of file | 25 | \ No newline at end of file |
@@ -0,0 +1,8 @@ | @@ -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 | \ No newline at end of file | 9 | \ No newline at end of file |
src/app/article/content-viewer/content-viewer.component.ts
@@ -14,7 +14,7 @@ import {ProfileService} from "../../../lib/ng-noosfero-api/http/profile.service" | @@ -14,7 +14,7 @@ import {ProfileService} from "../../../lib/ng-noosfero-api/http/profile.service" | ||
14 | provide('profileService', { useClass: ProfileService }) | 14 | provide('profileService', { useClass: ProfileService }) |
15 | ] | 15 | ] |
16 | }) | 16 | }) |
17 | -@Inject(ArticleService, ProfileService, "$log", "$stateParams") | 17 | +@Inject(ArticleService, ProfileService, "$stateParams") |
18 | export class ContentViewerComponent { | 18 | export class ContentViewerComponent { |
19 | 19 | ||
20 | @Input() | 20 | @Input() |
@@ -23,7 +23,10 @@ export class ContentViewerComponent { | @@ -23,7 +23,10 @@ export class ContentViewerComponent { | ||
23 | @Input() | 23 | @Input() |
24 | profile: noosfero.Profile = null; | 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 | this.activate(); | 30 | this.activate(); |
28 | } | 31 | } |
29 | 32 |
src/app/layout/navbar/navbar.html
@@ -26,19 +26,20 @@ | @@ -26,19 +26,20 @@ | ||
26 | <span ng-bind="ctrl.currentUser.person.name"></span> <b class="caret"></b> | 26 | <span ng-bind="ctrl.currentUser.person.name"></span> <b class="caret"></b> |
27 | </a> | 27 | </a> |
28 | <ul class="dropdown-menu" uib-dropdown-menu> | 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 | </ul> | 39 | </ul> |
40 | </li> | 40 | </li> |
41 | </ul> | 41 | </ul> |
42 | + | ||
42 | <ul class="nav navbar-nav navbar-right"> | 43 | <ul class="nav navbar-nav navbar-right"> |
43 | <language-selector class="nav navbar-nav navbar-right"></language-selector> | 44 | <language-selector class="nav navbar-nav navbar-right"></language-selector> |
44 | </ul> | 45 | </ul> |
@@ -49,3 +50,5 @@ | @@ -49,3 +50,5 @@ | ||
49 | </div> | 50 | </div> |
50 | </div> | 51 | </div> |
51 | </nav> | 52 | </nav> |
53 | +<div ui-view="toolbar"> | ||
54 | +</div> | ||
52 | \ No newline at end of file | 55 | \ No newline at end of file |
src/app/layout/navbar/navbar.ts
@@ -4,11 +4,13 @@ import {SessionService, AuthService, AuthController, AuthEvents} from "./../../l | @@ -4,11 +4,13 @@ import {SessionService, AuthService, AuthController, AuthEvents} from "./../../l | ||
4 | import {EnvironmentService} from "./../../../lib/ng-noosfero-api/http/environment.service"; | 4 | import {EnvironmentService} from "./../../../lib/ng-noosfero-api/http/environment.service"; |
5 | import {SidebarNotificationService} from "../sidebar/sidebar.notification.service"; | 5 | import {SidebarNotificationService} from "../sidebar/sidebar.notification.service"; |
6 | import {BodyStateClassesService} from '../services/body-state-classes.service'; | 6 | import {BodyStateClassesService} from '../services/body-state-classes.service'; |
7 | +import {DesignModeTogglerComponent} from './../../admin/layout-edit/designModeToggler.component'; | ||
8 | +import {BootstrapSwitcherComponent, BootstrapSwitcherItem} from './../../shared/components/bootstrap-switcher/bootstrap-switcher.component'; | ||
7 | 9 | ||
8 | @Component({ | 10 | @Component({ |
9 | selector: "acme-navbar", | 11 | selector: "acme-navbar", |
10 | templateUrl: "app/layout/navbar/navbar.html", | 12 | templateUrl: "app/layout/navbar/navbar.html", |
11 | - directives: [LanguageSelectorComponent], | 13 | + directives: [LanguageSelectorComponent, DesignModeTogglerComponent, BootstrapSwitcherComponent], |
12 | providers: [AuthService, SessionService, SidebarNotificationService, EnvironmentService] | 14 | providers: [AuthService, SessionService, SidebarNotificationService, EnvironmentService] |
13 | }) | 15 | }) |
14 | @Inject("$uibModal", AuthService, "SessionService", "$state", SidebarNotificationService, BodyStateClassesService, EnvironmentService) | 16 | @Inject("$uibModal", AuthService, "SessionService", "$state", SidebarNotificationService, BodyStateClassesService, EnvironmentService) |
@@ -18,7 +20,6 @@ export class Navbar { | @@ -18,7 +20,6 @@ export class Navbar { | ||
18 | private modalInstance: any = null; | 20 | private modalInstance: any = null; |
19 | public showHamburger: boolean = false; | 21 | public showHamburger: boolean = false; |
20 | public currentEnvironment: noosfero.Environment = <any>{ name: '' }; | 22 | public currentEnvironment: noosfero.Environment = <any>{ name: '' }; |
21 | - | ||
22 | /** | 23 | /** |
23 | * | 24 | * |
24 | */ | 25 | */ |
src/app/layout/scss/_layout.scss
@@ -35,3 +35,24 @@ | @@ -35,3 +35,24 @@ | ||
35 | padding: 0 20px 20px 20px; | 35 | padding: 0 20px 20px 20px; |
36 | } | 36 | } |
37 | } | 37 | } |
38 | + | ||
39 | + | ||
40 | +body.noosfero-design-on { | ||
41 | + | ||
42 | + div.content-wrapper { | ||
43 | + opacity: 0.5; | ||
44 | + } | ||
45 | +} | ||
46 | + | ||
47 | +ul.nav > li.toggler-container { | ||
48 | + position: relative; | ||
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: #edecec; | ||
58 | +} | ||
38 | \ No newline at end of file | 59 | \ No newline at end of file |
src/app/layout/scss/skins/_whbl.scss
@@ -281,6 +281,31 @@ $whbl-font-color: #16191c; | @@ -281,6 +281,31 @@ $whbl-font-color: #16191c; | ||
281 | .pace .pace-progress { | 281 | .pace .pace-progress { |
282 | background-color: #fff; | 282 | background-color: #fff; |
283 | } | 283 | } |
284 | + | ||
285 | + noosfero-design-toggler .ats-switch .knob i { | ||
286 | + color: #999999; | ||
287 | + } | ||
288 | + | ||
289 | + .ats-switch .knob { | ||
290 | + padding-right: 15px; | ||
291 | + } | ||
292 | + | ||
293 | + .ats-switch .glyphicon { | ||
294 | + top: 2px; | ||
295 | + } | ||
296 | + | ||
297 | + .ats-switch .switch-left { | ||
298 | + background-color: #41b941; | ||
299 | + font-weight: bold; | ||
300 | + color: white; | ||
301 | + } | ||
302 | + | ||
303 | + .ats-switch .switch-right { | ||
304 | + background-color: #ce3b3b; | ||
305 | + font-weight: bold; | ||
306 | + color: white; | ||
307 | + } | ||
308 | + | ||
284 | } | 309 | } |
285 | .rtl.skin-whbl #content-wrapper { | 310 | .rtl.skin-whbl #content-wrapper { |
286 | border-left: 0; | 311 | border-left: 0; |
src/app/layout/services/body-state-classes.service.spec.ts
@@ -4,7 +4,7 @@ import {AuthService} from "./../../login/auth.service"; | @@ -4,7 +4,7 @@ import {AuthService} from "./../../login/auth.service"; | ||
4 | import {AuthEvents} from "./../../login/auth-events"; | 4 | import {AuthEvents} from "./../../login/auth-events"; |
5 | 5 | ||
6 | import {EventEmitter} from 'ng-forward'; | 6 | import {EventEmitter} from 'ng-forward'; |
7 | - | 7 | +import {DesignModeService} from './../../admin/layout-edit/designMode.service'; |
8 | 8 | ||
9 | describe("BodyStateClasses Service", () => { | 9 | describe("BodyStateClasses Service", () => { |
10 | 10 | ||
@@ -19,10 +19,13 @@ describe("BodyStateClasses Service", () => { | @@ -19,10 +19,13 @@ describe("BodyStateClasses Service", () => { | ||
19 | }, | 19 | }, |
20 | authService: any = helpers.mocks.authService, | 20 | authService: any = helpers.mocks.authService, |
21 | bodyEl: { className: string }, | 21 | bodyEl: { className: string }, |
22 | - bodyElJq: any; | 22 | + bodyElJq: any, |
23 | + designModeService = new DesignModeService(); | ||
24 | + | ||
25 | + | ||
23 | 26 | ||
24 | let getService = (): BodyStateClassesService => { | 27 | let getService = (): BodyStateClassesService => { |
25 | - return new BodyStateClassesService($rootScope, $document, $state, authService); | 28 | + return new BodyStateClassesService($rootScope, $document, $state, authService, designModeService); |
26 | }; | 29 | }; |
27 | 30 | ||
28 | beforeEach(() => { | 31 | beforeEach(() => { |
@@ -168,4 +171,30 @@ describe("BodyStateClasses Service", () => { | @@ -168,4 +171,30 @@ describe("BodyStateClasses Service", () => { | ||
168 | 171 | ||
169 | expect(contentWrapperMock.removeClass).toHaveBeenCalledWith(BodyStateClassesService.CONTENT_WRAPPER_FULL); | 172 | expect(contentWrapperMock.removeClass).toHaveBeenCalledWith(BodyStateClassesService.CONTENT_WRAPPER_FULL); |
170 | }); | 173 | }); |
174 | + | ||
175 | + it("should add the class noosfero-design-on when designMode is changed to true", () => { | ||
176 | + let fnOnToggle: Function = null; | ||
177 | + designModeService.onToggle = <any> { | ||
178 | + subscribe: (fn: Function) => { | ||
179 | + fnOnToggle = fn; | ||
180 | + }, | ||
181 | + next: (value: boolean) => { | ||
182 | + fnOnToggle.apply(designModeService, [value]); | ||
183 | + } | ||
184 | + }; | ||
185 | + | ||
186 | + let service = getService(); | ||
187 | + | ||
188 | + bodyElJq.addClass = jasmine.createSpy("addClass"); | ||
189 | + bodyElJq.removeClass = jasmine.createSpy("removeClass"); | ||
190 | + service["bodyElement"] = bodyElJq; | ||
191 | + | ||
192 | + service.start(); | ||
193 | + | ||
194 | + debugger; | ||
195 | + designModeService.setInDesignMode(true); | ||
196 | + | ||
197 | + | ||
198 | + expect(bodyElJq.addClass).toHaveBeenCalledWith(BodyStateClassesService.DESIGN_MODE_ON_CLASSNAME); | ||
199 | + }); | ||
171 | }); | 200 | }); |
src/app/layout/services/body-state-classes.service.ts
@@ -3,6 +3,7 @@ import {AuthEvents} from "../../login/auth-events"; | @@ -3,6 +3,7 @@ import {AuthEvents} from "../../login/auth-events"; | ||
3 | import {AuthService} from "./../../login/auth.service"; | 3 | import {AuthService} from "./../../login/auth.service"; |
4 | import {HtmlUtils} from "../html-utils"; | 4 | import {HtmlUtils} from "../html-utils"; |
5 | import {INgForwardJQuery} from 'ng-forward/cjs/util/jqlite-extensions'; | 5 | import {INgForwardJQuery} from 'ng-forward/cjs/util/jqlite-extensions'; |
6 | +import {DesignModeService} from './../../admin/layout-edit/designMode.service'; | ||
6 | 7 | ||
7 | export interface StartParams { | 8 | export interface StartParams { |
8 | skin?: string; | 9 | skin?: string; |
@@ -22,12 +23,13 @@ export interface StartParams { | @@ -22,12 +23,13 @@ export interface StartParams { | ||
22 | * - full-content | 23 | * - full-content |
23 | */ | 24 | */ |
24 | @Injectable() | 25 | @Injectable() |
25 | -@Inject("$rootScope", "$document", "$state", AuthService) | 26 | +@Inject("$rootScope", "$document", "$state", AuthService, DesignModeService) |
26 | export class BodyStateClassesService { | 27 | export class BodyStateClassesService { |
27 | 28 | ||
28 | private started: boolean = false; | 29 | private started: boolean = false; |
29 | private skin: string; | 30 | private skin: string; |
30 | 31 | ||
32 | + public static get DESIGN_MODE_ON_CLASSNAME(): string { return "noosfero-design-on"; } | ||
31 | public static get USER_LOGGED_CLASSNAME(): string { return "noosfero-user-logged"; } | 33 | public static get USER_LOGGED_CLASSNAME(): string { return "noosfero-user-logged"; } |
32 | public static get ROUTE_STATE_CLASSNAME_PREFIX(): string { return "noosfero-route-"; } | 34 | public static get ROUTE_STATE_CLASSNAME_PREFIX(): string { return "noosfero-route-"; } |
33 | public static get CONTENT_WRAPPER_FULL(): string { return "full-content"; } | 35 | public static get CONTENT_WRAPPER_FULL(): string { return "full-content"; } |
@@ -38,16 +40,16 @@ export class BodyStateClassesService { | @@ -38,16 +40,16 @@ export class BodyStateClassesService { | ||
38 | private $rootScope: ng.IRootScopeService, | 40 | private $rootScope: ng.IRootScopeService, |
39 | private $document: ng.IDocumentService, | 41 | private $document: ng.IDocumentService, |
40 | private $state: ng.ui.IStateService, | 42 | private $state: ng.ui.IStateService, |
41 | - private authService: AuthService | 43 | + private authService: AuthService, |
44 | + private designModeService: DesignModeService | ||
42 | ) { | 45 | ) { |
43 | - | ||
44 | } | 46 | } |
45 | 47 | ||
46 | start(config?: StartParams) { | 48 | start(config?: StartParams) { |
47 | if (!this.started) { | 49 | if (!this.started) { |
48 | this.setupUserLoggedClassToggle(); | 50 | this.setupUserLoggedClassToggle(); |
49 | this.setupStateClassToggle(); | 51 | this.setupStateClassToggle(); |
50 | - | 52 | + this.setupDesignModeClassToggle(); |
51 | if (config) { | 53 | if (config) { |
52 | this.setThemeSkin(config.skin); | 54 | this.setThemeSkin(config.skin); |
53 | } | 55 | } |
@@ -87,9 +89,19 @@ export class BodyStateClassesService { | @@ -87,9 +89,19 @@ export class BodyStateClassesService { | ||
87 | } | 89 | } |
88 | 90 | ||
89 | /** | 91 | /** |
90 | - * Setup the initial class name on body element indicating the current route | ||
91 | - * and adds event handler to swith this class when the current page/state changes | 92 | + * setup the listeners to the desigModeService to add class on the Body Element |
93 | + * indicating the user activated the designMode | ||
92 | */ | 94 | */ |
95 | + private setupDesignModeClassToggle() { | ||
96 | + this.designModeService.onToggle.subscribe((designOn: boolean) => { | ||
97 | + if (designOn) { | ||
98 | + this.getBodyElement().addClass(BodyStateClassesService.DESIGN_MODE_ON_CLASSNAME); | ||
99 | + } else { | ||
100 | + this.getBodyElement().removeClass(BodyStateClassesService.DESIGN_MODE_ON_CLASSNAME); | ||
101 | + } | ||
102 | + }); | ||
103 | + } | ||
104 | + | ||
93 | private setupStateClassToggle() { | 105 | private setupStateClassToggle() { |
94 | let bodyElement = this.getBodyElement(); | 106 | let bodyElement = this.getBodyElement(); |
95 | bodyElement.addClass(BodyStateClassesService.ROUTE_STATE_CLASSNAME_PREFIX + this.$state.current.name); | 107 | bodyElement.addClass(BodyStateClassesService.ROUTE_STATE_CLASSNAME_PREFIX + this.$state.current.name); |
src/app/main/main.component.ts
@@ -111,7 +111,7 @@ export class EnvironmentContent { | @@ -111,7 +111,7 @@ export class EnvironmentContent { | ||
111 | "angular-bind-html-compile", "angularMoment", "angular.filter", "akoenig.deckgrid", | 111 | "angular-bind-html-compile", "angularMoment", "angular.filter", "akoenig.deckgrid", |
112 | "angular-timeline", "duScroll", "oitozero.ngSweetAlert", | 112 | "angular-timeline", "duScroll", "oitozero.ngSweetAlert", |
113 | "pascalprecht.translate", "tmh.dynamicLocale", "angularLoad", | 113 | "pascalprecht.translate", "tmh.dynamicLocale", "angularLoad", |
114 | - "angular-click-outside", "noosfero.init"] | 114 | + "angular-click-outside", "toggle-switch", "noosfero.init"] |
115 | }) | 115 | }) |
116 | @StateConfig([ | 116 | @StateConfig([ |
117 | { | 117 | { |
@@ -0,0 +1,21 @@ | @@ -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 "../../lib/ng-noosfero-api/http/profile.service"; | @@ -10,7 +10,7 @@ import {ProfileService} from "../../lib/ng-noosfero-api/http/profile.service"; | ||
10 | import {NotificationService} from "../shared/services/notification.service"; | 10 | import {NotificationService} from "../shared/services/notification.service"; |
11 | import {MyProfileComponent} from "./myprofile.component"; | 11 | import {MyProfileComponent} from "./myprofile.component"; |
12 | import {ProfileActionsComponent} from "./profile-actions.component"; | 12 | import {ProfileActionsComponent} from "./profile-actions.component"; |
13 | - | 13 | +import {ProfileToolbarComponent} from "./profile-toolbar.component"; |
14 | /** | 14 | /** |
15 | * @ngdoc controller | 15 | * @ngdoc controller |
16 | * @name profile.Profile | 16 | * @name profile.Profile |
@@ -42,6 +42,11 @@ import {ProfileActionsComponent} from "./profile-actions.component"; | @@ -42,6 +42,11 @@ import {ProfileActionsComponent} from "./profile-actions.component"; | ||
42 | templateUrl: "app/profile/navbar-actions.html", | 42 | templateUrl: "app/profile/navbar-actions.html", |
43 | controller: ProfileActionsComponent, | 43 | controller: ProfileActionsComponent, |
44 | controllerAs: "vm" | 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 "./profile-actions.component"; | @@ -54,6 +59,11 @@ import {ProfileActionsComponent} from "./profile-actions.component"; | ||
54 | templateUrl: "app/profile/navbar-actions.html", | 59 | templateUrl: "app/profile/navbar-actions.html", |
55 | controller: ProfileActionsComponent, | 60 | controller: ProfileActionsComponent, |
56 | controllerAs: "vm" | 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 "./profile-actions.component"; | @@ -106,6 +116,11 @@ import {ProfileActionsComponent} from "./profile-actions.component"; | ||
106 | templateUrl: "app/article/content-viewer/navbar-actions.html", | 116 | templateUrl: "app/article/content-viewer/navbar-actions.html", |
107 | controller: ContentViewerActionsComponent, | 117 | controller: ContentViewerActionsComponent, |
108 | controllerAs: "vm" | 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/shared/components/bootstrap-switcher/bootstrap-switcher.component.ts
0 → 100644
@@ -0,0 +1,51 @@ | @@ -0,0 +1,51 @@ | ||
1 | +import {Component, Input, Output, EventEmitter} from 'ng-forward'; | ||
2 | + | ||
3 | + | ||
4 | +export interface BootstrapSwitcherItem { | ||
5 | + value: any; | ||
6 | + label: string; | ||
7 | +} | ||
8 | +@Component({ | ||
9 | + selector: 'noosfero-bootstrap-switcher', | ||
10 | + template: ` | ||
11 | + <span class="switcher-label" ng-bind="ctrl.label | translate"></span> | ||
12 | + <div class="btn-group switcher"> | ||
13 | + <button ng-repeat="option in ctrl.options track by $index" | ||
14 | + (click)="ctrl.switcherClick(option)" | ||
15 | + ng-class="ctrl.getCssClassForItem(option)" | ||
16 | + class="btn btn-xs" ng-bind="option.label | translate"> | ||
17 | + </button> | ||
18 | + </div> | ||
19 | + `, | ||
20 | + inputs: ['activeClass', 'defaultClass', 'label', 'options', 'defaultOption'], | ||
21 | + outputs: ['onSwitch'] | ||
22 | +}) | ||
23 | +export class BootstrapSwitcherComponent { | ||
24 | + @Input() activeClass: string = 'active btn-danger'; | ||
25 | + @Input() defaultClass: string = 'btn-default'; | ||
26 | + @Input() label: string; | ||
27 | + @Input() options: BootstrapSwitcherItem[]; | ||
28 | + @Input() defaultOption: BootstrapSwitcherItem; | ||
29 | + @Output() onSwitch: EventEmitter<BootstrapSwitcherItem> = new EventEmitter<BootstrapSwitcherItem>(); | ||
30 | + | ||
31 | + selectedOption: BootstrapSwitcherItem = null; | ||
32 | + | ||
33 | + constructor() { } | ||
34 | + | ||
35 | + ngOnInit() { | ||
36 | + this.selectedOption = this.defaultOption; | ||
37 | + } | ||
38 | + | ||
39 | + isSelectedOption(value: BootstrapSwitcherItem): boolean { | ||
40 | + return this.selectedOption === value; | ||
41 | + } | ||
42 | + | ||
43 | + getCssClassForItem(value: BootstrapSwitcherItem): string { | ||
44 | + return this.isSelectedOption(value) ? this.activeClass : this.defaultClass; | ||
45 | + } | ||
46 | + | ||
47 | + switcherClick(value: BootstrapSwitcherItem) { | ||
48 | + this.selectedOption = value; | ||
49 | + this.onSwitch.next(value); | ||
50 | + } | ||
51 | +} | ||
0 | \ No newline at end of file | 52 | \ No newline at end of file |
src/app/shared/components/permission/permission.directive.ts
@@ -6,7 +6,7 @@ import {Directive, Inject, Input} from "ng-forward"; | @@ -6,7 +6,7 @@ import {Directive, Inject, Input} from "ng-forward"; | ||
6 | @Inject('$attrs', '$scope', '$element') | 6 | @Inject('$attrs', '$scope', '$element') |
7 | export class PermissionDirective { | 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 | $scope.$watch($attrs['permission'], () => { | 10 | $scope.$watch($attrs['permission'], () => { |
11 | let permissions = $scope.$eval($attrs['permission']); | 11 | let permissions = $scope.$eval($attrs['permission']); |
12 | let permissionAction = $attrs['permissionAction']; | 12 | let permissionAction = $attrs['permissionAction']; |
src/languages/en.json
@@ -75,6 +75,9 @@ | @@ -75,6 +75,9 @@ | ||
75 | "custom_content.title": "Edit content", | 75 | "custom_content.title": "Edit content", |
76 | "profile.custom_header.label": "Header", | 76 | "profile.custom_header.label": "Header", |
77 | "profile.custom_footer.label": "Footer", | 77 | "profile.custom_footer.label": "Footer", |
78 | + "designMode.label": "In Design", | ||
79 | + "designMode.toggle.ON": "ON", | ||
80 | + "designMode.toggle.OFF": "OFF", | ||
78 | "search.results.summary": "{results, plural, one{result} other{# results}}", | 81 | "search.results.summary": "{results, plural, one{result} other{# results}}", |
79 | "search.results.query.label": "Search for:", | 82 | "search.results.query.label": "Search for:", |
80 | "search.results.query.placeholder": "Search" | 83 | "search.results.query.placeholder": "Search" |
src/languages/pt.json
@@ -75,6 +75,9 @@ | @@ -75,6 +75,9 @@ | ||
75 | "custom_content.title": "Editar conteúdo", | 75 | "custom_content.title": "Editar conteúdo", |
76 | "profile.custom_header.label": "Cabeçalho", | 76 | "profile.custom_header.label": "Cabeçalho", |
77 | "profile.custom_footer.label": "Rodapé", | 77 | "profile.custom_footer.label": "Rodapé", |
78 | + "designMode.label": "Modo de Edição", | ||
79 | + "designMode.toggle.ON": "Ligado", | ||
80 | + "designMode.toggle.OFF": "Desligado", | ||
78 | "search.results.summary": "{results, plural, one{# resultado} other{# resultados}}", | 81 | "search.results.summary": "{results, plural, one{# resultado} other{# resultados}}", |
79 | "search.results.query.label": "Buscar:", | 82 | "search.results.query.label": "Buscar:", |
80 | "search.results.query.placeholder": "Informe aqui sua busca" | 83 | "search.results.query.placeholder": "Informe aqui sua busca" |
src/lib/ng-noosfero-api/http/profile.service.ts
@@ -22,7 +22,7 @@ export class ProfileService { | @@ -22,7 +22,7 @@ export class ProfileService { | ||
22 | this._currentProfilePromise.resolve(profile); | 22 | this._currentProfilePromise.resolve(profile); |
23 | } | 23 | } |
24 | 24 | ||
25 | - setCurrentProfileByIdentifier(identifier: string) { | 25 | + setCurrentProfileByIdentifier(identifier: string): ng.IPromise<noosfero.Profile> { |
26 | this.resetCurrentProfile(); | 26 | this.resetCurrentProfile(); |
27 | return this.getByIdentifier(identifier).then((profile: noosfero.Profile) => { | 27 | return this.getByIdentifier(identifier).then((profile: noosfero.Profile) => { |
28 | this.setCurrentProfile(profile); | 28 | this.setCurrentProfile(profile); |
src/lib/ng-noosfero-api/interfaces/article.ts
src/lib/ng-noosfero-api/interfaces/modelWithPermissions.ts
0 → 100644
src/lib/ng-noosfero-api/interfaces/profile.ts
themes/angular-participa-consulta/app/participa-consulta.scss