pax_global_header 0000666 0000000 0000000 00000000064 12747676640 0014535 g ustar 00root root 0000000 0000000 52 comment=d06a730ad1cb76919f1fa7b2a824af56b5e87939
angular-theme.git/ 0000775 0000000 0000000 00000000000 12747676640 0014414 5 ustar 00root root 0000000 0000000 angular-theme.git/.bowerrc 0000664 0000000 0000000 00000000046 12747676640 0016060 0 ustar 00root root 0000000 0000000 {
"directory": "bower_components"
}
angular-theme.git/.editorconfig 0000664 0000000 0000000 00000000326 12747676640 0017072 0 ustar 00root root 0000000 0000000 # http://editorconfig.org
root = true
[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.md]
trim_trailing_whitespace = false
angular-theme.git/.eslintrc 0000664 0000000 0000000 00000000311 12747676640 0016233 0 ustar 00root root 0000000 0000000 {
"extends": "eslint:recommended",
"plugins": ["angular"],
"env": {
"browser": true,
"jasmine": true
},
"globals": {
"angular": true,
"module": true,
"inject": true
}
}
angular-theme.git/.gitignore 0000664 0000000 0000000 00000000315 12747676640 0016403 0 ustar 00root root 0000000 0000000 node_modules/
bower_components/
coverage/
docs/
dist/
.sass-cache/
.idea/
.tmp/
.vscode/
src/noosfero.js*
src/commons.js*
src/noosfero-specs.js*
typings
npm-debug.log
src/vendor.bundle.js*
.vagrant/
*.sw*
angular-theme.git/.yo-rc.json 0000664 0000000 0000000 00000003074 12747676640 0016422 0 ustar 00root root 0000000 0000000 {
"generator-gulp-angular": {
"version": "1.0.2",
"props": {
"angularVersion": "~1.4.2",
"angularModules": [
{
"key": "animate",
"module": "ngAnimate"
},
{
"key": "cookies",
"module": "ngCookies"
},
{
"key": "touch",
"module": "ngTouch"
},
{
"key": "sanitize",
"module": "ngSanitize"
},
{
"key": "messages",
"module": "ngMessages"
},
{
"key": "aria",
"module": "ngAria"
}
],
"jQuery": {
"key": "jqLite"
},
"resource": {
"key": "angular-resource",
"module": "ngResource"
},
"router": {
"key": "angular-route",
"module": "ngRoute"
},
"ui": {
"key": "bootstrap",
"module": null
},
"bootstrapComponents": {
"key": "ui-bootstrap",
"module": "ui.bootstrap"
},
"cssPreprocessor": {
"key": "node-sass",
"extension": "scss"
},
"jsPreprocessor": {
"key": "noJsPrepro",
"extension": "js",
"srcExtension": "js"
},
"htmlPreprocessor": {
"key": "noHtmlPrepro",
"extension": "html"
},
"foundationComponents": {
"name": null,
"version": null,
"key": null,
"module": null
},
"paths": {
"src": "src",
"dist": "dist",
"e2e": "e2e",
"tmp": ".tmp"
}
}
}
} angular-theme.git/README.md 0000664 0000000 0000000 00000006556 12747676640 0015707 0 ustar 00root root 0000000 0000000 # Angular Theme
The Noosfero theme that uses the API to create a totally new client-side frontend.
## Getting started
### If you use Vagrant
Use our [VirtualBox](https://atlas.hashicorp.com/paulohtfs/boxes/noosfero-dev) with everything setup.
Run:
```
vagrant up
vagrant ssh
```
This box provides Noosfero and the Angular base theme repositories.
We've also set up vim and tmux to make the work easier.
### How to Install
1. Install [Node.js](https://nodejs.org/) and [npm](https://www.npmjs.com/)
1. Install [Bower](http://bower.io/): `npm install -g bower`
1. Install [Gulp](http://gulpjs.com/): `npm install -g gulp`
1. Install Node.js dependencies: `npm install`
1. Install bower dependencies: `bower install`
1. Build the project: `npm run build`
1. Build multiple themes: `npm run build-all`
1. Run project tests: `npm run test`
### How to Use
Copy the desired theme from the `dist` folder into
noosfero `public/design/themes`.
## Project Structure
The folder structure of this project was sorted by feature.
See some important folders bellow:
- Directives for blocks: `src/app/layout/blocks`
- Directives for articles: `src/app/article`
- Directives for activities: `src/app/profile/activities`
- Service to connect with Noosfero API: `src/lib/ng-noosfero-api`
- Content viewer component: `src/app/article/content-viewer`
- Profile component: `src/app/profile`
- Profile Info component: `src/app/profile/info`
## Change theme
1. Create the theme folder inside themes
1. Configure application to use the new theme, e.g.:
`npm config set angular-theme:theme custom-theme`
1. Create an app folder inside custom-theme and add your custom scss files
1. Put the templates that you want to override in the same structure from the main application source, e.g.:
`src/app/profile/profile.html` will be overriden by `themes/custom-theme/app/profile/profile.html`
## Change skin
- Create an any scss file into: `app/layout/scss/skins/`
> **Suggestion:** Create a `sass` file partial. Something like: **`_mycustom.scss`**.
- Extend your skin css class from `%skin-base` scss placeholder selector. Something like this:
> **Suggestion:** Use the prefix **`skin-`** to the css class
```sass
.skin-mycustom {
@extend %skin-base
}
```
- Configure application to use the new theme, e.g.:
`npm config set angular-theme:skin skin-mycustom`
OR add the default skin property to a specific `package.json` file (ONLY PERFORM A BUILD), like this:
```json
"config": {
"skin": "skin-yellow"
}
```
**N.B.**
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.
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`.
Example: _mycustom.
- Start the application with `npm start` scripts or make a build
> **PS:** If the configured skin is invalid, an error message is showed in the terminal.
## Development environment
## Known Issues
### Message Translation: angular-i18n
- Plural Interpolation only working when current language is En (English)
`Plural Function not found for locale`
For some reason the messageformat installed on bower_component directory was an older version. Removing the bower_components directory
and runing `bower install` solved the problem
angular-theme.git/Vagrantfile 0000664 0000000 0000000 00000001414 12747676640 0016601 0 ustar 00root root 0000000 0000000 #-*- mode: ruby -*-
# vi: set ft=ruby :
# This will config you local machine
# If you having problem to up check out the README.md
Vagrant.configure(2) do |config|
config.vm.define "noosfero-dev"
# This box has already
# - Ruby on Rails 4
# - NVM with NodeJS v5.9.0
config.vm.box = "paulohtfs/noosfero-dev"
# Network configurations
# Check if your host port is available
config.vm.network "forwarded_port", guest: 3000, host: 3000
config.vm.network "private_network", ip: "10.0.0.15"
# Shared folder
config.vm.synced_folder '.', '/vagrant', disabled: true
config.vm.synced_folder ".", "/home/vagrant/angular-theme"
# Change according to you hardware
config.vm.provider "virtualbox" do |vm|
vm.memory = 512;
vm.cpus = 1;
end
end
angular-theme.git/bower.json 0000664 0000000 0000000 00000004512 12747676640 0016427 0 ustar 00root root 0000000 0000000 {
"name": "angular",
"version": "0.0.0",
"dependencies": {
"angular-animate": "~1.5.0",
"angular-cookies": "~1.5.0",
"angular-touch": "~1.5.0",
"angular-sanitize": "~1.5.0",
"angular-messages": "~1.5.0",
"angular-aria": "~1.5.0",
"restangular": "~1.5.2",
"angular-ui-router": "~0.2.18",
"bootstrap-sass": "~3.3.6",
"angular-bootstrap": "~1.1.0",
"malarkey": "yuanqing/malarkey#~1.3.1",
"angular-toastr": "~1.7.0",
"moment": "~2.10.6",
"animate.css": "~3.4.0",
"angular": "~1.5.0",
"font-awesome": "fontawesome#~4.5.0",
"ngstorage": "~0.3.10",
"bootswatch": "~3.3.6",
"angular-moment": "~1.0.0-beta.4",
"lodash": "3.10.1",
"angular-filter": "~0.5.8",
"angular-deckgrid": "~0.5.0",
"angular-timeline": "~1.6.2",
"angular-scroll": "~1.0.0",
"ngSweetAlert": "angular-sweetalert#~1.1.0",
"angular-mocks": "^1.5.0",
"angular-translate": "^2.10.0",
"angular-translate-loader-static-files": "^2.10.0",
"angular-translate-handler-log": "^2.10.0",
"angular-dynamic-locale": "^0.1.30",
"angular-i18n": "^1.5.0",
"angular-load": "^0.4.1",
"angular-translate-interpolation-messageformat": "^2.10.0",
"angular-bind-html-compile": "^1.2.1",
"angular-click-outside": "^2.7.1",
"ng-ckeditor": "^0.2.1",
"angular-tag-cloud": "^0.3.0",
"angular-ui-switch": "^0.1.1",
"angular-password": "^1.0.1",
"ng-file-upload": "^12.0.4",
"ng-img-crop": "^0.3.2"
},
"devDependencies": {
"angular-mocks": "~1.5.0"
},
"overrides": {
"ng-file-upload": {
"main": [
"ng-file-upload-all.js"
]
},
"ng-ckeditor": {
"main": [
"ng-ckeditor.js",
"libs/ckeditor/ckeditor.js"
]
},
"bootstrap-sass": {
"main": [
"assets/stylesheets/_bootstrap.scss",
"assets/fonts/bootstrap/glyphicons-halflings-regular.eot",
"assets/fonts/bootstrap/glyphicons-halflings-regular.svg",
"assets/fonts/bootstrap/glyphicons-halflings-regular.ttf",
"assets/fonts/bootstrap/glyphicons-halflings-regular.woff",
"assets/fonts/bootstrap/glyphicons-halflings-regular.woff2"
]
},
"font-awesome": {
"main": [
"scss/font-awesome.scss",
"fonts/*"
]
}
},
"resolutions": {
"angular": "~1.5.0"
}
}
angular-theme.git/dev-scripts/ 0000775 0000000 0000000 00000000000 12747676640 0016657 5 ustar 00root root 0000000 0000000 angular-theme.git/dev-scripts/fix-jqlite.ts 0000664 0000000 0000000 00000000472 12747676640 0021306 0 ustar 00root root 0000000 0000000 let replace = require("replace");
import * as path from "path";
let wrong_jqlite_d_ts_file = path.join(__dirname, "../node_modules/ng-forward/cjs/util/jqlite-extensions.d.ts");
replace({
regex: /import JQuery from \".\/\";/,
replacement: "",
paths: [wrong_jqlite_d_ts_file],
sillent: false
});
angular-theme.git/dev-scripts/generate-index-modules.ts 0000664 0000000 0000000 00000002053 12747676640 0023574 0 ustar 00root root 0000000 0000000 import * as glob from "glob";
import * as path from "path";
import * as fs from "fs";
let directories = glob.sync("./src/app/**/**/");
// maps to absolute path
directories = directories.map((directory: string) => {
return path.resolve(__dirname, "..", directory);
});
// iterate to generate the index folders
directories.forEach((directory: string) => {
// skips the app directory
if (!/\/app$/.test(directory)) {
let current_files = glob.sync("./*.ts", { nodir: true, cwd: directory, ignore: ['./index.ts', './*.spec.ts'] });
console.log("DIRECTORY: ", directory);
console.log("FILES: ", current_files);
let indexPath = path.join(directory, "index.ts");
let index_ts_content: string = "/* Module Index Entry - generated using the script npm run generate-index */\n";
let exports_content = current_files.map((file) => {
return `export * from "./${path.basename(file, ".ts")}";\n`;
});
fs.writeFileSync(indexPath, index_ts_content + exports_content.join(""));
}
});
angular-theme.git/dev-scripts/remapCoverage.js 0000664 0000000 0000000 00000002751 12747676640 0022002 0 ustar 00root root 0000000 0000000 "use strict";
var path = require("path");
var fs = require("fs");
var remapIstanbul = require("remap-istanbul");
var coveragePath = path.join(__dirname, "..", "coverage");
console.log("COVERAGE PATH:", coveragePath);
fs.readdir(coveragePath, function (err, directories) {
if (err) {
console.error(err.message);
throw err;
}
directories.map(function (file) {
return path.join(coveragePath, file);
}).forEach(function (coverageFolder) {
var coverageFile = path.join(coverageFolder, "coverage-final.json");
var replace = require("replace");
var absoluteProjectPath = path.join(__dirname, "../");
var loadCoverage = require('remap-istanbul/lib/loadCoverage');
var remap = require('remap-istanbul/lib/remap');
var writeReport = require('remap-istanbul/lib/writeReport');
var collector = remap(loadCoverage(coverageFile), {});
var Store = require("istanbul").Store;
var store = Store.create("fslookup");
store.get = function (key) {
var pathNormalized = key.replace("src/webpack:/", "");
pathNormalized = pathNormalized.replace(/\.ts\?(\w+)/, ".ts");
return fs.readFileSync(pathNormalized, 'utf8');
};
writeReport(collector, 'html', coverageFolder, store);
writeReport(collector, 'json', path.join(coverageFolder, 'coverage-final-remaped.json'), store);
});
});
//# sourceMappingURL=remapCoverage.js.map angular-theme.git/dev-scripts/remapCoverage.js.map 0000664 0000000 0000000 00000003130 12747676640 0022546 0 ustar 00root root 0000000 0000000 {"version":3,"file":"remapCoverage.js","sourceRoot":"","sources":["remapCoverage.ts"],"names":[],"mappings":";AAkBA,IAAY,IAAI,WAAM,MAAM,CAAC,CAAA;AAC7B,IAAY,EAAE,WAAM,IAAI,CAAC,CAAA;AAEzB,IAAI,aAAa,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAAC;AAG9C,IAAI,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,EAAE,UAAU,CAAC,CAAC;AAM1D,OAAO,CAAC,GAAG,CAAC,gBAAgB,EAAE,YAAY,CAAC,CAAC;AAE5C,EAAE,CAAC,OAAO,CAAC,YAAY,EAAE,UAAC,GAAG,EAAE,WAAW;IACtC,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QACN,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAC3B,MAAM,GAAG,CAAC;IACd,CAAC;IAED,WAAW,CAAC,GAAG,CAAC,UAAC,IAAI;QACjB,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,CAAC;IACzC,CAAC,CAAC,CAAC,OAAO,CAAC,UAAC,cAAc;QAEtB,IAAI,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,qBAAqB,CAAC,CAAC;QAEpE,IAAI,OAAO,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;QAEjC,IAAI,mBAAmB,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;QAwBtD,IAAI,YAAY,GAAG,OAAO,CAAC,iCAAiC,CAAC,CAAC;QAC9D,IAAI,KAAK,GAAG,OAAO,CAAC,0BAA0B,CAAC,CAAC;QAChD,IAAI,WAAW,GAAG,OAAO,CAAC,gCAAgC,CAAC,CAAC;QAE5D,IAAI,SAAS,GAAG,KAAK,CAAC,YAAY,CAAC,YAAY,CAAC,EAAE,EAYjD,CAAC,CAAC;QAEH,IAAI,KAAK,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC,KAAK,CAAC;QACtC,IAAI,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;QACrC,KAAK,CAAC,GAAG,GAAG,UAAS,GAAG;YACpB,IAAI,cAAc,GAAG,GAAG,CAAC,OAAO,CAAC,eAAe,EAAE,EAAE,CAAC,CAAC;YACtD,cAAc,GAAG,cAAc,CAAC,OAAO,CAAC,aAAa,EAAE,KAAK,CAAC,CAAC;YAC9D,MAAM,CAAC,EAAE,CAAC,YAAY,CAAC,cAAc,EAAE,MAAM,CAAC,CAAC;QACnD,CAAC,CAAA;QACD,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,cAAc,EAAE,KAAK,CAAC,CAAC;QACtD,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,6BAA6B,CAAC,EAAE,KAAK,CAAC,CAAC;IACpG,CAAC,CAAC,CAAC;AAEP,CAAC,CAAC,CAAC"} angular-theme.git/dev-scripts/remapCoverage.ts 0000664 0000000 0000000 00000007343 12747676640 0022016 0 ustar 00root root 0000000 0000000 /**
* @script remap-coverage.ts
*
* Esse script serve para transformar as informações de cobertura geradas pelo karma-coverage
* e que originalmente é construída apontando para os arquivos javascript (já que os testes são executados em javascript)
* para a informação de cobertura apontando para os arquivos Typescript, utilizando os source maps gerados pelo compilador
* typescript
* @author: Abner Oliveira
*
* Examplo de uso:
*
* Na linha de comando, na pasta raiz do projeto, digite:
*
* ts-node dev-scripts/remap-coverage.ts
*
* Observação: O karma já deve ter sido executado antes, e a pasta de coverage deve ser "./coverage"
*/
import * as path from "path";
import * as fs from "fs";
let remapIstanbul = require("remap-istanbul");
// pasta onde os arquivos do coverage são gerados
let coveragePath = path.join(__dirname, "..", "coverage");
// o pré-processador "coverage" do runner de tests "karma" gera uma pasta
// de coverage para cada browser em que os testes foram executados
// iteraremos arqui então entre essas pastas para realizar o remap de cada uma
console.log("COVERAGE PATH:", coveragePath);
// lendo o diretório coveragePath
fs.readdir(coveragePath, (err, directories) => {
if (err) {
console.error(err.message);
throw err;
}
// para cada diretório na pasta coveragePath faz map transformando o path para o caminho absoluto
directories.map((file) => {
return path.join(coveragePath, file);
}).forEach((coverageFolder) => {
let coverageFile = path.join(coverageFolder, "coverage-final.json");
let replace = require("replace");
let absoluteProjectPath = path.join(__dirname, "../");
// replace({
// regex: absoluteProjectPath,
// replacement: "",
// paths: [coverageFile],
// sillent: true
// });
// para cada pasta executa o remap do coverage que está apontando para os arquivos js
// para apontar para os arquivos Typecript
// gerando dois reports: JSON e HTML
// remapIstanbul(coverageFile,
// {
// "exclude":
// "json": path.join(coverageFolder, "coverage-final-remaped.json")
// });
// replace({
// regex: "src/webpack:/",
// replacement: "",
// paths: [coverageFile],
// sillent: true
// });
let loadCoverage = require('remap-istanbul/lib/loadCoverage');
let remap = require('remap-istanbul/lib/remap');
let writeReport = require('remap-istanbul/lib/writeReport');
let collector = remap(loadCoverage(coverageFile), {
/*exclude: 'Reflect',
readFile: function(filePath): any {
let pathNormalized = filePath.replace("webpack:///./src/", "");
pathNormalized = pathNormalized.replace(/\.ts\?(\w+)"/, ".ts\"");
console.log("FILE PATH: ", pathNormalized);
if (!fs.existsSync(pathNormalized)) {
console.warn(new Error('Could not find file: "' + pathNormalized + '"'));
return '';
}
return fs.readFileSync(pathNormalized);
}*/
});
let Store = require("istanbul").Store;
let store = Store.create("fslookup");
store.get = function(key) {
let pathNormalized = key.replace("src/webpack:/", "");
pathNormalized = pathNormalized.replace(/\.ts\?(\w+)/, ".ts");
return fs.readFileSync(pathNormalized, 'utf8');
}
writeReport(collector, 'html', coverageFolder, store);
writeReport(collector, 'json', path.join(coverageFolder, 'coverage-final-remaped.json'), store);
});
});
angular-theme.git/dev-scripts/tsconfig.json 0000664 0000000 0000000 00000000375 12747676640 0021373 0 ustar 00root root 0000000 0000000 {
"compilerOptions": {
"module": "commonjs",
"target": "es5",
"noImplicitAny": false,
"sourceMap": true
},
"exclude": [
"node_modules",
"typings/browser",
"typings/browser.d.ts"
]
} angular-theme.git/dev-scripts/typings.json 0000664 0000000 0000000 00000000652 12747676640 0021252 0 ustar 00root root 0000000 0000000 {
"dependencies": {},
"devDependencies": {},
"ambientDependencies": {
"glob": "github:DefinitelyTyped/DefinitelyTyped/glob/glob.d.ts#a14d724826174d1669d4df04c80f4838b7e71fdf",
"minimatch": "github:DefinitelyTyped/DefinitelyTyped/minimatch/minimatch.d.ts#a3900b896f7b3361b79f9b503224777619907d53",
"node": "github:DefinitelyTyped/DefinitelyTyped/node/node.d.ts#48c1e3c1d6baefa4f1a126f188c27c4fefd36bff"
}
}
angular-theme.git/e2e/ 0000775 0000000 0000000 00000000000 12747676640 0015067 5 ustar 00root root 0000000 0000000 angular-theme.git/e2e/.eslintrc 0000664 0000000 0000000 00000000164 12747676640 0016714 0 ustar 00root root 0000000 0000000 {
"globals": {
"browser": false,
"element": false,
"by": false,
"$": false,
"$$": false
}
}
angular-theme.git/e2e/main.po.js 0000664 0000000 0000000 00000000765 12747676640 0016776 0 ustar 00root root 0000000 0000000 /**
* This file uses the Page Object pattern to define the main page for tests
* https://docs.google.com/presentation/d/1B6manhG0zEXkC-H-tPo2vwU06JhL8w9-XCF9oehXzAQ
*/
'use strict';
var MainPage = function() {
this.jumbEl = element(by.css('.jumbotron'));
this.h1El = this.jumbEl.element(by.css('h1'));
this.imgEl = this.jumbEl.element(by.css('img'));
this.thumbnailEls = element(by.css('body')).all(by.repeater('awesomeThing in main.awesomeThings'));
};
module.exports = new MainPage();
angular-theme.git/e2e/main.spec.js 0000664 0000000 0000000 00000001074 12747676640 0017304 0 ustar 00root root 0000000 0000000 'use strict';
describe('The main view', function () {
var page;
beforeEach(function () {
browser.get('/index.html');
page = require('./main.po');
});
it('should include jumbotron with correct data', function() {
expect(page.h1El.getText()).toBe('\'Allo, \'Allo!');
expect(page.imgEl.getAttribute('src')).toMatch(/assets\/images\/yeoman.png$/);
expect(page.imgEl.getAttribute('alt')).toBe('I\'m Yeoman');
});
it('should list more than 5 awesome things', function () {
expect(page.thumbnailEls.count()).toBeGreaterThan(5);
});
});
angular-theme.git/gulp/ 0000775 0000000 0000000 00000000000 12747676640 0015363 5 ustar 00root root 0000000 0000000 angular-theme.git/gulp/.eslintrc 0000664 0000000 0000000 00000000044 12747676640 0017205 0 ustar 00root root 0000000 0000000 {
"env": {
"node": true
}
}
angular-theme.git/gulp/build.js 0000664 0000000 0000000 00000013731 12747676640 0017025 0 ustar 00root root 0000000 0000000 'use strict';
var path = require('path');
var gulp = require('gulp');
var rename = require('gulp-rename');
var insert = require('gulp-insert');
var merge = require('merge-stream');
var conf = require('./conf');
var languages = require('./languages');
var themeName = conf.paths.theme.replace('-', ' ');
themeName = themeName.charAt(0).toUpperCase() + themeName.slice(1);
var noosferoThemePrefix = path.join("/designs/themes/", conf.paths.theme, '/');
var $ = require('gulp-load-plugins')({
pattern: ['gulp-*', 'main-bower-files', 'uglify-save-license', 'del']
});
gulp.task('partials', function () {
var merged = merge();
['app', conf.paths.plugins].forEach(function(partialPath) {
var srcPaths = [path.join(conf.paths.tmp, '/serve/app/**/*.html')];
conf.paths.allSources.forEach(function(src) {
srcPaths.push(path.join(src, partialPath, '/**/*.html'));
});
merged.add(gulp.src(srcPaths)
.pipe($.minifyHtml({
empty: true,
spare: true,
quotes: true
}))
.pipe($.angularTemplatecache('templateCacheHtml-'+partialPath+'.js', {
module: 'noosfero.templates.' + partialPath,
standalone: true,
root: partialPath
}))
.pipe(gulp.dest(conf.paths.tmp + '/partials/')));
});
return merged;
});
gulp.task('html', ['inject', 'partials'], function () {
var partialsInjectFile = gulp.src([
path.join(conf.paths.tmp, '/partials/templateCacheHtml-app.js'),
path.join(conf.paths.tmp, '/partials/templateCacheHtml-plugins.js')], { read: false });
var partialsInjectOptions = {
starttag: '',
ignorePath: path.join(conf.paths.tmp, '/partials'),
addRootSlash: false
};
var htmlFilter = $.filter('*.html', { restore: true });
var jsFilter = $.filter('**/*.js', { restore: true });
var cssFilter = $.filter('**/*.css', { restore: true });
var assets;
return gulp.src(path.join(conf.paths.tmp, '/serve/*.html'))
.pipe($.inject(partialsInjectFile, partialsInjectOptions))
.pipe(assets = $.useref.assets())
.pipe($.rev())
.pipe(jsFilter)
.pipe($.replace('assets/images/', noosferoThemePrefix + 'assets/images/'))
.pipe($.replace('/languages/', noosferoThemePrefix + 'languages/'))
.pipe($.replace('bower_components/angular-i18n/', noosferoThemePrefix + 'locale/angular-i18n/'))
.pipe($.replace('bower_components/moment/', noosferoThemePrefix + 'locale/moment/'))
.pipe($.replace('bower_components/messageformat/', noosferoThemePrefix + 'locale/messageformat/'))
.pipe($.sourcemaps.init())
.pipe($.ngAnnotate())
// TODO - check how to make uglify work with ngforward
.pipe($.uglify({ preserveComments: $.uglifySaveLicense, mangle: false, output: { beautify: false} })).on('error', conf.errorHandler('Uglify'))
.pipe($.sourcemaps.write('maps'))
.pipe(jsFilter.restore)
.pipe(cssFilter)
.pipe($.sourcemaps.init())
.pipe($.replace('../../bower_components/bootstrap-sass/assets/fonts/bootstrap/', '../fonts/'))
.pipe($.replace('../../bower_components/font-awesome/fonts/', '../fonts/'))
.pipe($.minifyCss({ processImport: false }))
.pipe($.sourcemaps.write('maps'))
.pipe(cssFilter.restore)
.pipe(assets.restore())
.pipe($.useref())
.pipe($.revReplace({prefix: noosferoThemePrefix}))
.pipe(htmlFilter)
.pipe($.replace('/bower_components/ng-ckeditor/libs/ckeditor/', noosferoThemePrefix + 'ng-ckeditor/libs/ckeditor/'))
.pipe($.minifyHtml({
empty: true,
spare: true,
quotes: true,
conditionals: true
}))
.pipe(htmlFilter.restore)
.pipe(gulp.dest(path.join(conf.paths.dist, '/')))
.pipe($.size({ title: path.join(conf.paths.dist, '/'), showFiles: true }));
});
// Only applies for fonts from bower dependencies
// Custom fonts are handled by the "other" task
gulp.task('fonts', function () {
return gulp.src($.mainBowerFiles())
.pipe($.filter('**/*.{eot,svg,ttf,woff,woff2}'))
.pipe($.flatten())
.pipe(gulp.dest(path.join(conf.paths.dist, '/fonts/')));
});
gulp.task('ckeditor', function () {
conf.wiredep.exclude.push(/bower_components\/ng-ckeditor\/libs\/ckeditor/); // exclude ckeditor from build to improve performance
return gulp.src(['bower_components/ng-ckeditor/**/*']).pipe(gulp.dest(path.join(conf.paths.dist, '/ng-ckeditor')));
});
gulp.task('locale', function () {
return gulp.src([
path.join("bower_components/angular-i18n", '*.js'),
path.join("bower_components/moment/locale", '*.js'),
path.join("bower_components/messageformat/locale", '*.js'),
], {base: 'bower_components/'})
.pipe(gulp.dest(path.join(conf.paths.dist, '/locale/')));
});
gulp.task('other', function () {
var fileFilter = $.filter(function (file) {
return file.stat.isFile();
});
var srcPaths = [path.join('!' + conf.paths.src, '/**/*.{map,ts,html,css,js,scss}')];
conf.paths.allSources.forEach(function(src) {
srcPaths.push(path.join(src, '/**/*'));
});
return gulp.src(srcPaths)
.pipe(fileFilter)
.pipe(gulp.dest(path.join(conf.paths.dist, '/')));
});
gulp.task('clean', function () {
return $.del(["dist", path.join(conf.paths.tmp, '/')]);
});
gulp.task('clean-docs', [], function() {
return $.del([path.join(conf.paths.docs, '/')]);
});
gulp.task('plugin-languages', ['locale'], function() {
return languages.pluginLanguages(conf.paths.dist);
});
gulp.task('noosfero', ['html'], function () {
var layouts = gulp.src('layouts/**/*')
.pipe(gulp.dest(path.join(conf.paths.dist, "layouts")));
var theme = gulp.src('theme.yml')
.pipe(insert.prepend('name: "' + themeName + '"\n'))
.pipe(gulp.dest(conf.paths.dist));
var index = gulp.src(path.join(conf.paths.dist, 'index.html'))
.pipe(rename('index.html.erb'))
.pipe(gulp.dest(conf.paths.dist));
return merge(layouts, theme, index);
});
gulp.task('inject-skin-build', ['html'], function () {
gulp.start('inject-skin');
});
gulp.task('build', ['ckeditor', 'html', 'fonts', 'other', 'locale', 'plugin-languages', 'noosfero', 'inject-skin-build']);
angular-theme.git/gulp/conf.js 0000664 0000000 0000000 00000007733 12747676640 0016660 0 ustar 00root root 0000000 0000000 /**
* This file contains the variables used in other gulp files
* which defines tasks
* By design, we only put there very generic config values
* which are used in several places to keep good readability
* of the tasks
*/
var argv = require('minimist')(process.argv.slice(2));
var gutil = require('gulp-util');
var path = require('path');
var fs = require('fs-extra');
/**
* The main paths of your project handle these with care
*/
exports.paths = {
src: 'src',
plugins: 'plugins',
dist: 'dist',
tmp: '.tmp',
e2e: 'e2e',
docs: 'docs',
themes: 'themes',
languages: 'languages'
};
exports.isBuild = function () {
if (!exports.building) {
exports.building = (argv._[0] == 'build' ? true : false);
}
return exports.building;
};
exports.isDefaultTheme = function (name) {
return /-default$/.test(name);
};
/**
* Check if theme folder exists on "themes" directory
*
* @param path The string relative path of the theme
*/
exports.themeExists = function (path) {
try {
fs.statSync(path);
} catch (e) {
throw new Error('The theme "'+exports.paths.theme+ ' on path "'+path+'" was not found');
}
};
/**
* Check if skin file exists on "{theme}/app/layout/skins" directory
*
* @param skin The skin name passed by arg to gulp task
*/
exports.skinExists = function (skin) {
var skinPath, prefixPath = '';
var skinFile = skin+'.scss';
if (/skin-/.test(skin)) {
skinFile = skin.replace('skin-','_')+'.scss';
}
if (exports.isDefaultTheme(exports.paths.theme)) {
prefixPath = exports.paths.src;
}else {
prefixPath = path.join(exports.paths.themes, exports.paths.theme);
}
skinPath = path.join(prefixPath, '/app/layout/scss/skins/', skinFile);
try {
fs.statSync(skinPath);
} catch(e) {
throw new Error('The skin file "'+skinPath+'" was not found');
}
var content = fs.readFileSync(skinPath, {encoding: 'utf8'});
if (content.search(skin) == -1) {
throw new Error('The skin css selector ".'+skin+'" was not found in "'+skinPath+'" file');
}else if (content.search('@extend %skin-base') == -1) {
throw new Error('The skin css selector ".'+skin+'" needs inherit from %skin-base sass placeholder');
}
};
exports.configTheme = function(theme) {
exports.paths.theme = theme || "angular-default";
var themePath = path.join(exports.paths.themes, exports.paths.theme);
exports.paths.allSources = [exports.paths.src, themePath];
exports.themeExists(themePath);
exports.paths.dist = path.join("dist", exports.paths.theme);
if(exports.isBuild() && !exports.isDefaultTheme(exports.paths.theme)){
try {
fs.statSync(path.join(themePath,'package.json'));
var themeData = fs.readJsonSync(path.join(themePath,'package.json'));
if(!themeData.config || !themeData.config.skin) {
throw new Error('The theme "'+exports.paths.theme+'" needs a default skin on their package.json file');
}
argv.skin = themeData.config.skin;
} catch (e) {
gutil.log(gutil.colors.yellow('[WARNING]','The package.json file was not found into theme:'), gutil.colors.cyan(exports.paths.theme));
}
}
if(argv.skin && argv.skin != 'skin-whbl') {
exports.skinExists(argv.skin);
exports.paths.skin = argv.skin;
}
gutil.log('Configuring theme', gutil.colors.green(exports.paths.theme.toUpperCase()));
}
exports.configTheme(argv.theme);
/**
* Wiredep is the lib which inject bower dependencies in your project
* Mainly used to inject script tags in the index.html but also used
* to inject css preprocessor deps and js files in karma
*/
exports.wiredep = {
exclude: [/jquery/, /\/bootstrap\.js$/, /\/bootstrap-sass\/.*\.js/, /\/bootstrap\.css/],
directory: 'bower_components'
};
/**
* Common implementation for an error handler of a Gulp plugin
*/
exports.errorHandler = function(title) {
'use strict';
return function(err) {
gutil.log(gutil.colors.red('[' + title + ']'), err.toString());
this.emit('end');
};
};
angular-theme.git/gulp/e2e-tests.js 0000664 0000000 0000000 00000002062 12747676640 0017534 0 ustar 00root root 0000000 0000000 'use strict';
var path = require('path');
var gulp = require('gulp');
var conf = require('./conf');
var browserSync = require('browser-sync');
var $ = require('gulp-load-plugins')();
// Downloads the selenium webdriver
gulp.task('webdriver-update', $.protractor.webdriver_update);
gulp.task('webdriver-standalone', $.protractor.webdriver_standalone);
function runProtractor (done) {
var params = process.argv;
var args = params.length > 3 ? [params[3], params[4]] : [];
gulp.src(path.join(conf.paths.e2e, '/**/*.js'))
.pipe($.protractor.protractor({
configFile: 'protractor.conf.js',
args: args
}))
.on('error', function (err) {
// Make sure failed tests cause gulp to exit non-zero
throw err;
})
.on('end', function () {
// Close browser sync server
browserSync.exit();
done();
});
}
gulp.task('protractor', ['protractor:src']);
gulp.task('protractor:src', ['serve:e2e', 'webdriver-update'], runProtractor);
gulp.task('protractor:dist', ['serve:e2e-dist', 'webdriver-update'], runProtractor);
angular-theme.git/gulp/inject.js 0000664 0000000 0000000 00000004556 12747676640 0017207 0 ustar 00root root 0000000 0000000 'use strict';
var path = require('path');
var gulp = require('gulp');
var conf = require('./conf');
var map = require('map-stream');
var transform = require('vinyl-transform');
var $ = require('gulp-load-plugins')();
var wiredep = require('wiredep').stream;
var _ = require('lodash');
var browserSync = require('browser-sync');
gulp.task('inject-reload', ['inject'], function() {
browserSync.reload();
});
gulp.task('inject', ['scripts', 'styles'], function () {
var injectStyles = gulp.src([
path.join(conf.paths.tmp, '/serve/app/**/*.css'),
path.join('!' + conf.paths.tmp, '/serve/app/vendor.css')
], { read: false });
var injectScripts = gulp.src([
path.join(conf.paths.src, '/app/**/*.module.js'),
path.join(conf.paths.src, '/app/**/*.js'),
path.join('!' + conf.paths.src, '/app/**/*.spec.js'),
path.join('!' + conf.paths.src, '/app/**/*.mock.js'),
])
.pipe($.angularFilesort()).on('error', conf.errorHandler('AngularFilesort'));
var injectOptions = {
ignorePath: [conf.paths.src, path.join(conf.paths.tmp, '/serve')],
addRootSlash: false
};
return gulp.src(path.join(conf.paths.src, '/*.html'))
.pipe($.inject(injectStyles, injectOptions))
.pipe($.inject(injectScripts, injectOptions))
.pipe(wiredep(_.extend({}, conf.wiredep)))
.pipe(gulp.dest(path.join(conf.paths.tmp, '/serve')));
});
/**
* Replace the default theme skin to a npm config
*
* Uses "vinyl-transform" + "map-stream" to open the
* js file and rewrite the source file into the same
* destination
*
* @see https://www.npmjs.com/package/vinyl-transform
* @see https://www.npmjs.com/package/map-stream
*/
gulp.task('inject-skin', function () {
if(conf.paths.skin) {
var jsPaths = {
src: path.join(conf.paths.src,'./noosfero.js'),
dest: conf.paths.src,
};
$.util.log('Configuring theme skin:', conf.paths.skin, '...');
var replaceSkin = transform(function(filename) {
return map(function(file, next) {
var contents = file.toString();
contents = contents.replace('skin-whbl', conf.paths.skin);
return next(null, contents);
});
});
if (conf.isBuild()) {
jsPaths.src = path.join(conf.paths.dist, 'scripts', 'app-*.js');
jsPaths.dest = path.join(conf.paths.dist, 'scripts');
}
gulp.src(jsPaths.src)
.pipe(replaceSkin)
.pipe(gulp.dest(jsPaths.dest));
}
});
angular-theme.git/gulp/languages.js 0000664 0000000 0000000 00000001615 12747676640 0017672 0 ustar 00root root 0000000 0000000 'use strict';
var path = require('path');
var gulp = require('gulp');
var merge = require('merge-stream');
var conf = require('./conf');
var mergeJson = require('gulp-merge-json');
var glob = require("glob");
exports.pluginLanguages = function(dest) {
var merged = merge();
glob(path.join(conf.paths.src, conf.paths.languages, "*.json"), function (er, files) {
files.forEach(function(file) {
merged.add(exports.pluginLanguage(file, dest));
});
});
return merged;
}
exports.pluginLanguage = function(file, dest) {
var language = file.split('/').pop().replace('\.json','');
return gulp.src(path.join(conf.paths.src, '**', conf.paths.languages, language+'.json'))
.pipe(mergeJson(path.join(conf.paths.languages, language+'.json')))
.pipe(gulp.dest(dest))
}
gulp.task('serve-languages', function() {
return exports.pluginLanguages(path.join(conf.paths.tmp, '/serve'));
});
angular-theme.git/gulp/scripts.js 0000664 0000000 0000000 00000000736 12747676640 0017416 0 ustar 00root root 0000000 0000000 'use strict';
var path = require('path');
var gulp = require('gulp');
var conf = require('./conf');
var browserSync = require('browser-sync');
var $ = require('gulp-load-plugins')();
gulp.task('scripts-reload', ['inject-skin'], function() {
return buildScripts()
.pipe(browserSync.stream());
});
gulp.task('scripts', function() {
return buildScripts();
});
function buildScripts() {
return gulp.src(path.join(conf.paths.src, '/**/*.js'))
.pipe($.size())
};
angular-theme.git/gulp/server.js 0000664 0000000 0000000 00000003717 12747676640 0017237 0 ustar 00root root 0000000 0000000 'use strict';
var path = require('path');
var gulp = require('gulp');
var conf = require('./conf');
var browserSync = require('browser-sync');
var browserSyncSpa = require('browser-sync-spa');
var util = require('util');
var proxyMiddleware = require('http-proxy-middleware');
function browserSyncInit(baseDir, browser) {
browser = browser === undefined ? 'default' : browser;
var routes = null;
if(baseDir === conf.paths.src || (util.isArray(baseDir) && baseDir.indexOf(conf.paths.src) !== -1)) {
routes = {
'/bower_components': 'bower_components'
};
}
var server = {
baseDir: baseDir,
routes: routes
};
server.middleware = [proxyMiddleware('http://localhost:3000/api', {changeOrigin:true}),
// proxyMiddleware('http://localhost:3000/myprofile', {changeOrigin:true}),
proxyMiddleware('http://localhost:3000/designs', {changeOrigin:true}),
proxyMiddleware('http://localhost:3000/image_uploads', {changeOrigin:true}),
proxyMiddleware('http://localhost:3000/account/logout', {changeOrigin:true}),
proxyMiddleware('http://localhost:3000/images', {changeOrigin:true})];
browserSync.instance = browserSync.init({
startPath: '/',
server: server,
port: 3001,
browser: browser
});
}
browserSync.use(browserSyncSpa({
selector: '[ng-app]'// Only needed for angular apps
}));
gulp.task('serve', ['serve-languages', 'watch'], function () {
var srcPaths = [path.join(conf.paths.tmp, '/serve')];
conf.paths.allSources.reverse().forEach(function(src) {
srcPaths.push(src);
});
browserSyncInit(srcPaths);
});
gulp.task('serve:dist', ['build'], function () {
browserSyncInit(conf.paths.dist);
});
gulp.task('serve:e2e', ['inject'], function () {
browserSyncInit([conf.paths.tmp + '/serve', conf.paths.src], []);
});
gulp.task('serve:e2e-dist', ['build'], function () {
browserSyncInit(conf.paths.dist, []);
});
angular-theme.git/gulp/styles.js 0000664 0000000 0000000 00000003202 12747676640 0017241 0 ustar 00root root 0000000 0000000 'use strict';
var path = require('path');
var gulp = require('gulp');
var conf = require('./conf');
var browserSync = require('browser-sync');
var $ = require('gulp-load-plugins')();
var wiredep = require('wiredep').stream;
var _ = require('lodash');
var importCss = require('gulp-import-css');
gulp.task('styles-reload', ['styles'], function() {
return buildStyles()
.pipe(browserSync.stream());
});
gulp.task('styles', function() {
return buildStyles();
});
var buildStyles = function() {
var sassOptions = {
style: 'expanded'
};
var srcPaths = [
path.join('!' + conf.paths.src, '/app/index.scss'),
path.join('!' + conf.paths.src, '/app/layout/scss/*.scss')
];
conf.paths.allSources.forEach(function(src) {
srcPaths.push(path.join(src, '/app/**/*.scss'));
srcPaths.push(path.join(src, conf.paths.plugins, '/**/*.scss'));
});
var injectFiles = gulp.src(srcPaths, { read: false });
var injectOptions = {
transform: function(filePath) {
filePath = filePath.replace(conf.paths.src + '/app/', '');
return '@import "' + filePath + '";';
},
starttag: '// injector',
endtag: '// endinjector',
addRootSlash: false
};
return gulp.src([
path.join(conf.paths.src, '/app/index.scss')
])
.pipe($.inject(injectFiles, injectOptions))
.pipe(wiredep(_.extend({}, conf.wiredep)))
.pipe($.sourcemaps.init())
.pipe($.sass(sassOptions)).on('error', conf.errorHandler('Sass'))
.pipe($.autoprefixer()).on('error', conf.errorHandler('Autoprefixer'))
.pipe($.sourcemaps.write())
.pipe(importCss())
.pipe(gulp.dest(path.join(conf.paths.tmp, '/serve/app/')));
};
angular-theme.git/gulp/unit-tests.js 0000664 0000000 0000000 00000002142 12747676640 0020037 0 ustar 00root root 0000000 0000000 'use strict';
var path = require('path');
var gulp = require('gulp');
var conf = require('./conf');
var karma = require('karma');
var pathSrcHtml = [
path.join(conf.paths.src, '/**/*.html')
];
var pathSrcJs = [
path.join(conf.paths.src, '/**/!(*.spec).js')
];
function runTests (singleRun, done) {
var reporters = ['progress'];
var preprocessors = {};
pathSrcHtml.forEach(function(path) {
preprocessors[path] = ['ng-html2js'];
});
if (singleRun) {
pathSrcJs.forEach(function(path) {
preprocessors[path] = ['coverage'];
});
reporters.push('coverage')
}
var localConfig = {
configFile: path.join(__dirname, '/../karma.conf.js'),
singleRun: singleRun,
autoWatch: !singleRun,
reporters: reporters,
preprocessors: preprocessors
};
var server = new karma.Server(localConfig, function(failCount) {
done(failCount ? new Error("Failed " + failCount + " tests.") : null);
})
server.start();
}
gulp.task('test', ['scripts'], function(done) {
runTests(true, done);
});
gulp.task('test:auto', ['watch'], function(done) {
runTests(false, done);
});
angular-theme.git/gulp/watch.js 0000664 0000000 0000000 00000002744 12747676640 0017036 0 ustar 00root root 0000000 0000000 'use strict';
var path = require('path');
var gulp = require('gulp');
var conf = require('./conf');
var languages = require('./languages');
var browserSync = require('browser-sync');
function isOnlyChange(event) {
return event.type === 'changed';
}
gulp.task('watch', ['inject'], function () {
gulp.watch([path.join(conf.paths.src, '/*.html'), 'bower.json'], ['inject-reload']);
var stylePaths = [path.join(conf.paths.src, conf.paths.plugins, '/**/*.scss')];
conf.paths.allSources.forEach(function(src) {
stylePaths.push(path.join(src, '/app/**/*.css'));
stylePaths.push(path.join(src, '/app/**/*.scss'));
});
gulp.watch(stylePaths, function(event) {
if(isOnlyChange(event)) {
gulp.start('styles-reload');
} else {
gulp.start('inject-reload');
}
});
gulp.watch(path.join(conf.paths.src, '/**/*.js'), function(event) {
if(isOnlyChange(event)) {
gulp.start('scripts-reload');
} else {
gulp.start('inject-reload');
}
});
gulp.watch(path.join(conf.paths.src, '**', conf.paths.languages, '*.json'), function(event) {
languages.pluginLanguage(event.path, path.join(conf.paths.tmp, '/serve'));
});
var watchPaths = [];
conf.paths.allSources.forEach(function(src) {
watchPaths.push(path.join(src, '/app/**/*.html'));
watchPaths.push(path.join(src, conf.paths.plugins, '/**/*.html'));
});
watchPaths.push(stylePaths);
gulp.watch(watchPaths, function(event) {
browserSync.reload(event.path);
});
});
angular-theme.git/gulpfile.js 0000664 0000000 0000000 00000003403 12747676640 0016561 0 ustar 00root root 0000000 0000000 /**
* Welcome to your gulpfile!
* The gulp tasks are splitted in several files in the gulp directory
* because putting all here was really too long
*/
'use strict';
var gulp = require('gulp');
var wrench = require('wrench');
/**
* This will load all js or coffee files in the gulp directory
* in order to load all gulp tasks
*/
wrench.readdirSyncRecursive('./gulp').filter(function(file) {
return (/\.(js|coffee)$/i).test(file);
}).map(function(file) {
require('./gulp/' + file);
});
/**
* Default task clean temporaries directories and launch the
* main optimization build task
*/
gulp.task('default', ['clean'], function () {
gulp.start('build');
});
gulp.task('ngdocs', ['clean-docs'], function () {
var gulpDocs = require('gulp-ngdocs');
var options = {
scripts: [
'bower_components/angular/angular.min.js',
'bower_components/angular/angular.min.js.map',
'bower_components/angular-animate/angular-animate.min.js',
'bower_components/angular-animate/angular-animate.min.js.map'
//'bower_components/angular/angular.js'
],
html5Mode: true,
startPage: '/',
title: "Noosfero Angular Theme Documentation",
//image: "path/to/my/image.png",
//imageLink: "http://my-domain.com",
titleLink: "/",
loadDefaults: {
angular: false,
angularAnimate: false
}
}
return gulpDocs.sections({
api: {
glob:[
//'src/**/*.js', '!src/noosfero.js', '!src/noosfero-specs.js'
//'src/noosfero.js'
'src/**/*.ts'
],//, '!src/**/*.spec.js'],
api: true,
title: 'API Documentation'
},
tutorial: {
glob: ['content/tutorial/*.ngdoc'],
title: 'Tutorial'
}
}).pipe(gulpDocs.process(options)).pipe(gulp.dest('./docs'));
});
angular-theme.git/karma-webpack.conf.js 0000664 0000000 0000000 00000006404 12747676640 0020407 0 ustar 00root root 0000000 0000000 /* global process, */
'use strict';
var path = require('path');
var conf = require('./gulp/conf');
var _ = require('lodash');
var wiredep = require('wiredep');
var pathSrcHtml = [
path.join(conf.paths.src, '/**/*.html')
];
function listFiles() {
var wiredepOptions = _.extend({}, conf.wiredep, {
dependencies: true,
devDependencies: true
});
var patterns = [].concat(wiredep(wiredepOptions).js)
.concat([
'./src/spec.ts'
]
)
.concat(pathSrcHtml);
var files = patterns.map(function (pattern) {
return {
pattern: pattern
};
});
files.push({
pattern: path.join(conf.paths.src, '/assets/**/*'),
included: false,
served: true,
watched: false
});
return files;
}
var webpackConfig = require("./webpack.config.js");
module.exports = function (config) {
var configuration = {
files: listFiles(),
singleRun: false,
autoWatch: true,
colors: true,
logLevel: config.LOG_INFO,
ngHtml2JsPreprocessor: {
stripPrefix: conf.paths.src + '/',
moduleName: 'angular'
},
frameworks: ['jasmine', 'phantomjs-shim'],//, 'angular-filesort'],
angularFilesort: {
whitelist: [path.join(conf.paths.src, '/**/!(*.html|*.spec|*.mock).js')]
},
browsers: ['PhantomJS'],
webpack: _.merge({
}, webpackConfig, {
devtool: 'inline-source-map'
}),
webpackServer: {
quite: true
},
plugins: [
'karma-chrome-launcher',
'karma-phantomjs-launcher',
'karma-angular-filesort',
'karma-webpack',
'karma-phantomjs-shim',
'karma-coverage',
'karma-jasmine',
'karma-spec-reporter',
'karma-ng-html2js-preprocessor',
'karma-sourcemap-loader'
],
coverageReporter: {
type: 'html',
dir: 'coverage/'
},
reporters: ['spec', "coverage"],
proxies: {
'/assets/': path.join('/base/', conf.paths.src, '/assets/')
}
};
// This is the default preprocessors configuration for a usage with Karma cli
// The coverage preprocessor is added in gulp/unit-test.js only for single tests
// It was not possible to do it there because karma doesn't let us now if we are
// running a single test or not
configuration.preprocessors = {
'src/**/*.ts': ['webpack','sourcemap']
};
pathSrcHtml.forEach(function (path) {
configuration.preprocessors[path] = ['ng-html2js'];
});
// This block is needed to execute Chrome on Travis
// If you ever plan to use Chrome and Travis, you can keep it
// If not, you can safely remove it
// https://github.com/karma-runner/karma/issues/1144#issuecomment-53633076
if (configuration.browsers[0] === 'Chrome' && process.env.TRAVIS) {
configuration.customLaunchers = {
'chrome-travis-ci': {
base: 'Chrome',
flags: ['--no-sandbox']
}
};
configuration.browsers = ['chrome-travis-ci'];
}
config.set(configuration);
};
angular-theme.git/karma.conf.js 0000664 0000000 0000000 00000012664 12747676640 0017002 0 ustar 00root root 0000000 0000000 /* global process, */
'use strict';
var path = require('path');
var conf = require('./gulp/conf');
var argv = require("yargs").argv;
var singleRun = (argv.singleRun !== undefined && argv.singleRun);
var coverage = (argv.coverage === undefined || argv.coverage);
if (argv.singleRun) {
singleRun = true;
}
var projectFiles = [
'./src/commons.js',
'./src/vendor.bundle.js',
'./src/noosfero.js',
'./src/noosfero-specs.js'
];
var karmaPlugins = [
'karma-chrome-launcher',
'karma-phantomjs-launcher',
'karma-angular-filesort',
'karma-phantomjs-shim',
'karma-jasmine',
'karma-spec-reporter',
'karma-ng-html2js-preprocessor',
'karma-sourcemap-loader',
'karma-coverage'
];
var karmaReporters = ['spec', 'coverage'];
// if (coverage) {
// karmaPlugins.push('karma-coverage');
// karmaReporters.push('coverage');
// }
var _ = require('lodash');
var wiredep = require('wiredep');
var pathSrcHtml = [
path.join('./src/**/*.html')
];
var glob = require("glob");
//var testFiles = glob.sync("./src/**/*.[sS]pec.ts");
function listFiles() {
var wiredepOptions = _.extend({}, conf.wiredep, {
dependencies: true,
devDependencies: true
});
var patterns = [].concat(wiredep(wiredepOptions).js)
.concat(projectFiles)
.concat(pathSrcHtml);
var files = patterns.map(function (pattern) {
return {
pattern: pattern
};
});
files.push({
pattern: path.join(conf.paths.src, '/assets/**/*'),
included: false,
served: true,
watched: false
});
// files.push({
// pattern: path.join(conf.paths.src, '/test.js.map'),
// included: false,
// served: true
// });
return files;
}
var webpackConfig = require("./webpack.config.js");
module.exports = function (config) {
var configuration = {
basePath: './',
files: listFiles(),
singleRun: singleRun,
autoWatch: true,
colors: true,
logLevel: config.LOG_INFO,
ngHtml2JsPreprocessor: {
stripPrefix: conf.paths.src + '/',
moduleName: 'templates'
},
frameworks: ['jasmine', 'phantomjs-shim'],//, 'angular-filesort'],
angularFilesort: {
whitelist: [path.join(conf.paths.src, '/**/!(*.html|*.spec|*.mock).js')]
},
browsers: ['PhantomJS'],
plugins: karmaPlugins,
reporters: karmaReporters,
proxies: {
'/assets/': path.join('/base/', conf.paths.src, '/assets/')
}
};
if(config.grep) {
configuration.client = { args: ['--grep', config.grep] };
}
if (coverage) {
/*configuration.webpack = {
module: {
loaders: [
{
test: /\.tsx?$/,
loader: 'ts-loader'
}
]
},
resolve: {
extensions: ['', '.webpack.js', '.web.js', '.ts', '.tsx', '.js'],
modulesDirectories: ['node_modules'],
root: path.resolve(__dirname)
}
};*/
/*configuration.webpack = _.merge({
}, webpackConfig, {
devtool: 'source-map'
}),
configuration.webpackServer = {
quite: true
};*/
// This is the default preprocessors configuration for a usage with Karma cli
// The coverage preprocessor is added in gulp/unit-test.js only for single tests
// It was not possible to do it there because karma doesn't let us now if we are
// running a single test or not
configuration.preprocessors = {
'src/noosfero.js': ['sourcemap', 'coverage'],
'src/**/*.ts': ['sourcemap']
};
configuration.coverageReporter = {
dir: 'coverage/',
reporters: [
{ type: 'html' },
{ type: 'json', file: 'coverage-final.json' },
{ type: 'text-summary' }
]
};
} else {
// This is the default preprocessors configuration for a usage with Karma cli
// The coverage preprocessor is added in gulp/unit-test.js only for single tests
// It was not possible to do it there because karma doesn't let us now if we are
// running a single test or not
configuration.preprocessors = {
'src/noosfero': ['coverage', 'sourcemap'],
'src/**/*.ts': ['sourcemap']
};
configuration.coverageReporter = {
dir: 'coverage/',
reporters: [
{ type: 'html' },
{ type: 'json', file: 'coverage-final.json' },
{ type: 'text-summary' }
]
};
}
pathSrcHtml.forEach(function (path) {
configuration.preprocessors[path] = ['ng-html2js'];
});
// This block is needed to execute Chrome on Travis
// If you ever plan to use Chrome and Travis, you can keep it
// If not, you can safely remove it
// https://github.com/karma-runner/karma/issues/1144#issuecomment-53633076
if (configuration.browsers[0] === 'Chrome' && process.env.TRAVIS) {
configuration.customLaunchers = {
'chrome-travis-ci': {
base: 'Chrome',
flags: ['--no-sandbox']
}
};
configuration.browsers = ['chrome-travis-ci'];
}
config.set(configuration);
};
angular-theme.git/layouts/ 0000775 0000000 0000000 00000000000 12747676640 0016114 5 ustar 00root root 0000000 0000000 angular-theme.git/layouts/angular-layout.html.erb 0000664 0000000 0000000 00000000326 12747676640 0022516 0 ustar 00root root 0000000 0000000 <% if params[:angular_theme_old] %>
<%= render file: Rails.root.join("app/views/layouts/application-ng.html.erb"), use_full_path: false %>
<% else %>
<%= from_theme_include(current_theme, "index") %>
<% end %>
angular-theme.git/package.json 0000664 0000000 0000000 00000007742 12747676640 0016714 0 ustar 00root root 0000000 0000000 {
"name": "angular-theme",
"version": "0.0.0",
"dependencies": {
"angular": "^1.5.0",
"angular-mock": "^1.0.0",
"moment": "^2.11.2",
"ng-forward": "0.0.1-alpha.12"
},
"config": {
"theme": "angular-default",
"skin": "skin-whbl"
},
"scripts": {
"build": "webpack; gulp clean && gulp --theme=$npm_package_config_theme --skin=$npm_package_config_skin build",
"build-all": "gulp clean && for d in ./themes/* ; do (gulp --theme=`basename $d` build); done",
"webpack": "webpack",
"karma": "concurrently \"webpack -w\" \"karma start\"",
"docs": "gulp ngdocs; static-server docs",
"coverage": "karma start --single-run; npm run remap-coverage",
"remap-coverage": "ts-node --project ./dev-scripts ./dev-scripts/remapCoverage.ts",
"test-single": "karma start --single-run",
"test-and-coverage": "karma start & npm run remap-coverage",
"test": "webpack -w --test",
"jenkins": "webpack && karma start --single-run",
"postinstall": "bower install; typings install; cd dev-scripts; typings install; cd ../; npm run fix-jqlite",
"start": "concurrently \"webpack -w\" \"gulp --theme=$npm_package_config_theme --skin=$npm_package_config_skin serve\"",
"generate-indexes": "ts-node --project ./dev-scripts ./dev-scripts/generate-index-modules.ts",
"fix-jqlite": "ts-node --project ./dev-scripts dev-scripts/fix-jqlite.ts",
"debug-gulp": "webpack; gulp clean; ./node_modules/.bin/iron-node node_modules/gulp/bin/gulp.js --theme=$npm_package_config_theme --skin=$npm_package_config_skin"
},
"devDependencies": {
"bower": "^1.7.7",
"browser-sync": "~2.9.11",
"browser-sync-spa": "~1.0.3",
"chalk": "~1.1.1",
"concurrently": "^2.0.0",
"core-js": "^2.1.3",
"del": "~2.0.2",
"eslint-plugin-angular": "~0.12.0",
"estraverse": "~4.1.0",
"expose-loader": "^0.7.1",
"fs-extra": "^0.30.0",
"glob": "^7.0.0",
"gulp": "^3.9.1",
"gulp-angular-filesort": "~1.1.1",
"gulp-angular-templatecache": "~1.8.0",
"gulp-autoprefixer": "~3.0.2",
"gulp-eslint": "~1.0.0",
"gulp-filter": "~3.0.1",
"gulp-flatten": "~0.2.0",
"gulp-import-css": "^0.1.2",
"gulp-inject": "~3.0.0",
"gulp-insert": "^0.5.0",
"gulp-load-plugins": "~0.10.0",
"gulp-merge-json": "^0.4.0",
"gulp-minify-css": "~1.2.1",
"gulp-minify-html": "~1.0.4",
"gulp-ng-annotate": "~1.1.0",
"gulp-ngdocs": "github:nikhilmodak/gulp-ngdocs.git",
"gulp-protractor": "~1.0.0",
"gulp-rename": "~1.2.2",
"gulp-replace": "~0.5.4",
"gulp-rev": "~6.0.1",
"gulp-rev-replace": "~0.4.2",
"gulp-sass": "~2.0.4",
"gulp-size": "~2.0.0",
"gulp-sourcemaps": "~1.6.0",
"gulp-typescript": "^2.12.0",
"gulp-uglify": "~1.4.1",
"gulp-useref": "~1.3.0",
"gulp-util": "~3.0.6",
"http-proxy-middleware": "~0.9.0",
"iron-node": "^3.0.7",
"istanbul": "^0.4.2",
"karma": "~0.13.10",
"karma-angular-filesort": "~1.0.0",
"karma-chrome-launcher": "^0.2.2",
"karma-coverage": "^0.5.3",
"karma-jasmine": "~0.3.6",
"karma-ng-html2js-preprocessor": "~0.2.0",
"karma-phantomjs-launcher": "~0.2.1",
"karma-phantomjs-shim": "^1.2.0",
"karma-sourcemap-loader": "^0.3.7",
"karma-spec-reporter": "0.0.24",
"karma-webpack": "^1.7.0",
"lodash": "~3.10.1",
"main-bower-files": "~2.9.0",
"map-stream": "0.0.6",
"merge-stream": "^1.0.0",
"on-build-webpack": "^0.1.0",
"phantomjs": "~1.9.18",
"phantomjs-polyfill": "0.0.2",
"reflect-metadata": "^0.1.3",
"remap-istanbul": "github:sitepen/remap-istanbul",
"replace": "^0.3.0",
"static-server": "^2.0.1",
"ts-loader": "^0.8.1",
"ts-node": "^0.5.5",
"tslint": "^3.5.0",
"tslint-loader": "^2.1.3",
"typescript": "^1.8.10",
"typings": "^0.6.8",
"uglify-save-license": "~0.4.1",
"vinyl-transform": "^1.0.0",
"webpack": "^1.12.14",
"wiredep": "~2.2.2",
"wrench": "~1.5.8",
"yargs": "^4.2.0"
},
"engines": {
"node": ">=0.10.0"
}
}
angular-theme.git/protractor.conf.js 0000664 0000000 0000000 00000001352 12747676640 0020076 0 ustar 00root root 0000000 0000000 'use strict';
var paths = require('./.yo-rc.json')['generator-gulp-angular'].props.paths;
// An example configuration file.
exports.config = {
// The address of a running selenium server.
//seleniumAddress: 'http://localhost:4444/wd/hub',
//seleniumServerJar: deprecated, this should be set on node_modules/protractor/config.json
// Capabilities to be passed to the webdriver instance.
capabilities: {
'browserName': 'chrome'
},
baseUrl: 'http://localhost:3000',
// Spec patterns are relative to the current working directory when
// protractor is called.
specs: [paths.e2e + '/**/*.js'],
// Options to be passed to Jasmine-node.
jasmineNodeOpts: {
showColors: true,
defaultTimeoutInterval: 30000
}
};
angular-theme.git/src/ 0000775 0000000 0000000 00000000000 12747676640 0015203 5 ustar 00root root 0000000 0000000 angular-theme.git/src/app/ 0000775 0000000 0000000 00000000000 12747676640 0015763 5 ustar 00root root 0000000 0000000 angular-theme.git/src/app/account/ 0000775 0000000 0000000 00000000000 12747676640 0017417 5 ustar 00root root 0000000 0000000 angular-theme.git/src/app/account/index.ts 0000664 0000000 0000000 00000000046 12747676640 0021076 0 ustar 00root root 0000000 0000000 export * from "./register.component";
angular-theme.git/src/app/account/register-component.html 0000664 0000000 0000000 00000010125 12747676640 0024130 0 ustar 00root root 0000000 0000000
{{"account.register.welcomeMessageTitle" | translate }}
{{"account.register.haveAccountMessage" | translate}}
angular-theme.git/src/app/account/register-terms.html 0000664 0000000 0000000 00000000452 12747676640 0023262 0 ustar 00root root 0000000 0000000
angular-theme.git/src/app/account/register.component.spec.ts 0000664 0000000 0000000 00000003671 12747676640 0024554 0 ustar 00root root 0000000 0000000 import { ComponentTestHelper, createClass } from "../../spec/component-test-helper";
import * as helpers from "../../spec/helpers";
import { RegisterComponent } from "./register.component";
// import {RegisterService} from "../../lib/ng-noosfero-api/http/register.service"
describe("Register Component", () => {
const htmlTemplate: string = '';
let helper: ComponentTestHelper;
let registerService = helpers.mocks.registerService;
let stateService = jasmine.createSpyObj("$state", ["transitionTo"]);
let notificationService = helpers.mocks.notificationService;
notificationService.success = jasmine.createSpy('success');
notificationService.error = jasmine.createSpy('error');
let account: any = {
id: 1,
login: 'test',
email: 'test@email.com',
password: 'xxx',
passwordConfirmation: 'xxx'
};
beforeEach(() => {
angular.mock.module('templates');
angular.mock.module('ngSanitize');
angular.mock.module('ngMessages');
angular.mock.module('ngPassword');
});
beforeEach((done) => {
let cls = createClass({
template: htmlTemplate,
directives: [RegisterComponent],
providers: [
helpers.createProviderToValue('$state', stateService),
helpers.createProviderToValue('$uibModal', helpers.mocks.$modal),
helpers.createProviderToValue('RegisterService', registerService),
helpers.createProviderToValue('NotificationService', notificationService),
helpers.createProviderToValue('EnvironmentService', helpers.mocks.environmentService)
]
});
helper = new ComponentTestHelper(cls, done);
});
it('register page was rendered', () => {
expect(helper.debugElement.query('div.register-page').length).toEqual(1);
});
});
angular-theme.git/src/app/account/register.component.ts 0000664 0000000 0000000 00000004646 12747676640 0023626 0 ustar 00root root 0000000 0000000 import { Inject, Input, Component, Output, EventEmitter, provide } from 'ng-forward';
import { RegisterService } from "./../../lib/ng-noosfero-api/http/register.service";
import { NotificationService } from "./../shared/services/notification.service";
import { EnvironmentService } from "../../lib/ng-noosfero-api/http/environment.service";
import { RegisterController } from "./register.controller";
import { IModalComponent } from "../shared/components/interfaces";
@Component({
selector: 'noosfero-register',
templateUrl: 'app/account/register-component.html',
providers: [
provide('registerService', { useClass: RegisterService })
]
})
@Inject('$state', '$uibModal', '$scope', RegisterService, NotificationService, EnvironmentService)
export class RegisterComponent {
@Input() account: any;
environment: noosfero.Environment;
modalInstance: ng.ui.bootstrap.IModalServiceInstance;
constructor(
private $state: ng.ui.IStateService,
private $uibModal: ng.ui.bootstrap.IModalService,
private $scope: ng.IScope,
public registerService: RegisterService,
private notificationService: NotificationService,
private environmentService: EnvironmentService
) {
this.account = {};
this.environment = environmentService.getCurrentEnvironment();
}
signup() {
if (this.account.password === this.account.passwordConfirmation) {
this.registerService.createAccount(this.account).then((response) => {
if (response.status === 201) {
this.$state.transitionTo('main.environment');
this.notificationService.success({ title: "account.register.success.title", message: "account.register.success.message" });
} else {
throw new Error('Invalid attributes');
}
});
} else {
this.notificationService.error({ message: "account.register.passwordConfirmation.failed" });
}
}
isInvalid(field: any): any {
return { 'has-error': field['$touched'] && field['$invalid'] };
}
openTerms() {
this.modalInstance = this.$uibModal.open({
templateUrl: 'app/account/register-terms.html',
size: 'lg',
controller: RegisterController,
controllerAs: 'vm',
bindToController: true,
scope: this.$scope
});
}
}
angular-theme.git/src/app/account/register.controller.ts 0000664 0000000 0000000 00000000616 12747676640 0024000 0 ustar 00root root 0000000 0000000 import { Input } from "ng-forward";
import { IModalComponent } from "../shared/components/interfaces";
export class RegisterController {
static $inject = ["$log", "$stateParams", "$scope"];
ctrl: IModalComponent;
constructor(
private $log: ng.ILogService,
private $stateParams: any
) { }
closeTerms() {
this.ctrl.modalInstance.dismiss('ok');
}
}
angular-theme.git/src/app/account/register.html 0000664 0000000 0000000 00000000316 12747676640 0022131 0 ustar 00root root 0000000 0000000
angular-theme.git/src/app/account/scss/ 0000775 0000000 0000000 00000000000 12747676640 0020372 5 ustar 00root root 0000000 0000000 angular-theme.git/src/app/account/scss/register.scss 0000664 0000000 0000000 00000001310 12747676640 0023106 0 ustar 00root root 0000000 0000000 .modal .modal-body-overflow {
max-height: 420px;
overflow-y: auto;
}
.register-page button {
width: 100%;
text-transform: uppercase;
font-weight: 600;
}
.register-page .light-text {
color: #BBB;
margin-top: 0px;
margin-bottom: 0px;
font-weight: 600;
}
.register-page .terms-info {
margin-top: 30px;
margin-bottom: 30px;
font-weight: bold;
}
.register-page .welcome-message {
text-align: center;
}
.register-page .already-registered-message {
margin-top: 60px;
text-align: center;
}
.register-page input {
height: 40px;
}
.register-page .register-field {
margin-bottom: 25px;
}
.register-page input:focus {
border: 2px solid #bbb;
}
angular-theme.git/src/app/admin/ 0000775 0000000 0000000 00000000000 12747676640 0017053 5 ustar 00root root 0000000 0000000 angular-theme.git/src/app/admin/index.ts 0000664 0000000 0000000 00000000115 12747676640 0020527 0 ustar 00root root 0000000 0000000 /* Module Index Entry - generated using the script npm run generate-index */
angular-theme.git/src/app/admin/layout-edit/ 0000775 0000000 0000000 00000000000 12747676640 0021313 5 ustar 00root root 0000000 0000000 angular-theme.git/src/app/admin/layout-edit/designMode.service.spec.ts 0000664 0000000 0000000 00000002433 12747676640 0026333 0 ustar 00root root 0000000 0000000 import {DesignModeService} from './designMode.service';
import {INoosferoLocalStorage} from "./../../shared/models/interfaces";
describe('DesignMode Service', () => {
let service: DesignModeService;
let $localStorage = { currentUser: null, settings: { designMode: false } };
beforeEach(() => {
service = new DesignModeService($localStorage);
});
it('has the designModeOn equals false as default', () => {
expect(service.isInDesignMode()).toBeFalsy();
});
it('allows set the designMode value', () => {
spyOn(service.onToggle, 'next').and.stub();
service.setInDesignMode(true);
expect(service.isInDesignMode).toBeTruthy();
});
it('emits the onToggle event when changing the designModeOn property', () => {
service.setInDesignMode(false);
spyOn(service.onToggle, 'next').and.stub();
service.setInDesignMode(true);
expect(service.onToggle.next).toHaveBeenCalled();
});
it('does not emit onToggle event when there is no change on designModeOn property', () => {
service.setInDesignMode(false);
spyOn(service.onToggle, 'next').and.stub();
service.setInDesignMode(false);
expect(service.onToggle.next).not.toHaveBeenCalled();
});
});
angular-theme.git/src/app/admin/layout-edit/designMode.service.ts 0000664 0000000 0000000 00000001574 12747676640 0025407 0 ustar 00root root 0000000 0000000 import {Injectable, Output, EventEmitter, Inject} from 'ng-forward';
import {INoosferoLocalStorage} from "./../../shared/models/interfaces";
@Injectable()
@Inject("$localStorage")
export class DesignModeService {
@Output() onToggle: EventEmitter = new EventEmitter();
isInDesignMode(): boolean {
return this.$localStorage.settings.designModeOn;
}
destroy() {
delete this.$localStorage.settings;
this.$localStorage.settings = {};
}
setInDesignMode(value: boolean) {
if (this.$localStorage.settings.designModeOn !== value) {
this.$localStorage.settings.designModeOn = value;
this.onToggle.next(value);
}
}
constructor(private $localStorage: INoosferoLocalStorage) {
if (!this.$localStorage.settings) {
this.$localStorage.settings = {};
}
}
}
angular-theme.git/src/app/admin/layout-edit/designModeToggler.component.spec.ts 0000664 0000000 0000000 00000005027 12747676640 0030223 0 ustar 00root root 0000000 0000000 import {ComponentTestHelper, createClass} from '../../../spec/component-test-helper';
import {INgForwardJQuery} from 'ng-forward/cjs/util/jqlite-extensions';
import * as helpers from '../../../spec/helpers';
import {DesignModeTogglerComponent} from './designModeToggler.component';
import {DesignModeService} from './designMode.service';
import {INoosferoLocalStorage} from "./../../shared/models/interfaces";
describe('DesignModeToggler Component', () => {
const htmlTemplate: string = '';
let helper: ComponentTestHelper;
beforeEach(() => {
angular.mock.module('templates');
angular.mock.module('ngSanitize');
angular.mock.module('uiSwitch');
});
let designModeService: DesignModeService;
let $localStorage = { currentUser: null, settings: { designMode: false } };
beforeEach((done) => {
designModeService = new DesignModeService($localStorage);
let cls = createClass({
template: htmlTemplate,
directives: [DesignModeTogglerComponent],
providers: [
helpers.createProviderToValue('DesignModeService', designModeService),
helpers.createProviderToValue('AuthService', helpers.mocks.authService),
]
});
helper = new ComponentTestHelper(cls, done);
});
it('changes css classes representing the switch is on or off', () => {
let switchEl: INgForwardJQuery = helper.debugElement.query('span.switch');
expect(switchEl.hasClass('checked')).toBeFalsy();
helper.component.inDesignMode = true;
helper.detectChanges();
expect(switchEl.hasClass('checked')).toBeTruthy();
});
it('emits event with value "true" when changing inDesignMode to On', (done) => {
designModeService.setInDesignMode(false);
designModeService.onToggle.subscribe((designModeOn: boolean) => {
expect(designModeOn).toBeTruthy();
done();
});
helper.component.inDesignMode = true;
helper.detectChanges();
});
it('emits events with value "false" when changing inDesignMode to Off', (done) => {
helper.component.inDesignMode = true;
helper.detectChanges();
designModeService.onToggle.subscribe((designModeOn: boolean) => {
expect(designModeOn).toBeFalsy();
done();
});
helper.component.inDesignMode = false;
helper.detectChanges();
});
});
angular-theme.git/src/app/admin/layout-edit/designModeToggler.component.ts 0000664 0000000 0000000 00000001566 12747676640 0027276 0 ustar 00root root 0000000 0000000 import {Component, Inject, Input} from 'ng-forward';
import {DesignModeService} from './designMode.service';
import {AuthService, AuthEvents} from '../../login';
@Component({
selector: 'design-toggler',
templateUrl: 'app/admin/layout-edit/designModeToggler.html'
})
@Inject(DesignModeService, AuthService, '$sce')
export class DesignModeTogglerComponent {
private _inDesignMode: boolean = false;
constructor(private designModeService: DesignModeService, private authService: AuthService, private $sce: ng.ISCEService) {
this.authService.subscribe(AuthEvents[AuthEvents.logoutSuccess], () => {
this.designModeService.destroy();
});
}
get inDesignMode(): boolean {
return this.designModeService.isInDesignMode();
};
set inDesignMode(value: boolean) {
this.designModeService.setInDesignMode(value);
};
}
angular-theme.git/src/app/admin/layout-edit/designModeToggler.html 0000664 0000000 0000000 00000000153 12747676640 0025602 0 ustar 00root root 0000000 0000000
angular-theme.git/src/app/admin/layout-edit/designModeToggler.scss 0000664 0000000 0000000 00000001361 12747676640 0025613 0 ustar 00root root 0000000 0000000 $off-text: #949494;
$off-color: #EFEFEF;
$blue-color: #36B4F6;
$red-color: #DF3B3A;
body.noosfero-design-on {
div.content-wrapper {
opacity: 0.5;
}
}
.switch {
@include not-select();
background-color: $off-color;
&[on][off] {
width: 60px;
}
&:focus {
outline: none;
}
&.checked small {
left: initial;
right: 0px;
}
&.blue.checked {
background: $blue-color;
border-color: $blue-color;
}
&.red.checked {
background: $red-color;
border-color: $red-color;
}
%switch-label {
font-weight: bold;
}
.on {
@extend %switch-label;
}
.off {
@extend %switch-label;
right: 2px;
top: 25%;
color: $off-text;
text-align: center;
}
}
angular-theme.git/src/app/article/ 0000775 0000000 0000000 00000000000 12747676640 0017406 5 ustar 00root root 0000000 0000000 angular-theme.git/src/app/article/article-default-view-component.spec.ts 0000664 0000000 0000000 00000012500 12747676640 0026722 0 ustar 00root root 0000000 0000000 import {Input, provide, Component} from 'ng-forward';
import {ArticleViewComponent, ArticleDefaultViewComponent} from './article-default-view.component';
import {ComponentTestHelper, createClass} from './../../spec/component-test-helper';
import * as helpers from "../../spec/helpers";
// this htmlTemplate will be re-used between the container components in this spec file
const htmlTemplate: string = '';
describe("Components", () => {
// the karma preprocessor html2js transform the templates html into js files which put
// the templates to the templateCache into the module templates
// we need to load the module templates here as the template for the
// component Noosfero ArtileView will be load on our tests
beforeEach(angular.mock.module("templates"));
describe("Article Default View Component", () => {
let helper: ComponentTestHelper;
const defaultViewTemplate: string = '';
let notificationService = helpers.mocks.notificationService;
let articleService: any = helpers.mocks.articleService;
let article = {
id: 1,
profile: {
identifier: "1"
}
};
let state = jasmine.createSpyObj("state", ["go", "transitionTo"]);
let providers = [
provide('$state', { useValue: state }),
provide('ArticleService', { useValue: articleService }),
helpers.createProviderToValue('NotificationService', notificationService),
].concat(helpers.provideFilters("translateFilter"));
/**
* The beforeEach procedure will initialize the helper and parse
* the component according to the given providers. Unfortunetly, in
* this mode, the providers and properties given to the construtor
* can't be overriden.
*/
beforeEach((done) => {
// Create the component bed for the test. Optionally, this could be done
// in each test if one needs customization of these parameters per test
let cls = createClass({
template: defaultViewTemplate,
directives: [ArticleDefaultViewComponent],
providers: providers,
properties: {
article: article
}
});
helper = new ComponentTestHelper(cls, done);
});
function getArticle() {
return this.article;
}
it("it should delete article when delete is activated", () => {
expect(helper.component.article).toEqual(article);
// Spy the state service
doDeleteArticle();
expect(state.transitionTo).toHaveBeenCalled();
});
it("hide button to delete article when user doesn't have permission", () => {
expect(helper.find(".article-toolbar .delete-article").attr('style')).toEqual("display: none; ");
});
it("hide button to edit article when user doesn't have permission", () => {
expect(helper.find(".article-toolbar .edit-article").attr('style')).toEqual("display: none; ");
});
it("show button to edit article when user has permission", () => {
(helper.component['article'])['permissions'] = ['allow_edit'];
helper.detectChanges();
expect(helper.find(".article-toolbar .edit-article").attr('style')).toEqual('');
});
it("show button to delete article when user has permission", () => {
(helper.component['article'])['permissions'] = ['allow_delete'];
helper.detectChanges();
expect(helper.find(".article-toolbar .delete-article").attr('style')).toEqual('');
});
/**
* Execute the delete method on the target component
*/
function doDeleteArticle() {
// Create a mock for the notification service confirmation
spyOn(helper.component.notificationService, 'confirmation').and.callFake(function(params: Function) {
});
// Create a mock for the ArticleService removeArticle method
spyOn(helper.component.articleService, 'remove').and.callFake(function(param: noosfero.Article) {
return {
catch: () => { }
};
});
helper.component.delete();
expect(notificationService.confirmation).toHaveBeenCalled();
helper.component.doDelete();
expect(articleService.remove).toHaveBeenCalled();
// After the component delete method execution, fire the
// ArticleEvent.removed event
simulateRemovedEvent();
}
/**
* Simulate the Notification Service confirmation and ArticleService
* notifyArticleRemovedListeners event
*/
function simulateRemovedEvent() {
helper.component.notificationService["confirmation"]({ title: "Title", message: "Message" }, () => { });
helper.component.articleService["modelRemovedEventEmitter"].next(article);
}
});
});
angular-theme.git/src/app/article/article-default-view.component.ts 0000664 0000000 0000000 00000007107 12747676640 0026001 0 ustar 00root root 0000000 0000000 import { bundle, Input, Inject, Component, Directive } from 'ng-forward';
import {ArticleBlogComponent} from "./types/blog/blog.component";
import {CommentsComponent} from "./comment/comments.component";
import {MacroDirective} from "./macro/macro.directive";
import {ArticleToolbarHotspotComponent} from "../hotspot/article-toolbar-hotspot.component";
import {ArticleContentHotspotComponent} from "../hotspot/article-content-hotspot.component";
import {ArticleService} from "./../../lib/ng-noosfero-api/http/article.service";
import { NotificationService } from "./../shared/services/notification.service";
import {PermissionDirective} from '../shared/components/permission/permission.directive';
/**
* @ngdoc controller
* @name ArticleDefaultView
* @description
* A default view for Noosfero Articles. If the specific article view is
* not implemented, then this view is used.
*/
@Component({
selector: 'noosfero-default-article',
templateUrl: 'app/article/article.html',
directives: [PermissionDirective]
})
@Inject("$state", ArticleService, NotificationService)
export class ArticleDefaultViewComponent {
@Input() article: noosfero.Article;
@Input() profile: noosfero.Profile;
constructor(private $state: ng.ui.IStateService, public articleService: ArticleService, public notificationService: NotificationService) {
// Subscribe to the Article Removed Event
this.articleService.subscribeToModelRemoved((article: noosfero.Article) => {
if (this.article.parent) {
this.$state.transitionTo('main.profile.page', { page: this.article.parent.path, profile: this.article.profile.identifier });
} else {
this.$state.transitionTo('main.profile.info', { profile: this.article.profile.identifier });
}
this.notificationService.success({ title: "article.remove.success.title", message: "article.remove.success.message" });
});
}
delete() {
this.notificationService.confirmation({ title: "article.remove.confirmation.title", message: "article.remove.confirmation.message" }, () => {
this.doDelete();
});
}
doDelete() {
this.articleService.remove(this.article);
}
}
/**
* @ngdoc controller
* @name ArticleView
* @description
* A dynamic view for articles. It uses the article type to replace
* the default template with the custom article directive.
*/
@Component({
selector: 'noosfero-article',
template: 'not-used',
directives: [ArticleDefaultViewComponent, ArticleBlogComponent,
CommentsComponent, MacroDirective, ArticleToolbarHotspotComponent,
ArticleContentHotspotComponent]
})
@Inject("$element", "$scope", "$injector", "$compile")
export class ArticleViewComponent {
@Input() article: noosfero.Article;
@Input() profile: noosfero.Profile;
directiveName: string;
ngOnInit() {
let articleType = this.article.type.replace(/::/, '');
let specificDirective = 'noosfero' + articleType;
this.directiveName = "noosfero-default-article";
if (this.$injector.has(specificDirective + 'Directive')) {
this.directiveName = specificDirective.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();
}
this.$element.replaceWith(this.$compile('<' + this.directiveName + ' [article]="ctrl.article" [profile]="ctrl.profile">' + this.directiveName + '>')(this.$scope));
}
constructor(
private $element: any,
private $scope: ng.IScope,
private $injector: ng.auto.IInjectorService,
private $compile: ng.ICompileService) {
}
}
angular-theme.git/src/app/article/article-view-component.spec.ts 0000664 0000000 0000000 00000015176 12747676640 0025314 0 ustar 00root root 0000000 0000000 import {Input, provide, Component} from 'ng-forward';
import {ArticleViewComponent, ArticleDefaultViewComponent} from './article-default-view.component';
import * as helpers from "../../spec/helpers";
// this htmlTemplate will be re-used between the container components in this spec file
const htmlTemplate: string = '';
describe("Components", () => {
// the karma preprocessor html2js transform the templates html into js files which put
// the templates to the templateCache into the module templates
// we need to load the module templates here as the template for the
// component Noosfero ArtileView will be load on our tests
beforeEach(angular.mock.module("templates"));
describe("ArticleView Component", () => {
let state = jasmine.createSpyObj("state", ["go", "transitionTo"]);
it("renders the default component when no specific component is found", (done: Function) => {
// Creating a container component (ArticleContainerComponent) to include
// the component under test (ArticleView)
@Component({
selector: 'test-container-component',
template: htmlTemplate,
directives: [ArticleViewComponent],
providers: [
helpers.createProviderToValue('CommentService', helpers.mocks.commentService),
helpers.provideFilters("translateFilter"),
helpers.createProviderToValue('NotificationService', helpers.mocks.notificationService),
helpers.createProviderToValue('SessionService', helpers.mocks.sessionWithCurrentUser({})),
helpers.createProviderToValue('ArticleService', helpers.mocks.articleService),
helpers.createProviderToValue('$state', state)
]
})
class ArticleContainerComponent {
article = { type: 'anyArticleType' };
profile = { name: 'profile-name' };
}
helpers.createComponentFromClass(ArticleContainerComponent).then((fixture) => {
// and here we can inspect and run the test assertions
// gets the children component of ArticleContainerComponent
let articleView: ArticleViewComponent = fixture.debugElement.componentViewChildren[0].componentInstance;
// and checks if the article View rendered was the Default Article View
expect(articleView.constructor.prototype).toEqual(ArticleDefaultViewComponent.prototype);
// done needs to be called (it isn't really needed, as we can read in
// here (https://github.com/ngUpgraders/ng-forward/blob/master/API.md#createasync)
// because createAsync in ng-forward is not really async, but as the intention
// here is write tests in angular 2 ways, this is recommended
done();
});
});
it("receives the article and profile as inputs", (done: Function) => {
// Creating a container component (ArticleContainerComponent) to include
// the component under test (ArticleView)
@Component({
selector: 'test-container-component',
template: htmlTemplate,
directives: [ArticleViewComponent],
providers: [
helpers.createProviderToValue('CommentService', helpers.mocks.commentService),
helpers.provideFilters("translateFilter"),
helpers.createProviderToValue('NotificationService', helpers.mocks.notificationService),
helpers.createProviderToValue('SessionService', helpers.mocks.sessionWithCurrentUser({})),
helpers.createProviderToValue('ArticleService', helpers.mocks.articleService),
helpers.createProviderToValue('$state', state)
]
})
class ArticleContainerComponent {
article = { type: 'anyArticleType' };
profile = { name: 'profile-name' };
}
// uses the TestComponentBuilder instance to initialize the component
helpers.createComponentFromClass(ArticleContainerComponent).then((fixture) => {
// and here we can inspect and run the test assertions
let articleView: ArticleViewComponent = fixture.debugElement.componentViewChildren[0].componentInstance;
// assure the article object inside the ArticleView matches
// the provided through the parent component
expect(articleView.article.type).toEqual("anyArticleType");
expect(articleView.profile.name).toEqual("profile-name");
// done needs to be called (it isn't really needed, as we can read in
// here (https://github.com/ngUpgraders/ng-forward/blob/master/API.md#createasync)
// because createAsync in ng-forward is not really async, but as the intention
// here is write tests in angular 2 ways, this is recommended
done();
});
});
it("renders a article view which matches to the article type", done => {
// NoosferoTinyMceArticle component created to check if it will be used
// when a article with type 'TinyMceArticle' is provided to the noosfero-article (ArticleView)
// *** Important *** - the selector is what ng-forward uses to define the name of the directive provider
@Component({ selector: 'noosfero-tiny-mce-article', template: "TinyMceArticle
" })
class TinyMceArticleView {
@Input() article: any;
@Input() profile: any;
}
// Creating a container component (ArticleContainerComponent) to include our NoosferoTinyMceArticle
@Component({ selector: 'test-container-component', template: htmlTemplate, directives: [ArticleViewComponent, TinyMceArticleView] })
class CustomArticleType {
article = { type: 'TinyMceArticle' };
profile = { name: 'profile-name' };
}
helpers.createComponentFromClass(CustomArticleType).then(fixture => {
let myComponent: CustomArticleType = fixture.componentInstance;
expect(myComponent.article.type).toEqual("TinyMceArticle");
expect(fixture.debugElement.componentViewChildren[0].text()).toEqual("TinyMceArticle");
done();
});
});
});
});
angular-theme.git/src/app/article/article.html 0000664 0000000 0000000 00000003165 12747676640 0021724 0 ustar 00root root 0000000 0000000
angular-theme.git/src/app/article/article.scss 0000664 0000000 0000000 00000000274 12747676640 0021731 0 ustar 00root root 0000000 0000000 .article {
.page-info {
.author {
a {
color: #b4bcc2;
}
}
}
.page-header {
margin-bottom: 5px;
}
.sub-header {
margin-bottom: 20px;
}
}
angular-theme.git/src/app/article/cms/ 0000775 0000000 0000000 00000000000 12747676640 0020170 5 ustar 00root root 0000000 0000000 angular-theme.git/src/app/article/cms/article-editor/ 0000775 0000000 0000000 00000000000 12747676640 0023077 5 ustar 00root root 0000000 0000000 angular-theme.git/src/app/article/cms/article-editor/article-editor.component.spec.ts 0000664 0000000 0000000 00000002217 12747676640 0031312 0 ustar 00root root 0000000 0000000 import {ArticleEditorComponent} from './article-editor.component';
import {BasicEditorComponent} from "../basic-editor/basic-editor.component";
import {ComponentTestHelper, createClass} from '../../../../spec/component-test-helper';
import * as helpers from "../../../../spec/helpers";
const htmlTemplate: string = '';
describe("Components", () => {
describe("Article Editor Component", () => {
let helper: ComponentTestHelper;
beforeEach(angular.mock.module("templates"));
beforeEach((done) => {
let properties = { article: { type: "TextArticle" } };
let cls = createClass({
template: htmlTemplate,
directives: [ArticleEditorComponent, BasicEditorComponent],
properties: properties
});
helper = new ComponentTestHelper(cls, done);
});
it("replace element with article basic editor when type is TextArticle", () => {
expect(helper.find("article-basic-editor").length).toEqual(1);
});
});
});
angular-theme.git/src/app/article/cms/article-editor/article-editor.component.ts 0000664 0000000 0000000 00000002116 12747676640 0030357 0 ustar 00root root 0000000 0000000 import {Component, Input, Inject} from 'ng-forward';
@Component({
selector: 'article-editor',
template: "not-used"
})
@Inject("$element", "$scope", "$injector", "$compile")
export class ArticleEditorComponent {
@Input() article: noosfero.Article;
constructor(
private $element: any,
private $scope: ng.IScope,
private $injector: ng.auto.IInjectorService,
private $compile: ng.ICompileService) { }
ngOnInit() {
let articleType = this.article && this.article.type ? this.article.type.replace(/::/, '') : "TextArticle";
let specificDirective = `${articleType.charAt(0).toLowerCase()}${articleType.substring(1)}Editor`;
let directiveName = "article-basic-editor";
if (specificDirective !== "articleEditor" && this.$injector.has(specificDirective + 'Directive')) {
directiveName = specificDirective.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();
}
this.$element.replaceWith(this.$compile('<' + directiveName + ' [article]="ctrl.article">' + directiveName + '>')(this.$scope));
}
}
angular-theme.git/src/app/article/cms/basic-editor/ 0000775 0000000 0000000 00000000000 12747676640 0022535 5 ustar 00root root 0000000 0000000 angular-theme.git/src/app/article/cms/basic-editor/basic-editor.component.ts 0000664 0000000 0000000 00000000365 12747676640 0027457 0 ustar 00root root 0000000 0000000 import {Component, Input} from 'ng-forward';
@Component({
selector: 'article-basic-editor',
templateUrl: "app/article/cms/basic-editor/basic-editor.html"
})
export class BasicEditorComponent {
@Input() article: noosfero.Article;
}
angular-theme.git/src/app/article/cms/basic-editor/basic-editor.html 0000664 0000000 0000000 00000000712 12747676640 0025770 0 ustar 00root root 0000000 0000000
angular-theme.git/src/app/article/cms/basic-editor/basic-editor.scss 0000664 0000000 0000000 00000000000 12747676640 0025765 0 ustar 00root root 0000000 0000000 angular-theme.git/src/app/article/cms/basic-options/ 0000775 0000000 0000000 00000000000 12747676640 0022742 5 ustar 00root root 0000000 0000000 angular-theme.git/src/app/article/cms/basic-options/basic-options.component.ts 0000664 0000000 0000000 00000000372 12747676640 0030067 0 ustar 00root root 0000000 0000000 import {Component, Input} from 'ng-forward';
@Component({
selector: 'article-basic-options',
templateUrl: "app/article/cms/basic-options/basic-options.html"
})
export class BasicOptionsComponent {
@Input() article: noosfero.Article;
}
angular-theme.git/src/app/article/cms/basic-options/basic-options.html 0000664 0000000 0000000 00000001162 12747676640 0026402 0 ustar 00root root 0000000 0000000
{{"article.basic_editor.visibility" | translate}}
angular-theme.git/src/app/article/cms/basic-options/basic-options.scss 0000664 0000000 0000000 00000000326 12747676640 0026412 0 ustar 00root root 0000000 0000000 .side-options {
margin-top: 25px;
.visibility {
.panel-heading {
background-color: transparent;
font-weight: bold;
}
.panel-body {
i {
color: #A5A5A5;
}
}
}
}
angular-theme.git/src/app/article/cms/cms.component.spec.ts 0000664 0000000 0000000 00000007324 12747676640 0024262 0 ustar 00root root 0000000 0000000 import {quickCreateComponent} from "../../../spec/helpers";
import {CmsComponent} from "./cms.component";
describe("Article Cms", () => {
let $rootScope: ng.IRootScopeService;
let $q: ng.IQService;
let articleServiceMock: any;
let profileServiceMock: any;
let $state: any;
let $stateParams: any;
let $window: any;
let profile = { id: 1 };
let notification: any;
beforeEach(inject((_$rootScope_: ng.IRootScopeService, _$q_: ng.IQService) => {
$rootScope = _$rootScope_;
$q = _$q_;
}));
beforeEach(() => {
$window = jasmine.createSpyObj("$window", ["back"]);
$state = jasmine.createSpyObj("$state", ["go"]);
notification = jasmine.createSpyObj("notification", ["success"]);
profileServiceMock = jasmine.createSpyObj("profileServiceMock", ["setCurrentProfileByIdentifier"]);
articleServiceMock = jasmine.createSpyObj("articleServiceMock", ["createInParent", "updateArticle", "get"]);
$stateParams = { profile: "profile" };
let setCurrentProfileByIdentifierResponse = $q.defer();
setCurrentProfileByIdentifierResponse.resolve(profile);
let articleCreate = $q.defer();
articleCreate.resolve({ data: { path: "path", profile: { identifier: "profile" } } });
let articleGet = $q.defer();
articleGet.resolve({ data: { path: "parent-path", profile: { identifier: "profile" } } });
profileServiceMock.setCurrentProfileByIdentifier = jasmine.createSpy("setCurrentProfileByIdentifier").and.returnValue(setCurrentProfileByIdentifierResponse.promise);
articleServiceMock.createInParent = jasmine.createSpy("createInParent").and.returnValue(articleCreate.promise);
articleServiceMock.updateArticle = jasmine.createSpy("updateArticle").and.returnValue(articleCreate.promise);
articleServiceMock.get = jasmine.createSpy("get").and.returnValue(articleGet.promise);
});
it("create an article in the current profile when save", done => {
$stateParams['parent_id'] = 1;
let component: CmsComponent = new CmsComponent(articleServiceMock, profileServiceMock, $state, notification, $stateParams, $window);
component.save();
$rootScope.$apply();
expect(profileServiceMock.setCurrentProfileByIdentifier).toHaveBeenCalled();
expect(articleServiceMock.createInParent).toHaveBeenCalledWith(1, component.article);
done();
});
it("got to the new article page and display an alert when saving sucessfully", done => {
$stateParams['parent_id'] = 1;
let component: CmsComponent = new CmsComponent(articleServiceMock, profileServiceMock, $state, notification, $stateParams, $window);
component.save();
$rootScope.$apply();
expect($state.go).toHaveBeenCalledWith("main.profile.page", { page: "path", profile: "profile" });
expect(notification.success).toHaveBeenCalled();
done();
});
it("go back when cancel article edition", done => {
let component: CmsComponent = new CmsComponent(articleServiceMock, profileServiceMock, $state, notification, $stateParams, $window);
$window.history = { back: jasmine.createSpy('back') };
component.cancel();
expect($window.history.back).toHaveBeenCalled();
done();
});
it("edit existing article when save", done => {
$stateParams['parent_id'] = null;
$stateParams['id'] = 2;
let component: CmsComponent = new CmsComponent(articleServiceMock, profileServiceMock, $state, notification, $stateParams, $window);
component.save();
$rootScope.$apply();
expect(articleServiceMock.updateArticle).toHaveBeenCalledWith(component.article);
done();
});
});
angular-theme.git/src/app/article/cms/cms.component.ts 0000664 0000000 0000000 00000006433 12747676640 0023331 0 ustar 00root root 0000000 0000000 import {StateConfig, Component, Inject, provide} from 'ng-forward';
import {ArticleService} from "../../../lib/ng-noosfero-api/http/article.service";
import {ProfileService} from "../../../lib/ng-noosfero-api/http/profile.service";
import {NotificationService} from "../../shared/services/notification.service.ts";
import {BasicOptionsComponent} from './basic-options/basic-options.component';
import {BasicEditorComponent} from './basic-editor/basic-editor.component';
import {ArticleEditorComponent} from './article-editor/article-editor.component';
@Component({
selector: 'article-cms',
templateUrl: "app/article/cms/cms.html",
providers: [
provide('articleService', { useClass: ArticleService }),
provide('profileService', { useClass: ProfileService }),
provide('notification', { useClass: NotificationService })
],
directives: [ArticleEditorComponent, BasicOptionsComponent, BasicEditorComponent]
})
@Inject(ArticleService, ProfileService, "$state", NotificationService, "$stateParams", "$window")
export class CmsComponent {
article: noosfero.Article;
parent: noosfero.Article = {};
id: number;
parentId: number;
profileIdentifier: string;
constructor(private articleService: ArticleService,
private profileService: ProfileService,
private $state: ng.ui.IStateService,
private notification: NotificationService,
private $stateParams: ng.ui.IStateParamsService,
private $window: ng.IWindowService) {
this.parentId = this.$stateParams['parent_id'];
this.profileIdentifier = this.$stateParams["profile"];
this.id = this.$stateParams['id'];
if (this.parentId) {
this.articleService.get(this.parentId).then((result: noosfero.RestResult) => {
this.parent = result.data;
});
}
if (this.id) {
this.articleService.get(this.id).then((result: noosfero.RestResult) => {
this.article = result.data;
this.article.name = this.article.title; // FIXME
});
} else {
this.article = { type: this.$stateParams['type'] || "TextArticle", published: true };
}
}
save() {
this.profileService.setCurrentProfileByIdentifier(this.profileIdentifier).then((profile: noosfero.Profile) => {
if (this.id) {
return this.articleService.updateArticle(this.article);
} else if (this.parentId) {
return this.articleService.createInParent(this.parentId, this.article);
} else {
return this.articleService.createInProfile(profile, this.article);
}
}).then((response: noosfero.RestResult) => {
let article = (response.data);
this.$state.go('main.profile.page', { page: article.path, profile: article.profile.identifier });
this.notification.success({ title: "article.basic_editor.success.title", message: "article.basic_editor.success.message" });
}).catch(() => {
this.notification.error({ message: "article.basic_editor.save.failed" });
});
}
cancel() {
this.$window.history.back();
}
}
angular-theme.git/src/app/article/cms/cms.html 0000664 0000000 0000000 00000001270 12747676640 0021640 0 ustar 00root root 0000000 0000000
angular-theme.git/src/app/article/cms/cms.scss 0000664 0000000 0000000 00000000066 12747676640 0021651 0 ustar 00root root 0000000 0000000 .cms {
@extend .container-fluid;
padding: 0 1%;
}
angular-theme.git/src/app/article/comment/ 0000775 0000000 0000000 00000000000 12747676640 0021050 5 ustar 00root root 0000000 0000000 angular-theme.git/src/app/article/comment/comment-reply-tooltip.html 0000664 0000000 0000000 00000000272 12747676640 0026222 0 ustar 00root root 0000000 0000000
angular-theme.git/src/app/article/comment/comment.component.spec.ts 0000664 0000000 0000000 00000011541 12747676640 0026016 0 ustar 00root root 0000000 0000000 import {Provider, provide, Component} from 'ng-forward';
import * as helpers from "../../../spec/helpers";
import {CommentComponent} from './comment.component';
const htmlTemplate: string = '';
describe("Components", () => {
describe("Comment Component", () => {
let properties: any;
let notificationService = helpers.mocks.notificationService;
let commentService = jasmine.createSpyObj("commentService", ["removeFromArticle"]);
beforeEach(angular.mock.module("templates"));
beforeEach(() => {
properties = {
article: { id: 1, accept_comments: true },
comment: { title: "title", body: "body" }
};
});
function createComponent() {
let providers = [
helpers.createProviderToValue('NotificationService', notificationService),
helpers.createProviderToValue("CommentService", commentService)
].concat(helpers.provideFilters("translateFilter"));
@Component({ selector: 'test-container-component', directives: [CommentComponent], template: htmlTemplate, providers: providers })
class ContainerComponent {
article = properties['article'];
comment = properties['comment'];
}
return helpers.createComponentFromClass(ContainerComponent);
}
it("render a comment", done => {
createComponent().then(fixture => {
expect(fixture.debugElement.queryAll(".comment").length).toEqual(1);
done();
});
});
it("not render a post comment tag in the beginning", done => {
createComponent().then(fixture => {
expect(fixture.debugElement.queryAll("noosfero-post-comment").length).toEqual(0);
done();
});
});
it("set show reply to true when click reply", done => {
createComponent().then(fixture => {
let component: CommentComponent = fixture.debugElement.componentViewChildren[0].componentInstance;
component.reply();
expect(component.showReply()).toBeTruthy("Reply was expected to be true");
done();
});
});
it("show reply relies on current comment __showReply attribute", done => {
createComponent().then(fixture => {
let component = fixture.debugElement.componentViewChildren[0];
component.componentInstance.comment.__showReply = false;
expect(component.componentInstance.showReply()).toEqual(false);
done();
});
});
it("display reply button", done => {
createComponent().then(fixture => {
expect(fixture.debugElement.queryAll(".comment .actions .reply").length).toEqual(1);
done();
});
});
it("not display reply button when accept_comments is false", done => {
properties['article']['accept_comments'] = false;
createComponent().then(fixture => {
expect(fixture.debugElement.queryAll(".comment .actions .reply").length).toEqual(0);
done();
});
});
it("does not show the Remove button if user is not allowed to remove", done => {
createComponent().then(fixture => {
let component: CommentComponent = fixture.debugElement.componentViewChildren[0].componentInstance;
component.allowRemove = () => false;
fixture.detectChanges();
expect(fixture.debugElement.queryAll("a.action.remove").length).toEqual(0);
done();
});
});
it("shows the Remove button if user is allowed to remove", done => {
createComponent().then(fixture => {
let component: CommentComponent = fixture.debugElement.componentViewChildren[0].componentInstance;
component.allowRemove = () => true;
fixture.detectChanges();
expect(fixture.debugElement.queryAll("a.action.remove").length).toEqual(1);
done();
});
});
it("call comment service to remove comment", done => {
notificationService.confirmation = (params: any, func: Function) => { func(); };
commentService.removeFromArticle = jasmine.createSpy("removeFromArticle").and.returnValue(Promise.resolve());
createComponent().then(fixture => {
let component = fixture.debugElement.componentViewChildren[0].componentInstance;
component.remove();
expect(commentService.removeFromArticle).toHaveBeenCalled();
done();
});
});
});
});
angular-theme.git/src/app/article/comment/comment.component.ts 0000664 0000000 0000000 00000003165 12747676640 0025070 0 ustar 00root root 0000000 0000000 import { Inject, Input, Component, Output, EventEmitter } from 'ng-forward';
import { PostCommentComponent } from "./post-comment/post-comment.component";
import { CommentService } from "../../../lib/ng-noosfero-api/http/comment.service";
import { NotificationService } from "../../shared/services/notification.service";
@Component({
selector: 'noosfero-comment',
outputs: ['commentRemoved'],
templateUrl: 'app/article/comment/comment.html'
})
@Inject(CommentService, NotificationService)
export class CommentComponent {
@Input() comment: noosfero.CommentViewModel;
@Input() article: noosfero.Article;
@Input() displayActions = true;
@Input() displayReplies = true;
@Output() commentRemoved: EventEmitter = new EventEmitter();
showReply() {
return this.comment && this.comment.__show_reply === true;
}
constructor(private commentService: CommentService,
private notificationService: NotificationService) { }
reply() {
this.comment.__show_reply = !this.comment.__show_reply;
}
allowRemove() {
return true;
}
remove() {
this.notificationService.confirmation({ title: "comment.remove.confirmation.title", message: "comment.remove.confirmation.message" }, () => {
this.commentService.removeFromArticle(this.article, this.comment).then((result: noosfero.RestResult) => {
this.commentRemoved.next(this.comment);
this.notificationService.success({ title: "comment.remove.success.title", message: "comment.remove.success.message" });
});
});
}
}
angular-theme.git/src/app/article/comment/comment.html 0000664 0000000 0000000 00000003106 12747676640 0023400 0 ustar 00root root 0000000 0000000
angular-theme.git/src/app/article/comment/comment.scss 0000664 0000000 0000000 00000002606 12747676640 0023413 0 ustar 00root root 0000000 0000000 .comments {
.comment {
margin: 20px;
.date {
@extend .text-muted;
@extend .small;
margin-left: 8px;
font-size: 12px;
}
.title {
font-weight: bold;
}
.actions {
.action {
text-decoration: none;
&:first-child {
.bullet-separator {
display: none;
}
}
.bullet-separator {
font-size: 8px;
vertical-align: middle;
margin: 3px;
color: #B6C2CA;
}
}
}
.media-left {
min-width: 40px;
}
.media-body {
padding: 0 10px 10px 0;
.reply-of {
font-size: 12px;
color: #B5B5B5;
margin-left: 5px;
i {
font-size: 10px;
}
}
h4 {
font-size: 16px;
}
}
noosfero-profile-image {
img {
height: 30px;
width: 30px;
max-width: 30px;
display: inline-block;
@extend .img-circle;
}
i {
font-size: 1.7em;
}
}
// Limit identation of replies
.comments {
margin-left: 30px;
.comments .comments {
margin-left: 0px;
.comment {
margin-left: 0px;
}
}
}
.tooltip-inner {
max-width: 350px;
text-align: left;
.reply-tooltip {
.comment {
margin: 5px;
}
}
}
}
}
angular-theme.git/src/app/article/comment/comments.component.spec.ts 0000664 0000000 0000000 00000011233 12747676640 0026177 0 ustar 00root root 0000000 0000000 import {Provider, provide, Component} from 'ng-forward';
import * as helpers from "../../../spec/helpers";
import {CommentsComponent} from './comments.component';
import {PostCommentComponent} from "./post-comment/post-comment.component";
const htmlTemplate: string = '';
describe("Components", () => {
describe("Comments Component", () => {
beforeEach(angular.mock.module("templates"));
let commentService = jasmine.createSpyObj("commentService", ["getByArticle"]);
let comments = [{ id: 2 }, { id: 3 }];
commentService.getByArticle = jasmine.createSpy("getByArticle")
.and.returnValue(helpers.mocks.promiseResultTemplate({ data: comments }));
let properties = { article: { id: 1 }, parent: null };
function createComponent() {
let providers = [
helpers.createProviderToValue('CommentService', commentService),
helpers.createProviderToValue('NotificationService', helpers.mocks.notificationService),
helpers.createProviderToValue('SessionService', helpers.mocks.sessionWithCurrentUser({}))
].concat(helpers.provideFilters("translateFilter"));
return helpers.quickCreateComponent({
providers: providers,
directives: [CommentsComponent],
template: htmlTemplate,
properties: properties
});
}
it("render comments associated to an article", done => {
createComponent().then(fixture => {
expect(fixture.debugElement.queryAll("noosfero-comment").length).toEqual(2);
done();
});
});
it("render a post comment tag", done => {
createComponent().then(fixture => {
expect(fixture.debugElement.queryAll("noosfero-post-comment").length).toEqual(1);
done();
});
});
it("update comments list when receive an reply", done => {
properties.parent = { id: 3 };
createComponent().then(fixture => {
(fixture.debugElement.componentViewChildren[0].componentInstance).commentAdded({ id: 1, reply_of: { id: 3 } });
fixture.detectChanges();
expect(fixture.debugElement.queryAll("noosfero-comment").length).toEqual(3);
done();
});
});
it("load comments for next page", done => {
createComponent().then(fixture => {
let headers = jasmine.createSpy("headers").and.returnValue(3);
commentService.getByArticle = jasmine.createSpy("getByArticle")
.and.returnValue(helpers.mocks.promiseResultTemplate({ data: { id: 4 }, headers: headers }));
let component: CommentsComponent = fixture.debugElement.componentViewChildren[0].componentInstance;
component.loadNextPage();
expect(component['page']).toEqual(3);
expect(component.comments.length).toEqual(3);
expect(component['total']).toEqual(3);
done();
});
});
it("not display more when there is no more comments to load", done => {
createComponent().then(fixture => {
let component: CommentsComponent = fixture.debugElement.componentViewChildren[0].componentInstance;
component['total'] = 0;
component.parent = null;
expect(component.displayMore()).toBeFalsy();
done();
});
});
it("remove comment when calling commentRemoved", done => {
createComponent().then(fixture => {
let component: CommentsComponent = fixture.debugElement.componentViewChildren[0].componentInstance;
let comment = { id: 1 };
component.comments = [comment];
component.commentRemoved(comment);
expect(component.comments).toEqual([]);
done();
});
});
it("do nothing when call commentRemoved with a comment that doesn't belongs to the comments list", done => {
createComponent().then(fixture => {
let component: CommentsComponent = fixture.debugElement.componentViewChildren[0].componentInstance;
let comment = { id: 1 };
component.comments = [comment];
component.commentRemoved({ id: 2 });
expect(component.comments).toEqual([comment]);
done();
});
});
});
});
angular-theme.git/src/app/article/comment/comments.component.ts 0000664 0000000 0000000 00000005237 12747676640 0025255 0 ustar 00root root 0000000 0000000 import { Inject, Input, Component, provide } from 'ng-forward';
import { PostCommentComponent } from "./post-comment/post-comment.component";
import { CommentService } from "../../../lib/ng-noosfero-api/http/comment.service";
import { CommentComponent } from "./comment.component";
@Component({
selector: 'noosfero-comments',
templateUrl: 'app/article/comment/comments.html',
directives: [PostCommentComponent, CommentComponent],
outputs: ['commentAdded']
})
@Inject(CommentService, "$scope")
export class CommentsComponent {
comments: noosfero.CommentViewModel[] = [];
@Input() showForm = true;
@Input() article: noosfero.Article;
@Input() parent: noosfero.CommentViewModel;
protected page = 1;
protected perPage = 5;
protected total = 0;
newComment = {};
constructor(protected commentService: CommentService, private $scope: ng.IScope) { }
ngOnInit() {
if (this.parent) {
this.comments = this.parent.replies;
} else {
this.loadNextPage();
}
}
commentAdded(comment: noosfero.CommentViewModel): void {
comment.__show_reply = false;
if (comment.reply_of) {
this.comments.forEach((commentOnList) => {
if (commentOnList.id === comment.reply_of.id) {
if (commentOnList.replies) {
commentOnList.replies.push(comment);
} else {
commentOnList.replies = [comment];
}
}
});
}
this.comments.push(comment);
this.resetShowReply();
this.$scope.$apply();
}
commentRemoved(comment: noosfero.Comment): void {
let index = this.comments.indexOf(comment, 0);
if (index >= 0) {
this.comments.splice(index, 1);
}
}
private resetShowReply() {
this.comments.forEach((comment: noosfero.CommentViewModel) => {
comment.__show_reply = false;
});
if (this.parent) {
this.parent.__show_reply = false;
}
}
loadComments() {
return this.commentService.getByArticle(this.article, { page: this.page, per_page: this.perPage });
}
loadNextPage() {
this.loadComments().then((result: noosfero.RestResult) => {
this.comments = this.comments.concat(result.data);
this.total = result.headers ? result.headers("total") : this.comments.length;
this.page++;
});
}
displayMore() {
let pages = Math.ceil(this.total / this.perPage);
return !this.parent && pages >= this.page;
}
}
angular-theme.git/src/app/article/comment/comments.html 0000664 0000000 0000000 00000001224 12747676640 0023562 0 ustar 00root root 0000000 0000000
angular-theme.git/src/app/article/comment/comments.scss 0000664 0000000 0000000 00000000124 12747676640 0023567 0 ustar 00root root 0000000 0000000 .comments {
border-top: 2px solid #F3F3F3;
.comments {
border-top: 0;
}
}
angular-theme.git/src/app/article/comment/post-comment/ 0000775 0000000 0000000 00000000000 12747676640 0023475 5 ustar 00root root 0000000 0000000 angular-theme.git/src/app/article/comment/post-comment/post-comment.component.spec.ts 0000664 0000000 0000000 00000007306 12747676640 0031432 0 ustar 00root root 0000000 0000000 import {Provider, provide, Component} from 'ng-forward';
import * as helpers from "../../../../spec/helpers";
import {PostCommentComponent} from './post-comment.component';
const htmlTemplate: string = '';
describe("Components", () => {
describe("Post Comment Component", () => {
let properties = { article: { id: 1, accept_comments: true } };
beforeEach(angular.mock.module("templates"));
let commentService = jasmine.createSpyObj("commentService", ["createInArticle"]);
let user = {};
let providers = [
new Provider('CommentService', { useValue: commentService }),
new Provider('NotificationService', { useValue: helpers.mocks.notificationService }),
new Provider('SessionService', { useValue: helpers.mocks.sessionWithCurrentUser(user) })
].concat(helpers.provideFilters("translateFilter"));
@Component({ selector: 'test-container-component', directives: [PostCommentComponent], template: htmlTemplate, providers: providers })
class ContainerComponent {
article = properties['article'];
comment = { id: 2 };
}
it("render the post comment form", done => {
helpers.createComponentFromClass(ContainerComponent).then(fixture => {
expect(fixture.debugElement.queryAll("form").length).toEqual(1);
done();
});
});
it("not render the post comment form when article doesn't accept comments", done => {
properties['article'].accept_comments = false;
helpers.createComponentFromClass(ContainerComponent).then(fixture => {
expect(fixture.debugElement.queryAll("form").length).toEqual(0);
done();
});
});
it("emit an event when create comment", done => {
helpers.createComponentFromClass(ContainerComponent).then(fixture => {
let component: PostCommentComponent = fixture.debugElement.componentViewChildren[0].componentInstance;
component.commentSaved.next = jasmine.createSpy("next");
commentService.createInArticle = jasmine.createSpy("createInArticle").and.returnValue(helpers.mocks.promiseResultTemplate({ data: {} }));
component.save();
expect(component.commentSaved.next).toHaveBeenCalled();
done();
});
});
it("notify success when create comment", done => {
helpers.createComponentFromClass(ContainerComponent).then(fixture => {
let component: PostCommentComponent = fixture.debugElement.componentViewChildren[0].componentInstance;
commentService.createInArticle = jasmine.createSpy("createInArticle").and.returnValue(helpers.mocks.promiseResultTemplate({ data: {} }));
component["notificationService"].success = jasmine.createSpy("success");
component.save();
expect(component["notificationService"].success).toHaveBeenCalled();
done();
});
});
it("set the reply id when reply to a comment", done => {
helpers.createComponentFromClass(ContainerComponent).then(fixture => {
let component: PostCommentComponent = fixture.debugElement.componentViewChildren[0].componentInstance;
component.comment = { reply_of_id: null };
component.parent = { id: 10 };
component.save();
expect(component.comment.reply_of_id).toEqual(component.parent.id);
done();
});
});
});
});
angular-theme.git/src/app/article/comment/post-comment/post-comment.component.ts 0000664 0000000 0000000 00000003254 12747676640 0030477 0 ustar 00root root 0000000 0000000 import { Inject, Input, Output, EventEmitter, Component } from 'ng-forward';
import { CommentService } from "../../../../lib/ng-noosfero-api/http/comment.service";
import { NotificationService } from "../../../shared/services/notification.service";
import { SessionService } from "../../../login";
import { CommentFormHotspotComponent } from "../../../hotspot/comment-form-hotspot.component";
@Component({
selector: 'noosfero-post-comment',
templateUrl: 'app/article/comment/post-comment/post-comment.html',
outputs: ['commentSaved'],
directives: [CommentFormHotspotComponent]
})
@Inject(CommentService, NotificationService, SessionService)
export class PostCommentComponent {
public static EVENT_COMMENT_RECEIVED = "comment.received";
@Input() article: noosfero.Article;
@Input() parent: noosfero.Comment;
@Output() commentSaved: EventEmitter = new EventEmitter();
@Input() comment = {};
private currentUser: noosfero.User;
constructor(private commentService: CommentService,
private notificationService: NotificationService,
private session: SessionService) {
this.currentUser = this.session.currentUser();
}
save() {
if (this.parent && this.comment) {
this.comment.reply_of_id = this.parent.id;
}
this.commentService.createInArticle(this.article, this.comment).then((result: noosfero.RestResult) => {
this.commentSaved.next(result.data);
this.comment.body = "";
this.notificationService.success({ title: "comment.post.success.title", message: "comment.post.success.message" });
});
}
}
angular-theme.git/src/app/article/comment/post-comment/post-comment.html 0000664 0000000 0000000 00000001572 12747676640 0027015 0 ustar 00root root 0000000 0000000
angular-theme.git/src/app/article/comment/post-comment/post-comment.scss 0000664 0000000 0000000 00000000530 12747676640 0027015 0 ustar 00root root 0000000 0000000 .comments {
.post-comment {
.media {
padding-top: 10px;
.media-left {
padding: 10px 0;
}
button {
margin-top: 10px;
&.ng-hide-add {
animation: 0.5s lightSpeedOut ease;
}
&.ng-hide-remove {
animation: 0.5s lightSpeedIn ease;
}
}
}
}
}
angular-theme.git/src/app/article/content-viewer/ 0000775 0000000 0000000 00000000000 12747676640 0022357 5 ustar 00root root 0000000 0000000 angular-theme.git/src/app/article/content-viewer/content-viewer-actions.component.spec.ts 0000664 0000000 0000000 00000005045 12747676640 0032274 0 ustar 00root root 0000000 0000000 import {Input, Component, provide} from 'ng-forward';
import * as helpers from "../../../spec/helpers";
import {ComponentTestHelper, createClass} from '../../../spec/component-test-helper';
import {ContentViewerActionsComponent} from './content-viewer-actions.component';
// this htmlTemplate will be re-used between the container components in this spec file
const htmlTemplate: string = '';
describe('Content Viewer Actions Component', () => {
let helper: ComponentTestHelper;
beforeEach(angular.mock.module("templates"));
let providers = [
provide('ProfileService', {
useValue: helpers.mocks.profileService
}),
provide('ArticleService', {
useValue: helpers.mocks.articleService
})
].concat(helpers.provideFilters("translateFilter"));
beforeEach((done) => {
let cls = createClass({
template: htmlTemplate,
directives: [ContentViewerActionsComponent],
providers: providers
});
helper = new ComponentTestHelper(cls, done);
});
it('renders content viewer actions directive', () => {
expect(helper.all("content-viewer-actions").length).toEqual(1);
});
it('return article parent as container when it is not a folder', () => {
let article = ({ id: 1, type: 'TextArticle', parent: { id: 2 } });
expect(helper.component.getArticleContainer(article)).toEqual(2);
});
it('return article as container when it is a folder', () => {
let article = ({ id: 1, type: 'Folder' });
expect(helper.component.getArticleContainer(article)).toEqual(1);
});
it('return article as container when it is a blog', () => {
let article = ({ id: 1, type: 'Blog' });
expect(helper.component.getArticleContainer(article)).toEqual(1);
});
it('check if profile was loaded', () => {
let profile: any = {
id: 1,
identifier: 'the-profile-test',
type: 'Person'
};
helpers.mocks.profileService.getCurrentProfile = () => {
return helpers.mocks.promiseResultTemplate(profile);
};
let component = new ContentViewerActionsComponent(helpers.mocks.profileService, helpers.mocks.articleService);
expect(component.profile).toEqual(jasmine.objectContaining(profile));
});
});
angular-theme.git/src/app/article/content-viewer/content-viewer-actions.component.ts 0000664 0000000 0000000 00000002530 12747676640 0031337 0 ustar 00root root 0000000 0000000 import {Component, Inject, provide} from "ng-forward";
import {ProfileService} from "../../../lib/ng-noosfero-api/http/profile.service";
import {ArticleService} from "../../../lib/ng-noosfero-api/http/article.service";
@Component({
selector: "content-viewer-actions",
templateUrl: "app/article/content-viewer/navbar-actions.html",
providers: [
provide('profileService', { useClass: ProfileService }),
provide('articleService', { useClass: ArticleService })
]
})
@Inject(ProfileService, ArticleService)
export class ContentViewerActionsComponent {
article: noosfero.Article;
profile: noosfero.Profile;
parentId: number;
constructor(profileService: ProfileService, articleService: ArticleService) {
profileService.getCurrentProfile().then((profile: noosfero.Profile) => {
this.profile = profile;
return articleService.getCurrent();
}).then((article: noosfero.Article) => {
this.article = article;
this.parentId = this.getArticleContainer(article);
});
}
getArticleContainer(article: noosfero.Article) {
// FIXME get folder types from api
if (article.type === "Blog" || article.type === "Folder") {
return article.id;
} else if (article.parent) {
return article.parent.id;
}
}
}
angular-theme.git/src/app/article/content-viewer/content-viewer.component.spec.ts 0000664 0000000 0000000 00000005452 12747676640 0030640 0 ustar 00root root 0000000 0000000 import {providers} from 'ng-forward/cjs/testing/providers';
import {Input, Component, provide} from 'ng-forward';
import * as helpers from "../../../spec/helpers";
import {ComponentFixture} from 'ng-forward/cjs/testing/test-component-builder';
import {ContentViewerComponent} from './content-viewer.component';
// this htmlTemplate will be re-used between the container components in this spec file
const htmlTemplate: string = '';
describe('Content Viewer Component', () => {
let stateParamsService: any;
// loading the templates
beforeEach(() => {
angular.mock.module("templates");
stateParamsService = { page: 1 };
providers((provide: any) => {
return [
provide('ArticleService', {
useValue: helpers.mocks.articleService
}),
provide('ProfileService', {
useValue: helpers.mocks.profileService
}),
// TODO: Como criar um mock do atributo "page" de stateParams
provide('$stateParams', {
useValue: stateParamsService
})
];
});
});
let buildComponent = (): Promise => {
return helpers.quickCreateComponent({
providers: [
helpers.provideEmptyObjects('Restangular')
],
directives: [ContentViewerComponent],
template: htmlTemplate
});
};
it('renders content viewer directive', (done: Function) => {
buildComponent().then((fixture: ComponentFixture) => {
expect(fixture.debugElement.query('content-viewer').length).toEqual(1);
done();
});
});
it('check if article was loaded', (done: Function) => {
let article: any = {
id: 1,
title: 'The article test'
};
let profile: any = {
id: 1,
identifier: 'the-profile-test',
type: 'Person'
};
helpers.mocks.profileService.getCurrentProfile = () => {
return helpers.mocks.promiseResultTemplate(profile);
};
helpers.mocks.articleService.getArticleByProfileAndPath = (profile: noosfero.Profile, path: string) => {
return helpers.mocks.promiseResultTemplate({
data: article
});
};
buildComponent().then((fixture: ComponentFixture) => {
let contentViewerComp: ContentViewerComponent = fixture.debugElement.componentViewChildren[0].componentInstance;
expect(contentViewerComp.profile).toEqual(profile);
expect(contentViewerComp.article).toEqual(article);
done();
});
});
});
angular-theme.git/src/app/article/content-viewer/content-viewer.component.ts 0000664 0000000 0000000 00000003016 12747676640 0027701 0 ustar 00root root 0000000 0000000 import {ArticleViewComponent} from "./../article-default-view.component";
import {Input, Component, StateConfig, Inject, provide} from "ng-forward";
import {ArticleBlogComponent} from "./../types/blog/blog.component";
import {ArticleService} from "../../../lib/ng-noosfero-api/http/article.service";
import {ProfileService} from "../../../lib/ng-noosfero-api/http/profile.service";
@Component({
selector: "content-viewer",
templateUrl: "app/article/content-viewer/page.html",
directives: [ArticleBlogComponent, ArticleViewComponent],
providers: [
provide('articleService', { useClass: ArticleService }),
provide('profileService', { useClass: ProfileService })
]
})
@Inject(ArticleService, ProfileService, "$stateParams")
export class ContentViewerComponent {
@Input()
article: noosfero.Article = null;
@Input()
profile: noosfero.Profile = null;
constructor(
private articleService: ArticleService,
private profileService: ProfileService,
private $stateParams: angular.ui.IStateParamsService) {
this.activate();
}
activate() {
this.profileService.getCurrentProfile().then((profile: noosfero.Profile) => {
this.profile = profile;
return this.articleService.getArticleByProfileAndPath(this.profile, this.$stateParams["page"]);
}).then((result: noosfero.RestResult) => {
this.article = result.data;
this.articleService.setCurrent(this.article);
});
}
}
angular-theme.git/src/app/article/content-viewer/index.ts 0000664 0000000 0000000 00000000255 12747676640 0024040 0 ustar 00root root 0000000 0000000 /* Module Index Entry - generated using the script npm run generate-index */
export * from "./content-viewer-actions.component";
export * from "./content-viewer.component";
angular-theme.git/src/app/article/content-viewer/navbar-actions.html 0000664 0000000 0000000 00000002053 12747676640 0026154 0 ustar 00root root 0000000 0000000
angular-theme.git/src/app/article/content-viewer/navbar-actions.spec.ts 0000664 0000000 0000000 00000004304 12747676640 0026570 0 ustar 00root root 0000000 0000000 import {TestComponentBuilder} from 'ng-forward/cjs/testing/test-component-builder';
import {Provider} from 'ng-forward';
import {ComponentTestHelper, createClass} from "./../../../spec/component-test-helper";
import {providers} from 'ng-forward/cjs/testing/providers';
import {ContentViewerActionsComponent} from '././content-viewer-actions.component';
import * as helpers from "../../../spec/helpers";
const htmlTemplate: string = '';
describe("Components", () => {
describe("Content Viewer Actions Component", () => {
let serviceMock = {
getEnvironmentPeople: (filters: any): any => {
return Promise.resolve([{ identifier: "person1" }]);
}
};
let providers = [
new Provider('ArticleService', { useValue: helpers.mocks.articleService }),
new Provider('ProfileService', { useValue: helpers.mocks.profileService })
];
let helper: ComponentTestHelper;
beforeEach(angular.mock.module("templates"));
/**
* The beforeEach procedure will initialize the helper and parse
* the component according to the given providers. Unfortunetly, in
* this mode, the providers and properties given to the construtor
* can't be overriden.
*/
beforeEach((done) => {
// Create the component bed for the test. Optionally, this could be done
// in each test if one needs customization of these parameters per test
let cls = createClass({
template: htmlTemplate,
directives: [ContentViewerActionsComponent],
providers: providers,
properties: {}
});
helper = new ComponentTestHelper(cls, done);
});
it("render the actions new item menu", () => {
expect(helper.all("a[class|='btn dropdown-toggle']")[0]).not.toBeNull();
});
it("render two menu item actions", () => {
expect(helper.all("ul")[1].find("li").length).toBe(2);
});
});
});
angular-theme.git/src/app/article/content-viewer/page.html 0000664 0000000 0000000 00000000147 12747676640 0024163 0 ustar 00root root 0000000 0000000
angular-theme.git/src/app/article/index.ts 0000664 0000000 0000000 00000000177 12747676640 0021072 0 ustar 00root root 0000000 0000000 /* Module Index Entry - generated using the script npm run generate-index */
export * from "./article-default-view.component";
angular-theme.git/src/app/article/macro/ 0000775 0000000 0000000 00000000000 12747676640 0020507 5 ustar 00root root 0000000 0000000 angular-theme.git/src/app/article/macro/macro.directive.spec.ts 0000664 0000000 0000000 00000002033 12747676640 0025064 0 ustar 00root root 0000000 0000000 import {Input, provide, Component} from 'ng-forward';
import {MacroDirective} from "./macro.directive";
import * as helpers from "../../../spec/helpers";
const htmlTemplate: string = '';
describe("Directives", () => {
describe("Macro directive", () => {
it("renders a macro component using the name passed in data-macro", (done: Function) => {
helpers.quickCreateComponent({ template: htmlTemplate, directives: [MacroDirective] }).then((fixture) => {
expect(fixture.debugElement.queryAll('macro-component').length).toEqual(1);
done();
});
});
it("extract custom attributes from macro", (done: Function) => {
helpers.quickCreateComponent({ template: htmlTemplate, directives: [MacroDirective] }).then((fixture) => {
expect(fixture.debugElement.query('macro-component').attr("custom")).toEqual("custom");
done();
});
});
});
});
angular-theme.git/src/app/article/macro/macro.directive.ts 0000664 0000000 0000000 00000002362 12747676640 0024140 0 ustar 00root root 0000000 0000000 import {Directive, Inject} from "ng-forward";
@Directive({
selector: '[macro]',
providers: []
})
@Inject('$element', '$scope', '$compile')
export class MacroDirective {
private macroPrefix = "data-macro";
constructor(private $element: any, private $scope: ng.IScope, private $compile: ng.ICompileService) {
let macro = $element[0].attributes[this.macroPrefix].value;
let componentName = this.normalizeName(macro);
let content = $element.html().replace(/"/g, '"');
let customAttributes = this.extractCustomAttributes($element[0].attributes);
$element.replaceWith($compile(`<${componentName} [article]="ctrl.article" content="${content}" ${customAttributes}>${componentName}>`)($scope));
}
extractCustomAttributes(attributes: any) {
let customAttributes = "";
for (let attr of attributes) {
if (attr.name.startsWith(this.macroPrefix + '-')) {
let name = this.normalizeName(attr.name.replace(this.macroPrefix + '-', ''));
customAttributes += ` ${name}='${attr.value}'`;
}
}
return customAttributes;
}
normalizeName(name: string) {
return name.replace(/[_\/]/g, '-').toLowerCase();
}
}
angular-theme.git/src/app/article/types/ 0000775 0000000 0000000 00000000000 12747676640 0020552 5 ustar 00root root 0000000 0000000 angular-theme.git/src/app/article/types/blog/ 0000775 0000000 0000000 00000000000 12747676640 0021475 5 ustar 00root root 0000000 0000000 angular-theme.git/src/app/article/types/blog/blog.component.spec.ts 0000664 0000000 0000000 00000005115 12747676640 0025724 0 ustar 00root root 0000000 0000000 import {providers} from 'ng-forward/cjs/testing/providers';
import {Input, provide, Component} from 'ng-forward';
import {ArticleBlogComponent} from './blog.component';
import {createComponentFromClass, quickCreateComponent, provideEmptyObjects, createProviderToValue, provideFilters} from "../../../../spec/helpers.ts";
import {ComponentTestHelper, createClass} from './../../../../spec/component-test-helper';
// this htmlTemplate will be re-used between the container components in this spec file
const htmlTemplate: string = '';
describe("Blog Component", () => {
function promiseResultTemplate(response?: {}) {
let thenFuncEmpty = (func: Function) => {
// does nothing
};
if (response) {
return {
then: (func: (response: any) => void) => {
func(response);
}
};
} else {
return {
then: (func: (response: any) => void) => {
// does nothing
}
};
}
}
let article1 = {
id: 1,
title: 'The article test'
};
let article2 = {
id: 1,
title: 'The article test'
};
let articles = [ article1, article2 ];
let articleService = {
getChildren: (article_id: number, filters: {}) => {
return promiseResultTemplate(null);
},
subscribeToArticleRemoved: (fn: Function) => {}
};
let helper: ComponentTestHelper;
beforeEach(angular.mock.module("templates"));
beforeEach((done) => {
providers((provide: any) => {
return [
provide('ArticleService', {
useValue: articleService
})
];
});
let providersHelper = [
provide('ArticleService', { useValue: articleService })
];
let cls = createClass({
template: htmlTemplate,
directives: [ArticleBlogComponent],
providers: providersHelper,
properties: {
posts: articles
}
});
helper = new ComponentTestHelper(cls, done);
});
it("renders the blog content", () => {
expect(helper.debugElement.query('div.blog').length).toEqual(1);
});
it("verify the blog data", () => {
expect(helper.component["posts"][0]).toEqual(jasmine.objectContaining(article1));
});
}); angular-theme.git/src/app/article/types/blog/blog.component.ts 0000664 0000000 0000000 00000002262 12747676640 0024773 0 ustar 00root root 0000000 0000000 import {Component, Input, Inject} from "ng-forward";
import {ArticleService} from "../../../../lib/ng-noosfero-api/http/article.service";
/**
* @ngdoc controller
* @name ArticleBlog
* @description
* An specific {@link ArticleView} for Blog articles.
*/
@Component({
selector: "noosfero-blog",
templateUrl: "app/article/types/blog/blog.html"
})
@Inject(ArticleService)
export class ArticleBlogComponent {
@Input() article: noosfero.Article;
@Input() profile: noosfero.Profile;
private posts: noosfero.Article[];
private perPage: number = 3;
private currentPage: number;
private totalPosts: number = 0;
constructor(private articleService: ArticleService) { }
ngOnInit() {
this.loadPage();
}
loadPage() {
let filters = {
content_type: "TextArticle",
per_page: this.perPage,
page: this.currentPage
};
this.articleService
.getChildren(this.article, filters)
.then((result: noosfero.RestResult) => {
this.totalPosts = result.headers("total");
this.posts = result.data;
});
}
}
angular-theme.git/src/app/article/types/blog/blog.html 0000664 0000000 0000000 00000001727 12747676640 0023315 0 ustar 00root root 0000000 0000000
angular-theme.git/src/app/article/types/blog/blog.scss 0000664 0000000 0000000 00000000401 12747676640 0023310 0 ustar 00root root 0000000 0000000 .blog {
.blog-cover {
margin: -15px;
position: relative;
h3 {
position: absolute;
bottom: 0;
background-color: rgba(0, 0, 0, 0.4);
color: white;
padding: 10px 15px;
margin: 0;
width: 100%;
}
}
}
angular-theme.git/src/app/article/types/blog/index.ts 0000664 0000000 0000000 00000000157 12747676640 0023157 0 ustar 00root root 0000000 0000000 /* Module Index Entry - generated using the script npm run generate-index */
export * from "./blog.component";
angular-theme.git/src/app/article/types/index.ts 0000664 0000000 0000000 00000000115 12747676640 0022226 0 ustar 00root root 0000000 0000000 /* Module Index Entry - generated using the script npm run generate-index */
angular-theme.git/src/app/environment/ 0000775 0000000 0000000 00000000000 12747676640 0020327 5 ustar 00root root 0000000 0000000 angular-theme.git/src/app/environment/environment-home.component.ts 0000664 0000000 0000000 00000002343 12747676640 0026174 0 ustar 00root root 0000000 0000000 import {Component, Inject, provide} from 'ng-forward';
import {EnvironmentService} from "../../lib/ng-noosfero-api/http/environment.service";
import {NotificationService} from "../shared/services/notification.service";
/**
* @ngdoc controller
* @name environment.Environment
* @description
* This is the environment controller.
*/
@Component({
selector: 'environment-home',
templateUrl: "app/environment/environment-home.html",
providers: [
provide('environmentService', { useClass: EnvironmentService }),
provide('notificationService', { useClass: NotificationService })
]
})
@Inject(EnvironmentService, "$log", "$sce")
export class EnvironmentHomeComponent {
environment: noosfero.Environment;
constructor(private environmentService: EnvironmentService, private $sce: ng.ISCEService) {
environmentService.get().then((result: noosfero.Environment) => {
this.environment = result;
});
}
getEnvironmentDescription() {
if (this.environment && this.environment.settings && this.environment.settings.description) {
return this.$sce.trustAsHtml(this.environment.settings.description);
}
else {
return "";
}
}
} angular-theme.git/src/app/environment/environment-home.html 0000664 0000000 0000000 00000000173 12747676640 0024510 0 ustar 00root root 0000000 0000000
{{ctrl.comment.author.name}}