Compare View

switch
from
...
to
 
Commits (26)
Showing 63 changed files   Show diff stats
@@ -53,18 +53,31 @@ See some important folders bellow: @@ -53,18 +53,31 @@ See some important folders bellow:
53 53
54 ## Change skin 54 ## Change skin
55 55
56 -- Create a any scss file into your theme folder structure 56 +- Create an any scss file into: `app/layout/skins/`
  57 + > **Suggestion:** Create a `sass` file partial. Something like: **`_mycustom.scss`**.
  58 +
57 - Extend your skin css class from `%skin-base` scss placeholder selector. Something like this: 59 - Extend your skin css class from `%skin-base` scss placeholder selector. Something like this:
  60 + > **Suggestion:** Use the prefix **`skin-`** to the css class
58 61
59 ```sass 62 ```sass
60 -.skin-custom { 63 +.skin-mycustom {
61 @extend %skin-base 64 @extend %skin-base
62 } 65 }
63 ``` 66 ```
64 - Configure application to use the new theme, e.g.: 67 - Configure application to use the new theme, e.g.:
65 -`npm config set angular-theme:skin custom-skin` 68 +`npm config set angular-theme:skin skin-mycustom`
  69 +
  70 +**N.B.**
  71 +
  72 +1. The full name of the scss class should be used as the parameter for the command `npm config set angular-theme:`, like in _skin-mycustom_. DO NOT use the file name of the skin as the parameter.
  73 +
  74 +2. The skin's file should be the named as the scss class without the word `skin`, preceded by an underline. Otherwise, it will raise an error during `npm install`.
  75 +
  76 +Example: _mycustom.
  77 +
66 78
67 -- Start the application with `npm start` scripts ou make a build 79 +- Start the application with `npm start` scripts or make a build
  80 + > **PS:** If the configured skin is invalid, an error message is showed in the terminal.
68 81
69 ## Development environment 82 ## Development environment
70 83
@@ -38,7 +38,8 @@ @@ -38,7 +38,8 @@
38 "angular-bind-html-compile": "^1.2.1", 38 "angular-bind-html-compile": "^1.2.1",
39 "angular-click-outside": "^2.7.1", 39 "angular-click-outside": "^2.7.1",
40 "ng-ckeditor": "^0.2.1", 40 "ng-ckeditor": "^0.2.1",
41 - "angular-bootstrap-toggle-switch": "^0.5.6" 41 + "angular-bootstrap-toggle-switch": "^0.5.6",
  42 + "angular-tag-cloud": "^0.3.0"
42 }, 43 },
43 "devDependencies": { 44 "devDependencies": {
44 "angular-mocks": "~1.5.0" 45 "angular-mocks": "~1.5.0"
@@ -9,6 +9,7 @@ @@ -9,6 +9,7 @@
9 var argv = require('minimist')(process.argv.slice(2)); 9 var argv = require('minimist')(process.argv.slice(2));
10 var gutil = require('gulp-util'); 10 var gutil = require('gulp-util');
11 var path = require('path'); 11 var path = require('path');
  12 +var fs = require('fs');
12 13
13 /** 14 /**
14 * The main paths of your project handle these with care 15 * The main paths of your project handle these with care
@@ -23,12 +24,70 @@ exports.paths = { @@ -23,12 +24,70 @@ exports.paths = {
23 themes: 'themes', 24 themes: 'themes',
24 languages: 'languages' 25 languages: 'languages'
25 }; 26 };
  27 +
  28 +/**
  29 +* Check if theme folder exists on "themes" directory
  30 +*
  31 +* @param path The string relative path of the theme
  32 +*/
  33 +exports.themeExists = function (path) {
  34 + try {
  35 + fs.statSync(path);
  36 + } catch (e) {
  37 + throw new Error('The theme "'+exports.paths.theme+ ' on path "'+path+'" was not found');
  38 + }
  39 +};
  40 +
  41 +/**
  42 +* Check if skin file exists on "{theme}/app/layout/skins" directory
  43 +*
  44 +* @param skin The skin name passed by arg to gulp task
  45 +*/
  46 +exports.skinExists = function (skin) {
  47 +
  48 + var skinPath, prefixPath = '';
  49 + var skinFile = skin+'.scss';
  50 + if (/skin-/.test(skin)) {
  51 + skinFile = skin.replace('skin-','_')+'.scss';
  52 + }
  53 +
  54 + if (/-default$/.test(exports.paths.theme)) {
  55 + prefixPath = exports.paths.src;
  56 + }else {
  57 + prefixPath = path.join(exports.paths.themes, exports.paths.theme);
  58 + }
  59 +
  60 + skinPath = path.join(prefixPath, '/app/layout/scss/skins/', skinFile);
  61 +
  62 + try {
  63 + fs.statSync(skinPath);
  64 + } catch(e) {
  65 + throw new Error('The skin file "'+skinPath+'" was not found');
  66 + }
  67 +
  68 + var content = fs.readFileSync(skinPath, {encoding: 'utf8'});
  69 + if(content.search(skin) == -1) {
  70 + throw new Error('The skin css selector ".'+skin+'" was not found in "'+skinPath+'" file');
  71 + }else if (content.search('@extend %skin-base') == -1) {
  72 + throw new Error('The skin css selector ".'+skin+'" needs inherit from %skin-base sass placeholder');
  73 + }
  74 +
  75 +};
  76 +
26 exports.configTheme = function(theme) { 77 exports.configTheme = function(theme) {
  78 +
27 exports.paths.theme = theme || "angular-default"; 79 exports.paths.theme = theme || "angular-default";
28 - exports.paths.allSources = [exports.paths.src, path.join(exports.paths.themes, exports.paths.theme)]; 80 + var themePath = path.join(exports.paths.themes, exports.paths.theme);
  81 +
  82 + exports.paths.allSources = [exports.paths.src, themePath];
  83 +
  84 +
  85 + exports.themeExists(themePath);
29 exports.paths.dist = path.join("dist", exports.paths.theme); 86 exports.paths.dist = path.join("dist", exports.paths.theme);
30 87
31 if(argv.skin) { 88 if(argv.skin) {
  89 + exports.skinExists(argv.skin);
  90 +
32 exports.paths.skin = argv.skin; 91 exports.paths.skin = argv.skin;
33 } 92 }
34 } 93 }
gulp/styles.js
@@ -10,6 +10,7 @@ var $ = require('gulp-load-plugins')(); @@ -10,6 +10,7 @@ var $ = require('gulp-load-plugins')();
10 10
11 var wiredep = require('wiredep').stream; 11 var wiredep = require('wiredep').stream;
12 var _ = require('lodash'); 12 var _ = require('lodash');
  13 +var importCss = require('gulp-import-css');
13 14
14 gulp.task('styles-reload', ['styles'], function() { 15 gulp.task('styles-reload', ['styles'], function() {
15 return buildStyles() 16 return buildStyles()
@@ -55,5 +56,6 @@ var buildStyles = function() { @@ -55,5 +56,6 @@ var buildStyles = function() {
55 .pipe($.sass(sassOptions)).on('error', conf.errorHandler('Sass')) 56 .pipe($.sass(sassOptions)).on('error', conf.errorHandler('Sass'))
56 .pipe($.autoprefixer()).on('error', conf.errorHandler('Autoprefixer')) 57 .pipe($.autoprefixer()).on('error', conf.errorHandler('Autoprefixer'))
57 .pipe($.sourcemaps.write()) 58 .pipe($.sourcemaps.write())
  59 + .pipe(importCss())
58 .pipe(gulp.dest(path.join(conf.paths.tmp, '/serve/app/'))); 60 .pipe(gulp.dest(path.join(conf.paths.tmp, '/serve/app/')));
59 }; 61 };
@@ -47,6 +47,7 @@ @@ -47,6 +47,7 @@
47 "gulp-eslint": "~1.0.0", 47 "gulp-eslint": "~1.0.0",
48 "gulp-filter": "~3.0.1", 48 "gulp-filter": "~3.0.1",
49 "gulp-flatten": "~0.2.0", 49 "gulp-flatten": "~0.2.0",
  50 + "gulp-import-css": "^0.1.2",
50 "gulp-inject": "~3.0.0", 51 "gulp-inject": "~3.0.0",
51 "gulp-insert": "^0.5.0", 52 "gulp-insert": "^0.5.0",
52 "gulp-load-plugins": "~0.10.0", 53 "gulp-load-plugins": "~0.10.0",
src/app/admin/layout-edit/designMode.service.spec.ts
1 import {DesignModeService} from './designMode.service'; 1 import {DesignModeService} from './designMode.service';
  2 +import {INoosferoLocalStorage} from "./../../shared/models/interfaces";
2 3
3 describe('DesignMode Service', () => { 4 describe('DesignMode Service', () => {
4 let service: DesignModeService; 5 let service: DesignModeService;
5 - 6 + let $localStorage = <INoosferoLocalStorage>{ currentUser: null, settings: { designMode: false } };
6 beforeEach(() => { 7 beforeEach(() => {
7 - service = new DesignModeService(); 8 + service = new DesignModeService($localStorage);
8 }); 9 });
9 10
10 it('has the designModeOn equals false as default', () => { 11 it('has the designModeOn equals false as default', () => {
@@ -18,14 +19,16 @@ describe(&#39;DesignMode Service&#39;, () =&gt; { @@ -18,14 +19,16 @@ describe(&#39;DesignMode Service&#39;, () =&gt; {
18 }); 19 });
19 20
20 it('emits the onToggle event when changing the designModeOn property', () => { 21 it('emits the onToggle event when changing the designModeOn property', () => {
  22 + service.setInDesignMode(false);
21 spyOn(service.onToggle, 'next').and.stub(); 23 spyOn(service.onToggle, 'next').and.stub();
22 service.setInDesignMode(true); 24 service.setInDesignMode(true);
23 expect(service.onToggle.next).toHaveBeenCalled(); 25 expect(service.onToggle.next).toHaveBeenCalled();
24 }); 26 });
25 27
26 it('does not emit onToggle event when there is no change on designModeOn property', () => { 28 it('does not emit onToggle event when there is no change on designModeOn property', () => {
  29 + service.setInDesignMode(false);
27 spyOn(service.onToggle, 'next').and.stub(); 30 spyOn(service.onToggle, 'next').and.stub();
28 service.setInDesignMode(false); 31 service.setInDesignMode(false);
29 expect(service.onToggle.next).not.toHaveBeenCalled(); 32 expect(service.onToggle.next).not.toHaveBeenCalled();
30 }); 33 });
31 -});  
32 \ No newline at end of file 34 \ No newline at end of file
  35 +});
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 @Injectable() 4 @Injectable()
  5 +@Inject("$localStorage")
4 export class DesignModeService { 6 export class DesignModeService {
5 - @Output() onToggle: EventEmitter<boolean> = new EventEmitter<boolean>();  
6 7
7 - private designModeOn: boolean = false; 8 + @Output() onToggle: EventEmitter<boolean> = new EventEmitter<boolean>();
8 9
9 isInDesignMode(): boolean { 10 isInDesignMode(): boolean {
10 - return this.designModeOn; 11 + return this.$localStorage.settings.designModeOn;
  12 + }
  13 +
  14 + destroy() {
  15 + delete this.$localStorage.settings;
  16 + this.$localStorage.settings = {};
11 } 17 }
12 18
13 setInDesignMode(value: boolean) { 19 setInDesignMode(value: boolean) {
14 - if (this.designModeOn !== value) {  
15 - this.designModeOn = value;  
16 - this.onToggle.next(this.designModeOn); 20 + if (this.$localStorage.settings.designModeOn !== value) {
  21 + this.$localStorage.settings.designModeOn = value;
  22 + this.onToggle.next(value);
17 } 23 }
18 } 24 }
19 25
20 - constructor() { 26 + constructor(private $localStorage: INoosferoLocalStorage) {
  27 + if (!this.$localStorage.settings) {
  28 + this.$localStorage.settings = {};
  29 + }
21 } 30 }
22 } 31 }
src/app/admin/layout-edit/designModeToggler.component.spec.ts
@@ -2,6 +2,7 @@ import {ComponentTestHelper, createClass} from &#39;../../../spec/component-test-hel @@ -2,6 +2,7 @@ import {ComponentTestHelper, createClass} from &#39;../../../spec/component-test-hel
2 import * as helpers from '../../../spec/helpers'; 2 import * as helpers from '../../../spec/helpers';
3 import {DesignModeTogglerComponent} from './designModeToggler.component'; 3 import {DesignModeTogglerComponent} from './designModeToggler.component';
4 import {DesignModeService} from './designMode.service'; 4 import {DesignModeService} from './designMode.service';
  5 +import {INoosferoLocalStorage} from "./../../shared/models/interfaces";
5 6
6 describe('DesignModeToggler Component', () => { 7 describe('DesignModeToggler Component', () => {
7 const htmlTemplate: string = '<noosfero-design-toggler></noosfero-design-toggler>'; 8 const htmlTemplate: string = '<noosfero-design-toggler></noosfero-design-toggler>';
@@ -14,13 +15,15 @@ describe(&#39;DesignModeToggler Component&#39;, () =&gt; { @@ -14,13 +15,15 @@ describe(&#39;DesignModeToggler Component&#39;, () =&gt; {
14 }); 15 });
15 16
16 let designModeService: DesignModeService; 17 let designModeService: DesignModeService;
  18 + let $localStorage = <INoosferoLocalStorage>{ currentUser: null, settings: { designMode: false } };
17 beforeEach((done) => { 19 beforeEach((done) => {
18 - designModeService = new DesignModeService(); 20 + designModeService = new DesignModeService($localStorage);
19 let cls = createClass({ 21 let cls = createClass({
20 template: htmlTemplate, 22 template: htmlTemplate,
21 directives: [DesignModeTogglerComponent], 23 directives: [DesignModeTogglerComponent],
22 providers: [ 24 providers: [
23 - helpers.createProviderToValue('DesignModeService', designModeService) 25 + helpers.createProviderToValue('DesignModeService', designModeService),
  26 + helpers.createProviderToValue('AuthService', helpers.mocks.authService),
24 ] 27 ]
25 }); 28 });
26 helper = new ComponentTestHelper<DesignModeTogglerComponent>(cls, done); 29 helper = new ComponentTestHelper<DesignModeTogglerComponent>(cls, done);
@@ -36,6 +39,7 @@ describe(&#39;DesignModeToggler Component&#39;, () =&gt; { @@ -36,6 +39,7 @@ describe(&#39;DesignModeToggler Component&#39;, () =&gt; {
36 }); 39 });
37 40
38 it('emits event with value "true" when changing inDesignMode to On', (done) => { 41 it('emits event with value "true" when changing inDesignMode to On', (done) => {
  42 + designModeService.setInDesignMode(false);
39 designModeService.onToggle.subscribe((designModeOn: boolean) => { 43 designModeService.onToggle.subscribe((designModeOn: boolean) => {
40 expect(designModeOn).toBeTruthy(); 44 expect(designModeOn).toBeTruthy();
41 done(); 45 done();
src/app/admin/layout-edit/designModeToggler.component.ts
1 import {Component, Inject} from 'ng-forward'; 1 import {Component, Inject} from 'ng-forward';
2 import {DesignModeService} from './designMode.service'; 2 import {DesignModeService} from './designMode.service';
  3 +import {AuthService, AuthEvents} from '../../login';
  4 +
3 @Component({ 5 @Component({
4 selector: 'noosfero-design-toggler', 6 selector: 'noosfero-design-toggler',
5 templateUrl: 'app/admin/layout-edit/designModeToggler.html' 7 templateUrl: 'app/admin/layout-edit/designModeToggler.html'
6 }) 8 })
7 -@Inject(DesignModeService) 9 +@Inject(DesignModeService, AuthService)
8 export class DesignModeTogglerComponent { 10 export class DesignModeTogglerComponent {
9 11
10 icon: string = "&nbsp;<i class='glyphicon glyphicon-wrench'></i>&nbsp;"; 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 private _inDesignMode: boolean = false; 20 private _inDesignMode: boolean = false;
@@ -21,4 +26,4 @@ export class DesignModeTogglerComponent { @@ -21,4 +26,4 @@ export class DesignModeTogglerComponent {
21 set inDesignMode(value: boolean) { 26 set inDesignMode(value: boolean) {
22 this.designModeService.setInDesignMode(value); 27 this.designModeService.setInDesignMode(value);
23 }; 28 };
24 -}  
25 \ No newline at end of file 29 \ No newline at end of file
  30 +}
src/app/environment/environment.html
1 <div class="environment-container"> 1 <div class="environment-container">
2 <div class="row"> 2 <div class="row">
3 - <noosfero-boxes ng-if="vm.boxes" [boxes]="vm.boxes" [owner]="vm.environment"></noosfero-boxes> 3 + <noosfero-boxes ng-if="vm.boxes"
  4 + [layout]="vm.environment.layout_template"
  5 + [boxes]="vm.boxes"
  6 + [owner]="vm.environment">
  7 + </noosfero-boxes>
4 </div> 8 </div>
5 </div> 9 </div>
src/app/index.scss
@@ -82,3 +82,4 @@ h1, h2, h3, h4, h5 { @@ -82,3 +82,4 @@ h1, h2, h3, h4, h5 {
82 @import "layout/scss/layout"; 82 @import "layout/scss/layout";
83 @import "layout/scss/sidebar"; 83 @import "layout/scss/sidebar";
84 @import "layout/scss/tables"; 84 @import "layout/scss/tables";
  85 +@import "layout/scss/forms";
src/app/layout/blocks/block.component.spec.ts
@@ -2,6 +2,7 @@ import {Component} from &#39;ng-forward&#39;; @@ -2,6 +2,7 @@ import {Component} from &#39;ng-forward&#39;;
2 import {BlockComponent} from './block.component'; 2 import {BlockComponent} from './block.component';
3 import * as helpers from "../../../spec/helpers"; 3 import * as helpers from "../../../spec/helpers";
4 import {ComponentTestHelper, createClass} from '../../../spec/component-test-helper'; 4 import {ComponentTestHelper, createClass} from '../../../spec/component-test-helper';
  5 +import {DesignModeService} from '../../admin/layout-edit/designMode.service';
5 6
6 const htmlTemplate: string = '<noosfero-block [block]="ctrl.block" [owner]="ctrl.profile"></noosfero-block>'; 7 const htmlTemplate: string = '<noosfero-block [block]="ctrl.block" [owner]="ctrl.profile"></noosfero-block>';
7 8
@@ -32,12 +33,12 @@ describe(&quot;Boxes Component&quot;, () =&gt; { @@ -32,12 +33,12 @@ describe(&quot;Boxes Component&quot;, () =&gt; {
32 helpers.createProviderToValue('TranslatorService', translatorService), 33 helpers.createProviderToValue('TranslatorService', translatorService),
33 helpers.createProviderToValue('$uibModal', helpers.mocks.$modal), 34 helpers.createProviderToValue('$uibModal', helpers.mocks.$modal),
34 helpers.createProviderToValue('BlockService', blockService), 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 helper = new ComponentTestHelper<BlockComponent>(cls, done); 40 helper = new ComponentTestHelper<BlockComponent>(cls, done);
39 }); 41 });
40 -  
41 let translatorService = jasmine.createSpyObj("translatorService", ["currentLanguage"]); 42 let translatorService = jasmine.createSpyObj("translatorService", ["currentLanguage"]);
42 let blockService = jasmine.createSpyObj("blockService", ["update"]); 43 let blockService = jasmine.createSpyObj("blockService", ["update"]);
43 let state = jasmine.createSpyObj("state", ["current"]); 44 let state = jasmine.createSpyObj("state", ["current"]);
src/app/layout/blocks/block.component.ts
@@ -11,7 +11,8 @@ import { DesignModeService } from &quot;../../admin/layout-edit/designMode.service&quot;; @@ -11,7 +11,8 @@ import { DesignModeService } from &quot;../../admin/layout-edit/designMode.service&quot;;
11 templateUrl: 'app/layout/blocks/block.html', 11 templateUrl: 'app/layout/blocks/block.html',
12 directives: [BlockEditionComponent] 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 export class BlockComponent { 16 export class BlockComponent {
16 17
17 @Input() block: noosfero.Block; 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 <div ng-show="displayActions" class="actions block-actions" permission="ctrl.block.permissions" permission-action="allow_edit"> 2 <div ng-show="displayActions" class="actions block-actions" permission="ctrl.block.permissions" permission-action="allow_edit">
3 <button type="submit" class="btn btn-xs btn-default" ng-click="ctrl.openEdit()"><i class="fa fa-edit fa-fw"></i></button> 3 <button type="submit" class="btn btn-xs btn-default" ng-click="ctrl.openEdit()"><i class="fa fa-edit fa-fw"></i></button>
4 </div> 4 </div>
src/app/layout/blocks/login-block/login-block.html
@@ -15,13 +15,21 @@ @@ -15,13 +15,21 @@
15 <div class="logged-user-info" ng-show="!ctrl.currentUser"> 15 <div class="logged-user-info" ng-show="!ctrl.currentUser">
16 <form> 16 <form>
17 <div class="form-group"> 17 <div class="form-group">
18 - <label for="exampleInputEmail1">{{"auth.form.login" | translate}}</label>  
19 - <input type="text" class="form-control" id="exampleInputEmail1" placeholder="Login / Email" ng-model="ctrl.credentials.username"> 18 + <label for="email">{{"auth.form.login" | translate}}</label>
  19 + <input type="text" class="form-control" id="email" placeholder="{{'auth.form.login' | translate}}" ng-model="ctrl.credentials.username">
20 </div> 20 </div>
21 <div class="form-group"> 21 <div class="form-group">
22 - <label for="exampleInputPassword1">{{"auth.form.password" | translate}}</label>  
23 - <input type="password" class="form-control" id="exampleInputPassword1" placeholder="Password" ng-model="ctrl.credentials.password"> 22 + <label for="passwd">{{"auth.form.password" | translate}}</label>
  23 + <input type="password" class="form-control" id="passwd" placeholder="{{'auth.form.password' | translate}}" ng-model="ctrl.credentials.password">
  24 + </div>
  25 + <div class="form-inline">
  26 + <div class="checkbox-nice">
  27 + <input type="checkbox" id="keep-logged">
  28 + <label for="keep-logged">
  29 + {{"auth.form.keepLoggedIn" | translate}}
  30 + </label>
  31 + </div>
24 </div> 32 </div>
25 <button type="submit" class="btn btn-default" ng-click="ctrl.login()">{{"auth.form.login_button" | translate}}</button> 33 <button type="submit" class="btn btn-default" ng-click="ctrl.login()">{{"auth.form.login_button" | translate}}</button>
26 </form> 34 </form>
27 -</div>  
28 \ No newline at end of file 35 \ No newline at end of file
  36 +</div>
src/app/layout/blocks/tags/index.ts 0 → 100644
@@ -0,0 +1 @@ @@ -0,0 +1 @@
  1 +export * from "./tags-block.component";
src/app/layout/blocks/tags/tags-block.component.spec.ts 0 → 100644
@@ -0,0 +1,55 @@ @@ -0,0 +1,55 @@
  1 +import {TestComponentBuilder} from 'ng-forward/cjs/testing/test-component-builder';
  2 +import {Provider, Input, provide, Component} from 'ng-forward';
  3 +import {provideFilters} from '../../../../spec/helpers';
  4 +import {TagsBlockComponent} from './tags-block.component';
  5 +
  6 +const htmlTemplate: string = '<noosfero-tags-block [block]="ctrl.block" [owner]="ctrl.owner"></noosfero-tags-block>';
  7 +
  8 +const tcb = new TestComponentBuilder();
  9 +
  10 +describe("Components", () => {
  11 + describe("Tags Block Component", () => {
  12 +
  13 + let settingsObj = {};
  14 + let mockedEnvironmentService = {
  15 + getTags: (): any => {
  16 + return Promise.resolve({ foo: 10, bar: 20 });
  17 + }
  18 + };
  19 + let profile = { name: 'profile-name' };
  20 + beforeEach(angular.mock.module("templates"));
  21 +
  22 + let state = jasmine.createSpyObj("state", ["go"]);
  23 +
  24 +
  25 + function getProviders() {
  26 + return [
  27 + new Provider('$state', { useValue: state }),
  28 + new Provider('EnvironmentService', {
  29 + useValue: mockedEnvironmentService
  30 + }),
  31 + ].concat(provideFilters("truncateFilter", "stripTagsFilter"));
  32 + }
  33 + let componentClass: any = null;
  34 +
  35 + function getComponent() {
  36 + @Component({ selector: 'test-container-component', template: htmlTemplate, directives: [TagsBlockComponent], providers: getProviders() })
  37 + class BlockContainerComponent {
  38 + block = { type: 'Block', settings: settingsObj };
  39 + owner = profile;
  40 + constructor() {
  41 + }
  42 + }
  43 + return BlockContainerComponent;
  44 + }
  45 +
  46 +
  47 + it("get tags from the environment service", done => {
  48 + tcb.createAsync(getComponent()).then(fixture => {
  49 + let tagsBlock: TagsBlockComponent = fixture.debugElement.componentViewChildren[0].componentInstance;
  50 + expect(tagsBlock.tags).toEqual([{ text: "foo", weight: '10', link: '/tag/foo' }, { text: "bar", weight: '20', link: '/tag/bar' }]);
  51 + done();
  52 + });
  53 + });
  54 + });
  55 +});
src/app/layout/blocks/tags/tags-block.component.ts 0 → 100644
@@ -0,0 +1,45 @@ @@ -0,0 +1,45 @@
  1 +import {Component, Inject, Input} from "ng-forward";
  2 +import {EnvironmentService} from "../../../../lib/ng-noosfero-api/http/environment.service";
  3 +
  4 +@Component({
  5 + selector: "noosfero-tags-block",
  6 + templateUrl: 'app/layout/blocks/tags/tags-block.html'
  7 +})
  8 +@Inject(EnvironmentService, "$state")
  9 +export class TagsBlockComponent {
  10 +
  11 + @Input() block: any;
  12 + @Input() owner: any;
  13 +
  14 + profile: any;
  15 + tags: any;
  16 + tagsLoaded: boolean = false;
  17 +
  18 + constructor(private environmentService: EnvironmentService, private $state: any) {
  19 + this.loadTags();
  20 + }
  21 +
  22 + loadTags() {
  23 + this.tags = [];
  24 + let tag = '';
  25 + let tags: any = [];
  26 + let that = this;
  27 +
  28 + this.environmentService.getTags()
  29 + .then((result: any) => {
  30 + for (tag in result) {
  31 + if (result.hasOwnProperty(tag)) {
  32 + let size: number = result[tag];
  33 + tags.push({ text: tag.toString(), weight: size.toString(), link: '/tag/' + tag });
  34 + }
  35 + }
  36 +
  37 + that.tagsLoaded = true;
  38 + that.tags = tags.slice();
  39 + });
  40 + }
  41 +
  42 + ngOnInit() {
  43 + this.profile = this.owner;
  44 + }
  45 +}
src/app/layout/blocks/tags/tags-block.html 0 → 100644
@@ -0,0 +1 @@ @@ -0,0 +1 @@
  1 +<ng-tag-cloud cloud-width="200" cloud-height="150" cloud-data="ctrl.tags"></ng-tag-cloud>
src/app/layout/blocks/tags/tags-block.scss 0 → 100644
@@ -0,0 +1,7 @@ @@ -0,0 +1,7 @@
  1 +@import url('../../bower_components/angular-tag-cloud/src/css/ng-tag-cloud.css');
  2 +
  3 +div.ng-tag-cloud span {
  4 + &.w10, &.w8, &.w9 {
  5 + color: #1E96D0;
  6 + }
  7 +}
src/app/layout/boxes/box.html
1 -<div ng-class="{'col-md-2-5': box.position!=1, 'col-md-7': box.position==1}">  
2 - <noosfero-block ng-repeat="block in box.blocks | orderBy: 'position'" [block]="block" [owner]="ctrl.owner"></noosfero-block> 1 +<div ng-class="box.position | setBoxLayout:ctrl.layout">
  2 +
  3 + <div ng-repeat="block in box.blocks | orderBy: 'position'" class="panel panel-default block {{block.type | lowercase}}" >
  4 + <div class="panel-heading" ng-show="block.title">
  5 + <h3 class="panel-title">{{block.title}}</h3>
  6 + </div>
  7 + <div class="panel-body {{block.type | lowercase}}" >
  8 + <noosfero-block [block]="block" [owner]="ctrl.owner"></noosfero-block>
  9 + </div>
  10 + </div>
3 </div> 11 </div>
src/app/layout/boxes/boxes.component.spec.ts
@@ -45,12 +45,7 @@ describe(&quot;Boxes Component&quot;, () =&gt; { @@ -45,12 +45,7 @@ describe(&quot;Boxes Component&quot;, () =&gt; {
45 state.current = { name: "" }; 45 state.current = { name: "" };
46 46
47 it("renders boxes into a container", () => { 47 it("renders boxes into a container", () => {
48 - expect(helper.find('div.col-md-7').length).toEqual(1);  
49 - expect(helper.find('div.col-md-2-5').length).toEqual(1);  
50 - });  
51 -  
52 - it("check the boxes order", () => {  
53 - expect(helper.component.boxesOrder(properties['boxes'][0])).toEqual(1);  
54 - expect(helper.component.boxesOrder(properties['boxes'][1])).toEqual(0); 48 + expect(helper.find('div.col-md-6').length).toEqual(1);
  49 + expect(helper.find('div.col-md-3').length).toEqual(1);
55 }); 50 });
56 }); 51 });
src/app/layout/boxes/boxes.component.ts
1 -import {Input, Component} from 'ng-forward'; 1 +import {Input, Inject, Component} from 'ng-forward';
  2 +import {DisplayBoxes} from "./display-boxes.filter";
  3 +import {SetBoxLayout} from "./set-box-layout.filter";
2 4
3 @Component({ 5 @Component({
4 selector: "noosfero-boxes", 6 selector: "noosfero-boxes",
5 - templateUrl: "app/layout/boxes/boxes.html" 7 + templateUrl: "app/layout/boxes/boxes.html",
  8 + directives: [DisplayBoxes, SetBoxLayout]
6 }) 9 })
7 export class BoxesComponent { 10 export class BoxesComponent {
8 11
9 @Input() boxes: noosfero.Box[]; 12 @Input() boxes: noosfero.Box[];
10 @Input() owner: noosfero.Profile | noosfero.Environment; 13 @Input() owner: noosfero.Profile | noosfero.Environment;
  14 + @Input() layout: string;
11 15
12 - boxesOrder(box: noosfero.Box) {  
13 - if (box.position === 2) return 0;  
14 - return box.position;  
15 - }  
16 } 16 }
src/app/layout/boxes/boxes.html
1 -<ng-include ng-repeat="box in ctrl.boxes | orderBy: ctrl.boxesOrder" src="'app/layout/boxes/box.html'"></ng-include> 1 +<ng-include ng-repeat="box in ctrl.boxes | displayBoxes:ctrl.layout" src="'app/layout/boxes/box.html'"></ng-include>
src/app/layout/boxes/display-boxes.filter.spec.ts 0 → 100644
@@ -0,0 +1,51 @@ @@ -0,0 +1,51 @@
  1 +import {DisplayBoxes} from './display-boxes.filter';
  2 +
  3 +describe("Boxes Filters", () => {
  4 + describe("Display Boxes Filter", () => {
  5 +
  6 + let boxes: noosfero.Box[] = [
  7 + {id: 1, position: 1 },
  8 + {id: 2, position: 2 },
  9 + {id: 3, position: 3 },
  10 + {id: 4, position: 4 }
  11 + ];
  12 +
  13 + let expected_on_default: noosfero.Box[] = [
  14 + {id: 1, position: 1 },
  15 + {id: 2, position: 2 },
  16 + {id: 3, position: 3 },
  17 + ];
  18 +
  19 + let expected_on_rightbar: noosfero.Box[] = [
  20 + {id: 1, position: 1 },
  21 + {id: 3, position: 3 },
  22 + ];
  23 +
  24 + it("filter boxes when layout is set to default", done => {
  25 + let filter = new DisplayBoxes();
  26 +
  27 + let filtered_boxes: noosfero.Box[] = filter.transform(boxes, "default");
  28 + expect(filtered_boxes.length).toEqual(3);
  29 + expect(filtered_boxes).toEqual(expected_on_default);
  30 + done();
  31 + });
  32 +
  33 + it("filter boxes when layout is set to rightbar", done => {
  34 + let filter = new DisplayBoxes();
  35 +
  36 + let filtered_boxes: noosfero.Box[] = filter.transform(boxes, "rightbar");
  37 + expect(filtered_boxes.length).toEqual(2);
  38 + expect(filtered_boxes).toEqual(expected_on_rightbar);
  39 + done();
  40 + });
  41 +
  42 + it("filter boxes with default layout when invalid layout is given", done => {
  43 + let filter = new DisplayBoxes();
  44 +
  45 + let filtered_boxes: noosfero.Box[] = filter.transform(boxes, "");
  46 + expect(filtered_boxes.length).toEqual(3);
  47 + expect(filtered_boxes).toEqual(expected_on_default);
  48 + done();
  49 + });
  50 + });
  51 +});
src/app/layout/boxes/display-boxes.filter.ts 0 → 100644
@@ -0,0 +1,37 @@ @@ -0,0 +1,37 @@
  1 +import {Pipe, Inject} from "ng-forward";
  2 +import {TranslatorService} from "../../shared/services/translator.service";
  3 +
  4 +@Pipe("displayBoxes")
  5 +@Inject(TranslatorService)
  6 +export class DisplayBoxes {
  7 +
  8 + transform(boxes: noosfero.Box[], layout: string) {
  9 + let function_str: string = "visible_on" + layout;
  10 + let valid_boxes: number[] = [];
  11 + let selected: noosfero.Box[] = [];
  12 + boxes = boxes || [];
  13 +
  14 + if (layout === "rightbar") {
  15 + valid_boxes = this.visible_on_right_bar();
  16 + }else {
  17 + valid_boxes = this.visible_on_default();
  18 + }
  19 +
  20 + for (let box of boxes) {
  21 + if (valid_boxes.indexOf(box.position) !== -1) {
  22 + selected.push(box);
  23 + }
  24 + }
  25 + return selected;
  26 + }
  27 +
  28 + private visible_on_default() {
  29 + return [1, 2, 3];
  30 + }
  31 +
  32 + private visible_on_right_bar() {
  33 + return [1, 3];
  34 + }
  35 +
  36 +}
  37 +
src/app/layout/boxes/set-box-layout.filter.spec.ts 0 → 100644
@@ -0,0 +1,34 @@ @@ -0,0 +1,34 @@
  1 +import {SetBoxLayout} from './set-box-layout.filter';
  2 +
  3 +describe("Boxes Filters", () => {
  4 + describe("Set Box Layout Filter", () => {
  5 + let box_layout_filter = new SetBoxLayout();
  6 + describe("When layout is set to default", () => {
  7 + it("return style when box position is 1 ", done => {
  8 + expect(box_layout_filter.transform(1, "default")).toEqual("col-md-6 col-md-push-3");
  9 + done();
  10 + });
  11 + it("return style when box position is 2", done => {
  12 + expect(box_layout_filter.transform(2, "default")).toEqual("col-md-3 col-md-pull-6");
  13 + done();
  14 + });
  15 + it("return style when any other position is given", done => {
  16 + expect(box_layout_filter.transform(null, "default")).toEqual("col-md-3");
  17 + expect(box_layout_filter.transform(3, "default")).toEqual("col-md-3");
  18 + expect(box_layout_filter.transform(99, "default")).toEqual("col-md-3");
  19 + done();
  20 + });
  21 + });
  22 +
  23 + describe("When layout is set to right_bar", () => {
  24 + it("return style when box position is 1 ", done => {
  25 + expect(box_layout_filter.transform(1, "rightbar")).toEqual("col-sm-6 col-sm-push-2");
  26 + done();
  27 + });
  28 + it("return style when box other position is given", done => {
  29 + expect(box_layout_filter.transform(2, "rightbar")).toEqual("col-sm-3 col-sm-push-2");
  30 + done();
  31 + });
  32 + });
  33 + });
  34 +});
src/app/layout/boxes/set-box-layout.filter.ts 0 → 100644
@@ -0,0 +1,34 @@ @@ -0,0 +1,34 @@
  1 +import {Pipe, Inject} from "ng-forward";
  2 +import {TranslatorService} from "../../shared/services/translator.service";
  3 +
  4 +@Pipe("setBoxLayout")
  5 +@Inject(TranslatorService)
  6 +export class SetBoxLayout {
  7 +
  8 + transform(pos: number, layout: string) {
  9 + if (layout === "rightbar") {
  10 + return this.right_bar(pos);
  11 + }else {
  12 + return this.default(pos);
  13 + }
  14 + }
  15 +
  16 + private default(position: number) {
  17 + if (position === 1) {
  18 + return "col-md-6 col-md-push-3";
  19 + }else if (position === 2) {
  20 + return "col-md-3 col-md-pull-6";
  21 + }else {
  22 + return "col-md-3";
  23 + }
  24 + }
  25 +
  26 + private right_bar(position: number) {
  27 + if (position === 1) {
  28 + return "col-sm-6 col-sm-push-2";
  29 + }else {
  30 + return "col-sm-3 col-sm-push-2";
  31 + }
  32 + }
  33 +
  34 +}
src/app/layout/language-selector/language-selector.html
1 -<li class="dropdown profile-menu" uib-dropdown> 1 +<li class="dropdown profile-menu btn-nav" uib-dropdown>
2 <a href="#" class="dropdown-toggle" aria-expanded="false" uib-dropdown-toggle> 2 <a href="#" class="dropdown-toggle" aria-expanded="false" uib-dropdown-toggle>
3 <span>{{"language.selector" | translate}}</span> <b class="caret"></b> 3 <span>{{"language.selector" | translate}}</span> <b class="caret"></b>
4 </a> 4 </a>
src/app/layout/navbar/navbar.html
@@ -16,7 +16,7 @@ @@ -16,7 +16,7 @@
16 </ul> 16 </ul>
17 17
18 <ul class="nav navbar-nav navbar-right"> 18 <ul class="nav navbar-nav navbar-right">
19 - <li ng-show="!ctrl.currentUser"> 19 + <li class="btn-nav" ng-show="!ctrl.currentUser">
20 <a ng-href="#" ng-click="ctrl.openLogin()">{{"navbar.login" | translate}}</a> 20 <a ng-href="#" ng-click="ctrl.openLogin()">{{"navbar.login" | translate}}</a>
21 </li> 21 </li>
22 22
@@ -51,4 +51,4 @@ @@ -51,4 +51,4 @@
51 </div> 51 </div>
52 </nav> 52 </nav>
53 <div ui-view="toolbar"> 53 <div ui-view="toolbar">
54 -</div>  
55 \ No newline at end of file 54 \ No newline at end of file
  55 +</div>
src/app/layout/navbar/navbar.scss
@@ -50,4 +50,10 @@ @@ -50,4 +50,10 @@
50 } 50 }
51 } 51 }
52 } 52 }
  53 +
  54 + .btn-nav {
  55 + border-radius: 0px;
  56 + height: 50px;
  57 + border: none;
  58 + }
53 } 59 }
src/app/layout/navbar/navbar.spec.ts
@@ -9,6 +9,8 @@ import {SessionService, AuthService, AuthController, AuthEvents} from &quot;./../../l @@ -9,6 +9,8 @@ import {SessionService, AuthService, AuthController, AuthEvents} from &quot;./../../l
9 9
10 import events from 'ng-forward/cjs/events/events'; 10 import events from 'ng-forward/cjs/events/events';
11 11
  12 +import {DesignModeService} from '../../admin/layout-edit/designMode.service';
  13 +
12 describe("Components", () => { 14 describe("Components", () => {
13 15
14 describe("Navbar Component", () => { 16 describe("Navbar Component", () => {
@@ -22,6 +24,7 @@ describe(&quot;Components&quot;, () =&gt; { @@ -22,6 +24,7 @@ describe(&quot;Components&quot;, () =&gt; {
22 let authService: any; 24 let authService: any;
23 let stateService: any; 25 let stateService: any;
24 let sessionService: SessionService; 26 let sessionService: SessionService;
  27 + let designModeService: DesignModeService;
25 28
26 let provideFunc = provide; 29 let provideFunc = provide;
27 30
@@ -37,6 +40,7 @@ describe(&quot;Components&quot;, () =&gt; { @@ -37,6 +40,7 @@ describe(&quot;Components&quot;, () =&gt; {
37 authService = helpers.mocks.authService; 40 authService = helpers.mocks.authService;
38 stateService = jasmine.createSpyObj("$state", ["go"]); 41 stateService = jasmine.createSpyObj("$state", ["go"]);
39 sessionService = <any>helpers.mocks.sessionWithCurrentUser(user); 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,6 +80,9 @@ describe(&quot;Components&quot;, () =&gt; {
76 }), 80 }),
77 provide('TranslatorService', { 81 provide('TranslatorService', {
78 useValue: helpers.mocks.translatorService 82 useValue: helpers.mocks.translatorService
  83 + }),
  84 + provide('DesignModeService', {
  85 + useValue: helpers.mocks.designModeService
79 }) 86 })
80 ].concat(helpers.provideFilters("translateFilter")), 87 ].concat(helpers.provideFilters("translateFilter")),
81 directives: [Navbar], 88 directives: [Navbar],
src/app/layout/scss/_forms.scss 0 → 100644
@@ -0,0 +1,36 @@ @@ -0,0 +1,36 @@
  1 +label {
  2 + cursor: pointer;
  3 +}
  4 +
  5 +.checkbox-nice {
  6 + position: relative;
  7 + padding-left: 15px;
  8 +
  9 + input[type=checkbox] {
  10 + visibility: hidden;
  11 + }
  12 + label {
  13 + padding-top: 3px;
  14 + }
  15 + &.checkbox-inline > label {
  16 + margin-left: 16px;
  17 + }
  18 + label:before {
  19 + @include checkbox-mark(22px, 22px, 1px, 1px, #ffffff, 2px solid $main-bg-color);
  20 + @include border-radius(3px);
  21 + }
  22 + label:after {
  23 + @include checkbox-mark(12px, 7px, 7px, 6px, transparent, 3px solid #000);
  24 + @include opacity(0);
  25 +
  26 + border-top: none;
  27 + border-right: none;
  28 + transform: rotate(-45deg);
  29 + }
  30 + label:hover::after {
  31 + @include opacity(0.3);
  32 + }
  33 + input[type=checkbox]:checked + label:after {
  34 + @include opacity(1);
  35 + }
  36 +}
src/app/layout/scss/_mixins.scss
@@ -3,3 +3,48 @@ @@ -3,3 +3,48 @@
3 border-radius: $radius; 3 border-radius: $radius;
4 background-clip: padding-box; /* stops bg color from leaking outside the border: */ 4 background-clip: padding-box; /* stops bg color from leaking outside the border: */
5 } 5 }
  6 +
  7 +@mixin checkbox-mark($width, $height, $top, $left, $bg, $border, $content: "", $cursor: pointer, $position: absolute) {
  8 + width: $width;
  9 + height: $height;
  10 + cursor: $cursor;
  11 + position: $position;
  12 + left: $left;
  13 + top: $top;
  14 + background: $bg;
  15 + content: $content;
  16 + border: $border;
  17 +}
  18 +
  19 +@mixin opacity($opacity) {
  20 + /* Netscape */
  21 + -moz-opacity: $opacity;
  22 +
  23 + /* Safari 1.x */
  24 + -khtml-opacity: $opacity;
  25 +
  26 + /* Good browsers */
  27 + opacity: $opacity;
  28 +}
  29 +
  30 +@mixin transition($args...) {
  31 +
  32 + $duration: 300ms;
  33 + $keys: keywords($args);
  34 + @if map-has-key($keys, duration) {
  35 + $duration: map-get($keys, duration);
  36 + }
  37 +
  38 + -webkit-transition: $args;
  39 + -o-transition: $args;
  40 + transition: $args;
  41 + -webkit-transition-duration: $duration;
  42 + transition-duration: $duration;
  43 +}
  44 +
  45 +@mixin outline($style: none, $width: 0px) {
  46 + &:focus {
  47 + outline-style: $style;
  48 + outline-width: $width;
  49 + }
  50 +}
src/app/layout/scss/skins/_whbl.scss
@@ -7,6 +7,15 @@ $whbl-font-color: #16191c; @@ -7,6 +7,15 @@ $whbl-font-color: #16191c;
7 #header-navbar { 7 #header-navbar {
8 background-color: $whbl-primary-color; 8 background-color: $whbl-primary-color;
9 } 9 }
  10 +
  11 + .navbar {
  12 + .btn-nav {
  13 + &:hover {
  14 + background-color: #1b86ba;
  15 + }
  16 + }
  17 + }
  18 +
10 .navbar > .container .navbar-brand { 19 .navbar > .container .navbar-brand {
11 background-color: transparent; 20 background-color: transparent;
12 width: 221px; 21 width: 221px;
@@ -306,6 +315,13 @@ $whbl-font-color: #16191c; @@ -306,6 +315,13 @@ $whbl-font-color: #16191c;
306 color: white; 315 color: white;
307 } 316 }
308 317
  318 + /* Form overrides */
  319 + .checkbox-nice {
  320 + label:after {
  321 + border-color: $whbl-primary-color;
  322 + }
  323 + }
  324 +
309 } 325 }
310 .rtl.skin-whbl #content-wrapper { 326 .rtl.skin-whbl #content-wrapper {
311 border-left: 0; 327 border-left: 0;
src/app/layout/services/body-state-classes.service.spec.ts
@@ -5,11 +5,13 @@ import {AuthEvents} from &quot;./../../login/auth-events&quot;; @@ -5,11 +5,13 @@ import {AuthEvents} from &quot;./../../login/auth-events&quot;;
5 5
6 import {EventEmitter} from 'ng-forward'; 6 import {EventEmitter} from 'ng-forward';
7 import {DesignModeService} from './../../admin/layout-edit/designMode.service'; 7 import {DesignModeService} from './../../admin/layout-edit/designMode.service';
  8 +import {INoosferoLocalStorage} from "./../../shared/models/interfaces";
8 9
9 describe("BodyStateClasses Service", () => { 10 describe("BodyStateClasses Service", () => {
10 11
11 let currentStateName = "main"; 12 let currentStateName = "main";
12 let bodyStateClasseService: BodyStateClassesService; 13 let bodyStateClasseService: BodyStateClassesService;
  14 + let $localStorage = <INoosferoLocalStorage>{ currentUser: null, settings: { designMode: false } };
13 let $rootScope: ng.IRootScopeService = <any>{}, 15 let $rootScope: ng.IRootScopeService = <any>{},
14 $document: ng.IDocumentService = <any>{}, 16 $document: ng.IDocumentService = <any>{},
15 $state: ng.ui.IStateService = <any>{ 17 $state: ng.ui.IStateService = <any>{
@@ -20,7 +22,7 @@ describe(&quot;BodyStateClasses Service&quot;, () =&gt; { @@ -20,7 +22,7 @@ describe(&quot;BodyStateClasses Service&quot;, () =&gt; {
20 authService: any = helpers.mocks.authService, 22 authService: any = helpers.mocks.authService,
21 bodyEl: { className: string }, 23 bodyEl: { className: string },
22 bodyElJq: any, 24 bodyElJq: any,
23 - designModeService = new DesignModeService(); 25 + designModeService = new DesignModeService($localStorage);
24 26
25 27
26 28
@@ -174,7 +176,7 @@ describe(&quot;BodyStateClasses Service&quot;, () =&gt; { @@ -174,7 +176,7 @@ describe(&quot;BodyStateClasses Service&quot;, () =&gt; {
174 176
175 it("should add the class noosfero-design-on when designMode is changed to true", () => { 177 it("should add the class noosfero-design-on when designMode is changed to true", () => {
176 let fnOnToggle: Function = null; 178 let fnOnToggle: Function = null;
177 - designModeService.onToggle = <any> { 179 + designModeService.onToggle = <any>{
178 subscribe: (fn: Function) => { 180 subscribe: (fn: Function) => {
179 fnOnToggle = fn; 181 fnOnToggle = fn;
180 }, 182 },
src/app/login/login.html
@@ -4,13 +4,21 @@ @@ -4,13 +4,21 @@
4 <div class="modal-body"> 4 <div class="modal-body">
5 <form> 5 <form>
6 <div class="form-group"> 6 <div class="form-group">
7 - <label for="exampleInputEmail1">{{"auth.form.login" | translate}}</label>  
8 - <input type="text" class="form-control" id="exampleInputEmail1" placeholder="Login / Email" ng-model="vm.credentials.username"> 7 + <label for="email">{{"auth.form.login" | translate}}</label>
  8 + <input type="text" class="form-control" id="email" placeholder="{{'auth.form.login' | translate}}" ng-model="vm.credentials.username">
9 </div> 9 </div>
10 <div class="form-group"> 10 <div class="form-group">
11 - <label for="exampleInputPassword1">{{"auth.form.password" | translate}}</label>  
12 - <input type="password" class="form-control" id="exampleInputPassword1" placeholder="Password" ng-model="vm.credentials.password"> 11 + <label for="passwd">{{"auth.form.password" | translate}}</label>
  12 + <input type="password" class="form-control" id="passwd" placeholder="{{'auth.form.password' | translate}}" ng-model="vm.credentials.password">
13 </div> 13 </div>
14 - <button type="submit" class="btn btn-default" ng-click="vm.login()">{{"auth.form.login_button" | translate}}</button> 14 + <div class="form-inline">
  15 + <div class="checkbox-nice">
  16 + <input type="checkbox" id="keep-logged">
  17 + <label for="keep-logged">
  18 + {{"auth.form.keepLoggedIn" | translate}}
  19 + </label>
  20 + </div>
  21 + </div>
  22 + <button type="submit" class="btn btn-default btn-block" ng-click="vm.login()">{{"auth.form.login_button" | translate}}</button>
15 </form> 23 </form>
16 </div> 24 </div>
src/app/login/login.scss 0 → 100644
@@ -0,0 +1,43 @@ @@ -0,0 +1,43 @@
  1 +.modal-content {
  2 + padding: 40px;
  3 + .modal-header {
  4 + border-bottom: 0;
  5 + text-align: center;
  6 + }
  7 + form {
  8 + margin-bottom: 30px;
  9 + button {
  10 + margin-top: 20px;
  11 + text-transform: uppercase;
  12 + }
  13 + }
  14 +}
  15 +
  16 +.strike {
  17 + display: block;
  18 + text-align: center;
  19 + overflow: hidden;
  20 + white-space: nowrap;
  21 + padding: 25px 0;
  22 + > span {
  23 + position: relative;
  24 + display: inline-block;
  25 + text-transform: uppercase;
  26 + }
  27 + > span:before, > span:after {
  28 + content: "";
  29 + position: absolute;
  30 + top: 50%;
  31 + width: 9999px;
  32 + height: 1px;
  33 + background: black;
  34 + }
  35 + > span:before {
  36 + right: 100%;
  37 + margin-right: 15px;
  38 + }
  39 + > span:after {
  40 + left: 100%;
  41 + margin-left: 15px;
  42 + }
  43 +}
src/app/login/session.service.spec.ts
@@ -13,7 +13,7 @@ describe(&quot;Services&quot;, () =&gt; { @@ -13,7 +13,7 @@ describe(&quot;Services&quot;, () =&gt; {
13 let $log: any; 13 let $log: any;
14 14
15 beforeEach(() => { 15 beforeEach(() => {
16 - $localStorage = <INoosferoLocalStorage>{ currentUser: null }; 16 + $localStorage = <INoosferoLocalStorage>{ currentUser: null, settings: null };
17 $log = jasmine.createSpyObj('$log', ['debug']); 17 $log = jasmine.createSpyObj('$log', ['debug']);
18 }); 18 });
19 19
src/app/login/session.service.ts
@@ -16,6 +16,7 @@ export class SessionService { @@ -16,6 +16,7 @@ export class SessionService {
16 16
17 destroy() { 17 destroy() {
18 delete this.$localStorage.currentUser; 18 delete this.$localStorage.currentUser;
  19 + delete this.$localStorage.settings;
19 }; 20 };
20 21
21 currentUser(): noosfero.User { 22 currentUser(): noosfero.User {
src/app/main/main.component.ts
@@ -18,6 +18,7 @@ import {ProfileImageBlockComponent} from &quot;../layout/blocks/profile-image/profile @@ -18,6 +18,7 @@ import {ProfileImageBlockComponent} from &quot;../layout/blocks/profile-image/profile
18 import {RawHTMLBlockComponent} from "../layout/blocks/raw-html/raw-html-block.component"; 18 import {RawHTMLBlockComponent} from "../layout/blocks/raw-html/raw-html-block.component";
19 import {StatisticsBlockComponent} from "../layout/blocks/statistics/statistics-block.component"; 19 import {StatisticsBlockComponent} from "../layout/blocks/statistics/statistics-block.component";
20 import {PersonTagsPluginInterestsBlockComponent} from "../layout/blocks/person-tags-plugin-interests/person-tags-plugin-interests-block.component"; 20 import {PersonTagsPluginInterestsBlockComponent} from "../layout/blocks/person-tags-plugin-interests/person-tags-plugin-interests-block.component";
  21 +import {TagsBlockComponent} from "../layout/blocks/tags/tags-block.component";
21 import {CustomContentComponent} from "../profile/custom-content/custom-content.component"; 22 import {CustomContentComponent} from "../profile/custom-content/custom-content.component";
22 23
23 import {MembersBlockComponent} from "../layout/blocks/members/members-block.component"; 24 import {MembersBlockComponent} from "../layout/blocks/members/members-block.component";
@@ -105,7 +106,7 @@ export class EnvironmentContent { @@ -105,7 +106,7 @@ export class EnvironmentContent {
105 MainBlockComponent, RecentDocumentsBlockComponent, Navbar, SidebarComponent, ProfileImageBlockComponent, 106 MainBlockComponent, RecentDocumentsBlockComponent, Navbar, SidebarComponent, ProfileImageBlockComponent,
106 MembersBlockComponent, NoosferoTemplate, DateFormat, RawHTMLBlockComponent, StatisticsBlockComponent, 107 MembersBlockComponent, NoosferoTemplate, DateFormat, RawHTMLBlockComponent, StatisticsBlockComponent,
107 LoginBlockComponent, CustomContentComponent, PermissionDirective, SearchFormComponent, SearchComponent, 108 LoginBlockComponent, CustomContentComponent, PermissionDirective, SearchFormComponent, SearchComponent,
108 - PersonTagsPluginInterestsBlockComponent, BlockComponent 109 + PersonTagsPluginInterestsBlockComponent, TagsBlockComponent, BlockComponent
109 ].concat(plugins.mainComponents).concat(plugins.hotspots), 110 ].concat(plugins.mainComponents).concat(plugins.hotspots),
110 providers: [AuthService, SessionService, NotificationService, BodyStateClassesService, 111 providers: [AuthService, SessionService, NotificationService, BodyStateClassesService,
111 "ngAnimate", "ngCookies", "ngStorage", "ngTouch", 112 "ngAnimate", "ngCookies", "ngStorage", "ngTouch",
@@ -114,7 +115,7 @@ export class EnvironmentContent { @@ -114,7 +115,7 @@ export class EnvironmentContent {
114 "angular-bind-html-compile", "angularMoment", "angular.filter", "akoenig.deckgrid", 115 "angular-bind-html-compile", "angularMoment", "angular.filter", "akoenig.deckgrid",
115 "angular-timeline", "duScroll", "oitozero.ngSweetAlert", 116 "angular-timeline", "duScroll", "oitozero.ngSweetAlert",
116 "pascalprecht.translate", "tmh.dynamicLocale", "angularLoad", 117 "pascalprecht.translate", "tmh.dynamicLocale", "angularLoad",
117 - "angular-click-outside", "toggle-switch", "noosfero.init"] 118 + "angular-click-outside", "toggle-switch", "ngTagCloud", "noosfero.init"]
118 }) 119 })
119 @StateConfig([ 120 @StateConfig([
120 { 121 {
src/app/profile/custom-content/custom-content.component.spec.ts
1 import {CustomContentComponent} from './custom-content.component'; 1 import {CustomContentComponent} from './custom-content.component';
2 import {ComponentTestHelper, createClass} from '../../../spec/component-test-helper'; 2 import {ComponentTestHelper, createClass} from '../../../spec/component-test-helper';
3 import * as helpers from "../../../spec/helpers"; 3 import * as helpers from "../../../spec/helpers";
  4 +import {DesignModeService} from '../../admin/layout-edit/designMode.service';
4 5
5 const htmlTemplate: string = '<custom-content [attribute]="\'custom_footer\'" [profile]="ctrl.profile"></custom-content>'; 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,6 +15,7 @@ describe(&quot;Components&quot;, () =&gt; {
14 beforeEach((done) => { 15 beforeEach((done) => {
15 let profileService = jasmine.createSpyObj("profileService", ["update"]); 16 let profileService = jasmine.createSpyObj("profileService", ["update"]);
16 let notificationService = jasmine.createSpyObj("notificationService", ["success"]); 17 let notificationService = jasmine.createSpyObj("notificationService", ["success"]);
  18 + let designModeService = { isInDesignMode: () => { return true; }};
17 let properties = { profile: { custom_footer: "footer" } }; 19 let properties = { profile: { custom_footer: "footer" } };
18 let cls = createClass({ 20 let cls = createClass({
19 template: htmlTemplate, 21 template: htmlTemplate,
@@ -22,7 +24,8 @@ describe(&quot;Components&quot;, () =&gt; { @@ -22,7 +24,8 @@ describe(&quot;Components&quot;, () =&gt; {
22 providers: [ 24 providers: [
23 helpers.createProviderToValue("$uibModal", helpers.mocks.$modal), 25 helpers.createProviderToValue("$uibModal", helpers.mocks.$modal),
24 helpers.createProviderToValue("ProfileService", profileService), 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 helper = new ComponentTestHelper<CustomContentComponent>(cls, done); 31 helper = new ComponentTestHelper<CustomContentComponent>(cls, done);
src/app/profile/custom-content/custom-content.component.ts
@@ -12,7 +12,8 @@ import {DesignModeService} from &#39;../../admin/layout-edit/designMode.service&#39;; @@ -12,7 +12,8 @@ import {DesignModeService} from &#39;../../admin/layout-edit/designMode.service&#39;;
12 @Inject("$uibModal", "$scope", ProfileService, NotificationService, DesignModeService) 12 @Inject("$uibModal", "$scope", ProfileService, NotificationService, DesignModeService)
13 export class CustomContentComponent { 13 export class CustomContentComponent {
14 14
15 - static $inject = ["DesignModeService"]; // @Inject doesn't works with uibModal.open 15 + // @Inject doesn't works with uibModal.open
  16 + static $inject = ["DesignModeService"];
16 17
17 @Input() attribute: string; 18 @Input() attribute: string;
18 @Input() profile: noosfero.Profile; 19 @Input() profile: noosfero.Profile;
@@ -20,7 +21,6 @@ export class CustomContentComponent { @@ -20,7 +21,6 @@ export class CustomContentComponent {
20 21
21 content: string; 22 content: string;
22 originalContent: string; 23 originalContent: string;
23 - editionMode = false;  
24 private modalInstance: any = null; 24 private modalInstance: any = null;
25 25
26 constructor(private $uibModal: any, 26 constructor(private $uibModal: any,
@@ -35,9 +35,10 @@ export class CustomContentComponent { @@ -35,9 +35,10 @@ export class CustomContentComponent {
35 }, () => { 35 }, () => {
36 if (this.profile) this.content = (<any>this.profile)[this.attribute]; 36 if (this.profile) this.content = (<any>this.profile)[this.attribute];
37 }); 37 });
38 - this.designModeService.onToggle.subscribe((designModeOn: boolean) => {  
39 - this.editionMode = designModeOn;  
40 - }); 38 + }
  39 +
  40 + inEditMode() {
  41 + return this.designModeService.isInDesignMode();
41 } 42 }
42 43
43 openEdit() { 44 openEdit() {
src/app/profile/custom-content/custom-content.html
1 <div class="custom-content"> 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 <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> 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 </div> 4 </div>
5 <div class="content" ng-bind-html="ctrl.content"></div> 5 <div class="content" ng-bind-html="ctrl.content"></div>
src/app/profile/profile.html
1 <div class="profile-container"> 1 <div class="profile-container">
2 - <custom-content class="profile-header" [label]="'profile.custom_header.label'" [attribute]="'custom_header'" [profile]="vm.profile"></custom-content>  
3 - <div class="row">  
4 - <noosfero-boxes ng-if="vm.boxes" [boxes]="vm.boxes" [owner]="vm.profile"></noosfero-boxes>  
5 - </div> 2 + <custom-content class="profile-header"
  3 + [label]="'profile.custom_header.label'"
  4 + [attribute]="'custom_header'"
  5 + [profile]="vm.profile">
  6 + </custom-content>
  7 + <div class="row" ui-view="profile-info"></div>
  8 + <noosfero-boxes ng-if="vm.boxes"
  9 + [layout]="vm.profile.layout_template"
  10 + [boxes]="vm.boxes"
  11 + [owner]="vm.profile" class="row">
  12 + </noosfero-boxes>
6 <custom-content class="profile-footer" [label]="'profile.custom_footer.label'" [attribute]="'custom_footer'" [profile]="vm.profile"></custom-content> 13 <custom-content class="profile-footer" [label]="'profile.custom_footer.label'" [attribute]="'custom_footer'" [profile]="vm.profile"></custom-content>
7 </div> 14 </div>
src/app/search/search-form/search-form.component.spec.ts
@@ -21,8 +21,8 @@ describe(&quot;Components&quot;, () =&gt; { @@ -21,8 +21,8 @@ describe(&quot;Components&quot;, () =&gt; {
21 helper = new ComponentTestHelper<SearchFormComponent>(cls, done); 21 helper = new ComponentTestHelper<SearchFormComponent>(cls, done);
22 }); 22 });
23 23
24 - it("render a input for search query", () => {  
25 - expect(helper.find(".search-input").length).toEqual(1); 24 + it("render a button that open a search query field", () => {
  25 + expect(helper.find(".btn-search-nav").length).toEqual(1);
26 }); 26 });
27 27
28 it("go to search page when click on search button", () => { 28 it("go to search page when click on search button", () => {
src/app/search/search-form/search-form.html
1 -<form class="navbar-form search-form" role="search" ng-if="!ctrl.isSearchPage()">  
2 - <div class="input-group">  
3 - <input type="text" class="search-input form-control" placeholder="Search" name="q" ng-model="ctrl.query">  
4 - <div class="input-group-btn">  
5 - <button class="btn btn-default" type="submit" (click)="ctrl.search()"><i class="fa fa-search fa-fw"></i></button> 1 +<a class="btn btn-nav" ng-click="showSearch = !showSearch">
  2 + <i class="fa fa-search btn-search-nav" aria-hidden="true"></i>
  3 +</a>
  4 +<form class="navbar-form search-form" role="search">
  5 + <div class="ng-scope" ng-class="{'top-search-wrap': !showSearch, 'top-search-toggled': showSearch}">
  6 + <div class="tsw-inner">
  7 + <i id="top-search-close" class="fa fa-chevron-left" aria-hidden="true" ng-click="showSearch = false"></i>
  8 + <input type="text" placeholder="{{ 'search.label' | translate }}" name="q" ng-model="ctrl.query">
  9 + <i class="fa fa-search btn-search" aria-hidden="true" (click)="ctrl.search()"></i>
  10 + <button type="submit" (click)="ctrl.search()"></i>
6 </div> 11 </div>
7 </div> 12 </div>
8 </form> 13 </form>
src/app/search/search-form/search-form.scss 0 → 100644
@@ -0,0 +1,107 @@ @@ -0,0 +1,107 @@
  1 +/**
  2 +* TODO: Remove the temporary reimport mixins
  3 +* Maybe the cause for this is in gulp/styles.js
  4 +* task on compile sass order.
  5 +*/
  6 +@import "../../layout/scss/mixins";
  7 +
  8 +@mixin search-wrap-btn {
  9 + @include border-radius(2px 0px 0px 2px);
  10 + @content;
  11 + font-size: 23px;
  12 + font-style: normal;
  13 + width: 45px;
  14 + text-align: center;
  15 + cursor: pointer;
  16 + height: 40px;
  17 + padding-top: 9px;
  18 +
  19 + background-color: #e3e3e3;
  20 + &:hover {
  21 + background-color: #D1D1D1;
  22 + }
  23 +
  24 + @include outline(none);
  25 +}
  26 +
  27 +.top-search-wrap {
  28 + @include opacity(0);
  29 + @include transition(all);
  30 +
  31 + position: absolute;
  32 + top: -65px;
  33 + left: 0;
  34 + width: 100%;
  35 + height: 70px;
  36 + background: #fff;
  37 + z-index: 10;
  38 +
  39 + .tsw-inner {
  40 + position: relative;
  41 + padding: 15px;
  42 + max-width: 700px;
  43 + display: block;
  44 + margin: 0 auto;
  45 + }
  46 +
  47 + #top-search-close {
  48 + @include border-radius(2px 0px 0px 2px);
  49 + @include search-wrap-btn {
  50 + position: absolute;
  51 + top: 15px;
  52 + left: 15px;
  53 + }
  54 +
  55 + @include outline(none);
  56 + }
  57 +
  58 + .btn-search {
  59 + display: inline;
  60 + float: right;
  61 +
  62 + @include search-wrap-btn {
  63 + position: relative;
  64 + top: -40px;
  65 + left: 0px;
  66 + }
  67 +
  68 + }
  69 +
  70 + input[type="text"] {
  71 + @include border-radius(2px);
  72 + border: 0;
  73 + height: 40px;
  74 + padding: 0 10px 0 55px;
  75 + font-size: 18px;
  76 + width: 500px;
  77 + background-color: #efefef;
  78 + width: 100%;
  79 +
  80 + @include outline(none);
  81 + }
  82 +
  83 +}
  84 +
  85 +.top-search-toggled {
  86 + @extend .top-search-wrap;
  87 + @include opacity(1);
  88 + position: fixed;
  89 + top: 0;
  90 + box-shadow: 0px 1px 4px rgba(0, 0, 0, 0.3);
  91 +}
  92 +
  93 +.btn-nav {
  94 + .btn-search-nav {
  95 + font-size: 25px;
  96 + color: #FFF;
  97 + cursor: pointer;
  98 + padding: 1px;
  99 + }
  100 +}
  101 +
  102 +
  103 +.search-form {
  104 + button[type="submit"] {
  105 + visibility: hidden;
  106 + }
  107 +}
src/app/search/search.component.ts
@@ -23,7 +23,7 @@ export class SearchComponent { @@ -23,7 +23,7 @@ export class SearchComponent {
23 } 23 }
24 24
25 search() { 25 search() {
26 - this.$state.go('main.environment.search', { query: this.query }); 26 + this.$state.go('main.environment.search', { query: this.query });
27 } 27 }
28 28
29 loadPage() { 29 loadPage() {
src/app/search/search.html
1 <form ng-submit="ctrl.search()"> 1 <form ng-submit="ctrl.search()">
2 <label for="query" ng-bind-html="'search.results.query.label' | translate"></label> 2 <label for="query" ng-bind-html="'search.results.query.label' | translate"></label>
3 -<input id="query" placeholder="{{'search.results.query.placeholder' | translate}}" type="search" class="search-box-title" ng-model="ctrl.query"> 3 +<h3 id="query" class="search-box-title">{{ctrl.query}}</h3>
4 </form> 4 </form>
5 <div class="search-results"> 5 <div class="search-results">
6 <div class="summary"> 6 <div class="summary">
src/app/search/search.scss
@@ -2,7 +2,6 @@ @@ -2,7 +2,6 @@
2 .summary { 2 .summary {
3 color: #bbbbbb; 3 color: #bbbbbb;
4 font-size: 13px; 4 font-size: 13px;
5 - border-top: 1px solid #ececec;  
6 } 5 }
7 .result { 6 .result {
8 margin: 25px 0; 7 margin: 25px 0;
@@ -45,4 +44,4 @@ @@ -45,4 +44,4 @@
45 44
46 .search-box-title:focus { 45 .search-box-title:focus {
47 outline: none; 46 outline: none;
48 -}  
49 \ No newline at end of file 47 \ No newline at end of file
  48 +}
src/app/shared/models/interfaces.ts
@@ -8,4 +8,5 @@ export interface UserResponse { @@ -8,4 +8,5 @@ export interface UserResponse {
8 8
9 export interface INoosferoLocalStorage extends angular.storage.ILocalStorageService { 9 export interface INoosferoLocalStorage extends angular.storage.ILocalStorageService {
10 currentUser: noosfero.User; 10 currentUser: noosfero.User;
  11 + settings: any;
11 } 12 }
src/languages/en.json
@@ -21,9 +21,10 @@ @@ -21,9 +21,10 @@
21 "activities.create_article.description": "has published on", 21 "activities.create_article.description": "has published on",
22 "activities.add_member_in_community.description": "has joined the community", 22 "activities.add_member_in_community.description": "has joined the community",
23 "activities.new_friendship.description": "has made {friends, plural, one{one new friend} other{# new friends}}:", 23 "activities.new_friendship.description": "has made {friends, plural, one{one new friend} other{# new friends}}:",
24 - "auth.title": "Login",  
25 - "auth.form.login": "Login / Email address", 24 + "auth.title": "Great to have you back!",
  25 + "auth.form.login": "Username or Email address",
26 "auth.form.password": "Password", 26 "auth.form.password": "Password",
  27 + "auth.form.keepLoggedIn": "Keep me logged in",
27 "auth.form.login_button": "Login", 28 "auth.form.login_button": "Login",
28 "navbar.content_viewer_actions.new_item": "New Item", 29 "navbar.content_viewer_actions.new_item": "New Item",
29 "navbar.profile_actions.new_item": "New Item", 30 "navbar.profile_actions.new_item": "New Item",
@@ -80,8 +81,8 @@ @@ -80,8 +81,8 @@
80 "designMode.toggle.ON": "ON", 81 "designMode.toggle.ON": "ON",
81 "designMode.toggle.OFF": "OFF", 82 "designMode.toggle.OFF": "OFF",
82 "search.results.summary": "{results, plural, one{result} other{# results}}", 83 "search.results.summary": "{results, plural, one{result} other{# results}}",
83 - "search.results.query.label": "Search for:",  
84 - "search.results.query.placeholder": "Search", 84 + "search.results.query.label": "Search therm:",
  85 + "search.label": "Search",
85 "block.edit": "Edit", 86 "block.edit": "Edit",
86 "block.edition.title": "Edit Block", 87 "block.edition.title": "Edit Block",
87 "block.edition.success.title": "Good job!", 88 "block.edition.success.title": "Good job!",
src/languages/pt.json
@@ -21,9 +21,10 @@ @@ -21,9 +21,10 @@
21 "activities.create_article.description": "publicou em", 21 "activities.create_article.description": "publicou em",
22 "activities.add_member_in_community.description": "entrou na comunidade", 22 "activities.add_member_in_community.description": "entrou na comunidade",
23 "activities.new_friendship.description": "fez {friends, plural, one{um novo amigo} other{# novos amigos}}:", 23 "activities.new_friendship.description": "fez {friends, plural, one{um novo amigo} other{# novos amigos}}:",
24 - "auth.title": "Login",  
25 - "auth.form.login": "Login / Email", 24 + "auth.title": "Legal ter você de volta!",
  25 + "auth.form.login": "Nome de usuário ou Email",
26 "auth.form.password": "Senha", 26 "auth.form.password": "Senha",
  27 + "auth.form.keepLoggedIn": "Continuar logado",
27 "auth.form.login_button": "Login", 28 "auth.form.login_button": "Login",
28 "navbar.content_viewer_actions.new_item": "Novo Item", 29 "navbar.content_viewer_actions.new_item": "Novo Item",
29 "navbar.profile_actions.new_item": "Novo Item", 30 "navbar.profile_actions.new_item": "Novo Item",
@@ -80,8 +81,8 @@ @@ -80,8 +81,8 @@
80 "designMode.toggle.ON": "Ligado", 81 "designMode.toggle.ON": "Ligado",
81 "designMode.toggle.OFF": "Desligado", 82 "designMode.toggle.OFF": "Desligado",
82 "search.results.summary": "{results, plural, one{# resultado} other{# resultados}}", 83 "search.results.summary": "{results, plural, one{# resultado} other{# resultados}}",
83 - "search.results.query.label": "Buscar:",  
84 - "search.results.query.placeholder": "Informe aqui sua busca", 84 + "search.results.query.label": "Termo da busca:",
  85 + "search.label": "Pesquisar",
85 "block.edit": "Editar", 86 "block.edit": "Editar",
86 "block.edition.title": "Editar Bloco", 87 "block.edition.title": "Editar Bloco",
87 "block.edition.success.title": "Bom trabalho!", 88 "block.edition.success.title": "Bom trabalho!",
src/lib/ng-noosfero-api/http/environment.service.ts
@@ -68,6 +68,14 @@ export class EnvironmentService { @@ -68,6 +68,14 @@ export class EnvironmentService {
68 return errorFunction; 68 return errorFunction;
69 } 69 }
70 70
  71 + getTags(): ng.IPromise<{}> {
  72 + let p = this.restangular.one('environment').customGET('tags');
  73 + let deferred = this.$q.defer<{}>();
  74 + p.then(this.getHandleSuccessFunction<{}>(deferred));
  75 + p.catch(this.getHandleErrorFunction<{}>(deferred));
  76 + return deferred.promise;
  77 + }
  78 +
71 /** 79 /**
72 * TODO - use restangular service as base class, and this will not be necessary here anymore 80 * TODO - use restangular service as base class, and this will not be necessary here anymore
73 */ 81 */
src/lib/ng-noosfero-api/interfaces/environment.ts
@@ -15,5 +15,13 @@ namespace noosfero { @@ -15,5 +15,13 @@ namespace noosfero {
15 */ 15 */
16 id: number; 16 id: number;
17 settings: any 17 settings: any
  18 +
  19 + /**
  20 + * @ngdoc property
  21 + * @name layout_template
  22 + * @propertyOf noofero.Environment
  23 + * @returns {string} The Environment layout (e.g. default, rightbar)
  24 + */
  25 + layout_template: string;
18 } 26 }
19 -}  
20 \ No newline at end of file 27 \ No newline at end of file
  28 +}
src/lib/ng-noosfero-api/interfaces/profile.ts
@@ -80,5 +80,13 @@ namespace noosfero { @@ -80,5 +80,13 @@ namespace noosfero {
80 custom_footer: string; 80 custom_footer: string;
81 81
82 permissions: string[]; 82 permissions: string[];
  83 +
  84 + /**
  85 + * @ngdoc property
  86 + * @name layout_template
  87 + * @propertyOf noofero.Profile
  88 + * @returns {string} The Profile layout template (e.g.: "rightbar", "default")
  89 + */
  90 + layout_template: string;
83 } 91 }
84 } 92 }
src/plugins/comment_paragraph/hotspot/export-comment-button.scss 0 → 100644
@@ -0,0 +1,4 @@ @@ -0,0 +1,4 @@
  1 +.export-comment-button {
  2 + margin-left: 1px;
  3 +}
  4 +
src/spec/mocks.ts
@@ -193,6 +193,17 @@ export var mocks: any = { @@ -193,6 +193,17 @@ export var mocks: any = {
193 currentUser: () => { return user; } 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 $translate: { 207 $translate: {
197 use: (lang?: string) => { 208 use: (lang?: string) => {
198 return lang ? Promise.resolve(lang) : "en"; 209 return lang ? Promise.resolve(lang) : "en";
themes/angular-participa-consulta/README.md 0 → 100644
@@ -0,0 +1,10 @@ @@ -0,0 +1,10 @@
  1 +# Angular Participa Consulta Theme
  2 +
  3 +
  4 +## Getting started
  5 +
  6 +Run these commands to set the proper theme and skin
  7 +
  8 +`npm config set angular-theme:theme angular-participa-consulta`
  9 +
  10 +`npm config set angular-theme:skin skin-yellow`
themes/angular-participa-consulta/app/layout/scss/skins/_yellow.scss 0 → 100644
@@ -0,0 +1,64 @@ @@ -0,0 +1,64 @@
  1 +.skin-yellow {
  2 + @extend %skin-base;
  3 +
  4 + .notifications-list .item-footer {
  5 + background: #DAE1C4;
  6 + color: #4F9CAC;
  7 + }
  8 +
  9 + .navbar-nav .open > a,
  10 + .navbar-nav .open > a:hover,
  11 + .navbar-nav .open > a:focus {
  12 + background-color: $selected-color;
  13 + color: #000;
  14 + }
  15 +
  16 + .nav .open > a,
  17 + .nav .open > a:hover,
  18 + .nav .open > a:focus {
  19 + border: none;
  20 + }
  21 +
  22 + .dropdown-menu {
  23 + li > a:hover {
  24 + color: #555;
  25 + background-color: #F7F7F7;
  26 + }
  27 +
  28 + .active > a,
  29 + .active > a:hover,
  30 + .active > a:focus {
  31 + color: #000;
  32 + background-color: #CCC;
  33 + }
  34 + }
  35 +
  36 + .nav .caret {
  37 + border-bottom-color: #fff !important;
  38 + border-top-color: #fff !important;
  39 + }
  40 +
  41 + .nav .open .caret {
  42 + border-bottom-color: #000 !important;
  43 + border-top-color: #000 !important;
  44 + }
  45 +
  46 + .navbar-inverse .navbar-toggle {
  47 + border-color: #D49F18;
  48 + }
  49 +
  50 + .container-fluid .navbar-header .navbar-toggle {
  51 + &:hover, &:focus {
  52 + background-color: #f5b025;
  53 + }
  54 + }
  55 +
  56 + .navbar {
  57 + .navbar-nav .btn-nav {
  58 + &:hover {
  59 + background-color: $selected-color;
  60 + }
  61 + }
  62 + }
  63 +
  64 +}
themes/angular-participa-consulta/app/navbar.scss
1 -.skin-yellow {  
2 - .navbar-inverse .navbar-toggle {  
3 - border-color: #D49F18;  
4 - }  
5 -  
6 - .container-fluid .navbar-header .navbar-toggle {  
7 - &:hover, &:focus {  
8 - background-color: #f5b025;  
9 - }  
10 - }  
11 -}  
12 -  
13 .navbar { 1 .navbar {
14 min-height: 123px; 2 min-height: 123px;
15 background-color: #f9c404; 3 background-color: #f9c404;
themes/angular-participa-consulta/app/participa-consulta.scss
@@ -21,53 +21,6 @@ $selected-color: #f6c445; @@ -21,53 +21,6 @@ $selected-color: #f6c445;
21 src: url('../assets/fonts/participa-consulta/Ubuntu-RI.ttf'); 21 src: url('../assets/fonts/participa-consulta/Ubuntu-RI.ttf');
22 } 22 }
23 23
24 -.skin-yellow {  
25 - @extend %skin-base;  
26 -  
27 - .notifications-list .item-footer {  
28 - background: #DAE1C4;  
29 - color: #4F9CAC;  
30 - }  
31 -  
32 - .navbar-nav .open > a,  
33 - .navbar-nav .open > a:hover,  
34 - .navbar-nav .open > a:focus {  
35 - background-color: $selected-color;  
36 - color: #000;  
37 - }  
38 -  
39 - .nav .open > a,  
40 - .nav .open > a:hover,  
41 - .nav .open > a:focus {  
42 - border: none;  
43 - }  
44 -  
45 - .dropdown-menu {  
46 - li > a:hover {  
47 - color: #555;  
48 - background-color: #F7F7F7;  
49 - }  
50 -  
51 - .active > a,  
52 - .active > a:hover,  
53 - .active > a:focus {  
54 - color: #000;  
55 - background-color: #CCC;  
56 - }  
57 - }  
58 -  
59 - .nav .caret {  
60 - border-bottom-color: #fff !important;  
61 - border-top-color: #fff !important;  
62 - }  
63 -  
64 - .nav .open .caret {  
65 - border-bottom-color: #000 !important;  
66 - border-top-color: #000 !important;  
67 - }  
68 -  
69 -}  
70 -  
71 .profile-header, .profile-footer{ 24 .profile-header, .profile-footer{
72 text-align: center; 25 text-align: center;
73 } 26 }