Signed-off-by: Alex Coles <alex@alexbcoles.com> Conflicts: .travis.yml Gemfile Gemfile.lock README.md app/assets/stylesheets/external.css.sass.erb app/assets/stylesheets/legacy/main.css.sass app/models/work_package.rb config/routes.rb lib/tabular_form_builder.rb spec/controllers/versions_controller_spec.rb spec/exemplars/type_exemplar.rb spec/factories/type_factory.rb spec/legacy/unit/default_data_spec.rb spec/legacy/unit/helpers/application_helper_spec.rb spec/legacy/unit/mail_handler_spec.rb spec/legacy/unit/project_spec.rb spec/legacy/unit/time_entry_activity_spec.rb spec/legacy/unit/type_spec.rb spec/models/work_package/work_package_validations_spec.rb spec/requests/api/v3/render_resource_spec.rb test/functional/types_controller_test.rb test/test_helper.rb test/unit/version_test.rbpull/2952/head
@ -1,2 +1,2 @@ |
||||
https://github.com/heroku/heroku-buildpack-nodejs.git#v58 |
||||
https://github.com/heroku/heroku-buildpack-nodejs.git#v71 |
||||
https://github.com/pkgr/heroku-buildpack-ruby.git#universal |
||||
|
@ -0,0 +1,10 @@ |
||||
root = true |
||||
|
||||
[*] |
||||
end_of_line = lf |
||||
insert_final_newline = true |
||||
|
||||
[*.{js,rb}] |
||||
charset = utf-8 |
||||
indent_style = space |
||||
indent_size = 2 |
@ -0,0 +1,37 @@ |
||||
#-- copyright |
||||
# OpenProject is a project management system. |
||||
# Copyright (C) 2012-2015 the OpenProject Foundation (OPF) |
||||
# |
||||
# This program is free software; you can redistribute it and/or |
||||
# modify it under the terms of the GNU General Public License version 3. |
||||
# |
||||
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: |
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang |
||||
# Copyright (C) 2010-2013 the ChiliProject Team |
||||
# |
||||
# This program is free software; you can redistribute it and/or |
||||
# modify it under the terms of the GNU General Public License |
||||
# as published by the Free Software Foundation; either version 2 |
||||
# of the License, or (at your option) any later version. |
||||
# |
||||
# This program is distributed in the hope that it will be useful, |
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
# GNU General Public License for more details. |
||||
# |
||||
# You should have received a copy of the GNU General Public License |
||||
# along with this program; if not, write to the Free Software |
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
||||
# |
||||
# See doc/COPYRIGHT.rdoc for more details. |
||||
#++ |
||||
|
||||
# If you place a .env file into the root directory of OpenProject |
||||
# you can override some default settings that foreman will use |
||||
# to start OpenProject |
||||
|
||||
# override the default bind address |
||||
HOST=0.0.0.0 |
||||
|
||||
# override the default port |
||||
PORT=1337 |
@ -1,266 +1,6 @@ |
||||
AllCops: |
||||
Exclude: |
||||
- db/schema.rb |
||||
- lib/plugins/rfpdf/**/* |
||||
|
||||
AccessorMethodName: |
||||
Enabled: false |
||||
|
||||
ActionFilter: |
||||
Enabled: false |
||||
|
||||
Alias: |
||||
Enabled: false |
||||
|
||||
AndOr: |
||||
Enabled: false |
||||
|
||||
ArrayJoin: |
||||
Enabled: false |
||||
|
||||
AsciiComments: |
||||
Enabled: false |
||||
|
||||
AsciiIdentifiers: |
||||
Enabled: false |
||||
|
||||
Attr: |
||||
Enabled: false |
||||
|
||||
BlockNesting: |
||||
Enabled: false |
||||
|
||||
Blocks: |
||||
Enabled: false |
||||
|
||||
CaseEquality: |
||||
Enabled: false |
||||
|
||||
CharacterLiteral: |
||||
Enabled: false |
||||
|
||||
ClassAndModuleChildren: |
||||
Enabled: false |
||||
|
||||
ClassLength: |
||||
Enabled: false |
||||
|
||||
ClassVars: |
||||
Enabled: false |
||||
|
||||
CollectionMethods: |
||||
PreferredMethods: |
||||
find: detect |
||||
reduce: inject |
||||
collect: map |
||||
find_all: select |
||||
|
||||
ColonMethodCall: |
||||
Enabled: false |
||||
|
||||
CommentAnnotation: |
||||
Enabled: false |
||||
|
||||
CyclomaticComplexity: |
||||
Enabled: false |
||||
|
||||
Delegate: |
||||
Enabled: false |
||||
|
||||
DeprecatedHashMethods: |
||||
Enabled: false |
||||
|
||||
Documentation: |
||||
Enabled: false |
||||
|
||||
DotPosition: |
||||
EnforcedStyle: leading |
||||
|
||||
DoubleNegation: |
||||
Enabled: false |
||||
|
||||
EachWithObject: |
||||
Enabled: false |
||||
|
||||
EmptyLiteral: |
||||
Enabled: false |
||||
|
||||
Encoding: |
||||
Enabled: false |
||||
|
||||
EvenOdd: |
||||
Enabled: false |
||||
|
||||
FileName: |
||||
Enabled: false |
||||
|
||||
FlipFlop: |
||||
Enabled: false |
||||
|
||||
FormatString: |
||||
Enabled: false |
||||
|
||||
GlobalVars: |
||||
Enabled: false |
||||
|
||||
GuardClause: |
||||
Enabled: false |
||||
|
||||
IfUnlessModifier: |
||||
Enabled: false |
||||
|
||||
IfWithSemicolon: |
||||
Enabled: false |
||||
|
||||
InlineComment: |
||||
Enabled: false |
||||
|
||||
Lambda: |
||||
Enabled: false |
||||
|
||||
LambdaCall: |
||||
Enabled: false |
||||
|
||||
LineEndConcatenation: |
||||
Enabled: false |
||||
|
||||
LineLength: |
||||
Max: 99 |
||||
|
||||
MethodLength: |
||||
Enabled: false |
||||
|
||||
ModuleFunction: |
||||
Enabled: false |
||||
|
||||
NegatedIf: |
||||
Enabled: false |
||||
|
||||
NegatedWhile: |
||||
Enabled: false |
||||
|
||||
Next: |
||||
Enabled: false |
||||
|
||||
NilComparison: |
||||
Enabled: false |
||||
|
||||
Not: |
||||
Enabled: false |
||||
|
||||
NumericLiterals: |
||||
Enabled: false |
||||
|
||||
OneLineConditional: |
||||
Enabled: false |
||||
|
||||
OpMethod: |
||||
Enabled: false |
||||
|
||||
ParameterLists: |
||||
Enabled: false |
||||
|
||||
PercentLiteralDelimiters: |
||||
Enabled: false |
||||
|
||||
PerlBackrefs: |
||||
Enabled: false |
||||
|
||||
PredicateName: |
||||
NamePrefixBlacklist: |
||||
- is_ |
||||
|
||||
Proc: |
||||
Enabled: false |
||||
|
||||
RaiseArgs: |
||||
Enabled: false |
||||
|
||||
RegexpLiteral: |
||||
Enabled: false |
||||
|
||||
SelfAssignment: |
||||
Enabled: false |
||||
|
||||
SingleLineBlockParams: |
||||
Enabled: false |
||||
|
||||
SingleLineMethods: |
||||
Enabled: false |
||||
|
||||
SignalException: |
||||
Enabled: false |
||||
|
||||
SpecialGlobalVars: |
||||
Enabled: false |
||||
|
||||
StringLiterals: |
||||
EnforcedStyle: single_quotes |
||||
|
||||
VariableInterpolation: |
||||
Enabled: false |
||||
|
||||
TrailingComma: |
||||
Enabled: false |
||||
|
||||
TrivialAccessors: |
||||
Enabled: false |
||||
|
||||
VariableInterpolation: |
||||
Enabled: false |
||||
|
||||
WhenThen: |
||||
Enabled: false |
||||
|
||||
WhileUntilModifier: |
||||
Enabled: false |
||||
|
||||
WordArray: |
||||
Enabled: false |
||||
|
||||
# Lint |
||||
|
||||
AmbiguousOperator: |
||||
Enabled: false |
||||
|
||||
AmbiguousRegexpLiteral: |
||||
Enabled: false |
||||
|
||||
AssignmentInCondition: |
||||
Enabled: false |
||||
|
||||
ConditionPosition: |
||||
Enabled: false |
||||
|
||||
DeprecatedClassMethods: |
||||
Enabled: false |
||||
|
||||
ElseLayout: |
||||
Enabled: false |
||||
|
||||
HandleExceptions: |
||||
Enabled: false |
||||
|
||||
InvalidCharacterLiteral: |
||||
Enabled: false |
||||
|
||||
LiteralInCondition: |
||||
Enabled: false |
||||
|
||||
LiteralInInterpolation: |
||||
Enabled: false |
||||
|
||||
Loop: |
||||
Enabled: false |
||||
|
||||
ParenthesesAsGroupedExpression: |
||||
Enabled: false |
||||
|
||||
RequireParentheses: |
||||
Enabled: false |
||||
|
||||
UnderscorePrefixedVariableName: |
||||
Enabled: false |
||||
|
||||
Void: |
||||
Enabled: false |
||||
ruby: |
||||
enabled: true |
||||
config_file: .rubocop.yml |
||||
java_script: |
||||
enabled: true |
||||
config_file: ./frontend/.jshintrc |
||||
|
@ -1,2 +1,266 @@ |
||||
inherit_from: |
||||
- ./.hound.yml |
||||
AllCops: |
||||
Exclude: |
||||
- db/schema.rb |
||||
- lib/plugins/rfpdf/**/* |
||||
|
||||
AccessorMethodName: |
||||
Enabled: false |
||||
|
||||
ActionFilter: |
||||
Enabled: false |
||||
|
||||
Alias: |
||||
Enabled: false |
||||
|
||||
AndOr: |
||||
Enabled: false |
||||
|
||||
ArrayJoin: |
||||
Enabled: false |
||||
|
||||
AsciiComments: |
||||
Enabled: false |
||||
|
||||
AsciiIdentifiers: |
||||
Enabled: false |
||||
|
||||
Attr: |
||||
Enabled: false |
||||
|
||||
BlockNesting: |
||||
Enabled: false |
||||
|
||||
Blocks: |
||||
Enabled: false |
||||
|
||||
CaseEquality: |
||||
Enabled: false |
||||
|
||||
CharacterLiteral: |
||||
Enabled: false |
||||
|
||||
ClassAndModuleChildren: |
||||
Enabled: false |
||||
|
||||
ClassLength: |
||||
Enabled: false |
||||
|
||||
ClassVars: |
||||
Enabled: false |
||||
|
||||
CollectionMethods: |
||||
PreferredMethods: |
||||
find: detect |
||||
reduce: inject |
||||
collect: map |
||||
find_all: select |
||||
|
||||
ColonMethodCall: |
||||
Enabled: false |
||||
|
||||
CommentAnnotation: |
||||
Enabled: false |
||||
|
||||
CyclomaticComplexity: |
||||
Enabled: false |
||||
|
||||
Delegate: |
||||
Enabled: false |
||||
|
||||
DeprecatedHashMethods: |
||||
Enabled: false |
||||
|
||||
Documentation: |
||||
Enabled: false |
||||
|
||||
DotPosition: |
||||
EnforcedStyle: leading |
||||
|
||||
DoubleNegation: |
||||
Enabled: false |
||||
|
||||
EachWithObject: |
||||
Enabled: false |
||||
|
||||
EmptyLiteral: |
||||
Enabled: false |
||||
|
||||
Encoding: |
||||
Enabled: false |
||||
|
||||
EvenOdd: |
||||
Enabled: false |
||||
|
||||
FileName: |
||||
Enabled: false |
||||
|
||||
FlipFlop: |
||||
Enabled: false |
||||
|
||||
FormatString: |
||||
Enabled: false |
||||
|
||||
GlobalVars: |
||||
Enabled: false |
||||
|
||||
GuardClause: |
||||
Enabled: false |
||||
|
||||
IfUnlessModifier: |
||||
Enabled: false |
||||
|
||||
IfWithSemicolon: |
||||
Enabled: false |
||||
|
||||
InlineComment: |
||||
Enabled: false |
||||
|
||||
Lambda: |
||||
Enabled: false |
||||
|
||||
LambdaCall: |
||||
Enabled: false |
||||
|
||||
LineEndConcatenation: |
||||
Enabled: false |
||||
|
||||
LineLength: |
||||
Max: 99 |
||||
|
||||
MethodLength: |
||||
Enabled: false |
||||
|
||||
ModuleFunction: |
||||
Enabled: false |
||||
|
||||
NegatedIf: |
||||
Enabled: false |
||||
|
||||
NegatedWhile: |
||||
Enabled: false |
||||
|
||||
Next: |
||||
Enabled: false |
||||
|
||||
NilComparison: |
||||
Enabled: false |
||||
|
||||
Not: |
||||
Enabled: false |
||||
|
||||
NumericLiterals: |
||||
Enabled: false |
||||
|
||||
OneLineConditional: |
||||
Enabled: false |
||||
|
||||
OpMethod: |
||||
Enabled: false |
||||
|
||||
ParameterLists: |
||||
Enabled: false |
||||
|
||||
PercentLiteralDelimiters: |
||||
Enabled: false |
||||
|
||||
PerlBackrefs: |
||||
Enabled: false |
||||
|
||||
PredicateName: |
||||
NamePrefixBlacklist: |
||||
- is_ |
||||
|
||||
Proc: |
||||
Enabled: false |
||||
|
||||
RaiseArgs: |
||||
Enabled: false |
||||
|
||||
RegexpLiteral: |
||||
Enabled: false |
||||
|
||||
SelfAssignment: |
||||
Enabled: false |
||||
|
||||
SingleLineBlockParams: |
||||
Enabled: false |
||||
|
||||
SingleLineMethods: |
||||
Enabled: false |
||||
|
||||
SignalException: |
||||
Enabled: false |
||||
|
||||
SpecialGlobalVars: |
||||
Enabled: false |
||||
|
||||
StringLiterals: |
||||
EnforcedStyle: single_quotes |
||||
|
||||
VariableInterpolation: |
||||
Enabled: false |
||||
|
||||
TrailingComma: |
||||
Enabled: false |
||||
|
||||
TrivialAccessors: |
||||
Enabled: false |
||||
|
||||
VariableInterpolation: |
||||
Enabled: false |
||||
|
||||
WhenThen: |
||||
Enabled: false |
||||
|
||||
WhileUntilModifier: |
||||
Enabled: false |
||||
|
||||
WordArray: |
||||
Enabled: false |
||||
|
||||
# Lint |
||||
|
||||
AmbiguousOperator: |
||||
Enabled: false |
||||
|
||||
AmbiguousRegexpLiteral: |
||||
Enabled: false |
||||
|
||||
AssignmentInCondition: |
||||
Enabled: false |
||||
|
||||
ConditionPosition: |
||||
Enabled: false |
||||
|
||||
DeprecatedClassMethods: |
||||
Enabled: false |
||||
|
||||
ElseLayout: |
||||
Enabled: false |
||||
|
||||
HandleExceptions: |
||||
Enabled: false |
||||
|
||||
InvalidCharacterLiteral: |
||||
Enabled: false |
||||
|
||||
LiteralInCondition: |
||||
Enabled: false |
||||
|
||||
LiteralInInterpolation: |
||||
Enabled: false |
||||
|
||||
Loop: |
||||
Enabled: false |
||||
|
||||
ParenthesesAsGroupedExpression: |
||||
Enabled: false |
||||
|
||||
RequireParentheses: |
||||
Enabled: false |
||||
|
||||
UnderscorePrefixedVariableName: |
||||
Enabled: false |
||||
|
||||
Void: |
||||
Enabled: false |
||||
|
@ -1,12 +1,16 @@ |
||||
stage: |
||||
before: |
||||
- bower install --allow-root |
||||
- npm install -g npm |
||||
- cd frontend; |
||||
/usr/local/bin/npm install --unsafe-perm --ignore-scripts && |
||||
bower install --allow-root; |
||||
cd .. |
||||
- cp config/configuration.yml.example config/configuration.yml |
||||
- cp config/database.teatro.yml config/database.yml |
||||
- bundle exec rake generate_secret_token |
||||
- bundle exec rake generate_secret_token |
||||
|
||||
database: |
||||
- bundle exec rake db:create db:migrate |
||||
- bundle exec rake db:seed RAILS_ENV=development |
||||
|
||||
run: foreman start -c web=1,worker=1 |
||||
run: foreman start -f Procfile.dev |
||||
|
@ -0,0 +1,13 @@ |
||||
### Contributor Code of Conduct |
||||
|
||||
As contributors and maintainers of this project, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities. |
||||
|
||||
We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, age, or religion. |
||||
|
||||
Examples of unacceptable behavior by participants include the use of sexual language or imagery, derogatory comments or personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct. |
||||
|
||||
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. Project maintainers who do not follow the Code of Conduct may be removed from the project team. |
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers. |
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant](http:contributor-covenant.org), version 1.0.0, available at [http://contributor-covenant.org/version/1/0/0/](http://contributor-covenant.org/version/1/0/0/). By participating in this project you agree to abide by its terms. |
@ -1,7 +1,99 @@ |
||||
OpenProject is an open source project and we encourage you to help us out. We'd be happy if you do one of these things: |
||||
OpenProject is an open source project and we encourage you to help us out. For contributing to OpenProject, please read the following guidelines. |
||||
|
||||
* Create a [new work package on openproject.org](https://www.openproject.org/projects/openproject/work_packages) if you find a bug or need a feature |
||||
* Help out other people on our [forums](https://www.openproject.org/projects/openproject/boards) |
||||
* Help us [translate OpenProject to more languages](https://www.openproject.org/projects/openproject/wiki/Translations) |
||||
* Contribute code via GitHub Pull Requests, see our [contribution page](https://www.openproject.org/projects/openproject/wiki/Contribution) for more information |
||||
* See [Git Flow](https://www.openproject.org/projects/openproject/wiki/Git_Branching_Model) |
||||
*Please also note that these rules should be acknowledged by everyone, but repository contributors might occasionally deviate from them for practical purposes, e.g. not fork the repo, but have a branch on the main repository. This should however stay an exception.* |
||||
|
||||
## Contributors License Agreement |
||||
|
||||
External contributors have to sign a CLA before contributing to OpenProject. |
||||
The [CLA can be found here](https://www.openproject.org/wp-content/uploads/2014/09/OPF-Contributor-License-Agreement_v.2.pdf) and has to be filled out and sent to cla@openproject.org. Additionally, a GPG signature has to be provided. |
||||
|
||||
## Development flow |
||||
|
||||
For contributing source code, please follow the git workflow below: |
||||
|
||||
- **Fork** OpenProject on GitHub |
||||
- Clone your fork to your development machine: |
||||
|
||||
``` |
||||
git clone git@github.com/<username>/openproject |
||||
``` |
||||
|
||||
- Optional: Add the original OpenProject repository as a remote, so you can fetch changes: |
||||
|
||||
``` |
||||
git remote add upstream git@github.com:opf/openproject |
||||
``` |
||||
|
||||
- Make sure you're on the right branch. The main development branch is `dev`: |
||||
|
||||
``` |
||||
git checkout dev |
||||
``` |
||||
|
||||
- Create a feature branch: |
||||
|
||||
``` |
||||
git checkout -b feature/<short description of your feature> |
||||
``` |
||||
|
||||
- Make your changes, then push the branch into your ***own*** repository: |
||||
|
||||
``` |
||||
git push origin <your feature branch> |
||||
``` |
||||
|
||||
- Create a pull request against a branch of of the <opf/openproject> repository, containing a ***clear description*** of what the pull request attempts to change and/or fix. |
||||
|
||||
If your pull request **does not contain a description** for what it does and what it's intentions are, we will reject it. If you are working on a specific work package from the [list](https://community.openproject.org/projects/openproject/work_packages?query_props=%7B%22c%22:%5B%22type%22,%22status%22,%22subject%22,%22assigned_to%22%5D,%22t%22:%22parent:desc%22,%22f%22:%5B%7B%22n%22:%22status_id%22,%22o%22:%22!%22,%22t%22:%22list_status%22,%22v%22:%5B%2217%22,%2223%22,%223%22,%2214%22,%226%22%5D%7D%5D,%22pa%22:1,%22pp%22:20%7D), you may include a link to that work package in the description, so we can track your work. |
||||
|
||||
We will then review your pull request. Please note that you can add commits after the pull request has been created by pushing to the branch in your fork. |
||||
|
||||
## Important notes |
||||
|
||||
To ensure a smooth workflow for everyone, please take note of the following: |
||||
|
||||
### Testing |
||||
|
||||
Please add tests to your code to verify functionality, especially if it is a new feature. |
||||
|
||||
Pull requests will be verified by TravisCI as well, but please run them locally as well and make sure they are green before creating your pull request. We have a lot of pull requests coming in and it takes some time to run the complete suite for each one. |
||||
|
||||
### Branching model |
||||
|
||||
The main development branch for upcoming releases is `dev`. If in doubt, create your pull request against `dev`. All new features, gem updates and bugfixes for the upcoming release should go into the `dev` branch. |
||||
|
||||
#### Bugs and hotfixes |
||||
|
||||
Bugfixes for one of the actively supported versions of OpenProject should be issued against the respective branch. A fix for the current version (called "Hotfix" and the branch ideally being named `hotfix/XYZ`) should target `release/*` and a fix for the former version (called "Backport" and the branch ideally being named `backport/XYZ`) should target `backport/*`. We will try to merge hotfixes into dev branch but if that is no trivial task, we might ask you to create another PR for that. |
||||
|
||||
#### Travis CI |
||||
|
||||
If you push to your branch in quick sucession, please consider stopping the associated Travis builds, as Travis will run for each commit. This is especially true if you force push to the branch. |
||||
|
||||
Please also use `[ci skip]` in your commit message to suppress builds which are not necessary (e.g. after fixing a typo in the `README`). |
||||
|
||||
### Inactive pull requests |
||||
|
||||
We want to keep the Pull request list as cleaned up as possible - we will aim close pull requests after an **inactivity period of 72 hours** (no comments, no further pushes) which are not labelled as `work in progress` by us. |
||||
|
||||
### Issue tracking and coordination |
||||
|
||||
We use OpenProject for development coordination - please have a look at [the work packages list](https://community.openproject.org/projects/openproject/work_packages?query_props=%7B%22c%22:%5B%22type%22,%22status%22,%22subject%22,%22assigned_to%22%5D,%22t%22:%22parent:desc%22,%22f%22:%5B%7B%22n%22:%22status_id%22,%22o%22:%22!%22,%22t%22:%22list_status%22,%22v%22:%5B%2217%22,%2223%22,%223%22,%2214%22,%226%22%5D%7D%5D,%22pa%22:1,%22pp%22:20%7D) for upcoming features and reported bugs. |
||||
|
||||
### Contributor Code of Conduct |
||||
|
||||
As contributors and maintainers of this project, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities. |
||||
|
||||
We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, age, or religion. |
||||
|
||||
Examples of unacceptable behavior by participants include the use of sexual language or imagery, derogatory comments or personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct. |
||||
|
||||
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. Project maintainers who do not follow the Code of Conduct may be removed from the project team. |
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers. |
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant](http:contributor-covenant.org), version 1.0.0, available at [http://contributor-covenant.org/version/1/0/0/](http://contributor-covenant.org/version/1/0/0/) |
||||
|
||||
### Get in touch |
||||
|
||||
If you want to get in touch with us, there is also a [Gitter channel](https://gitter.im/opf/openproject) to talk to us directly. |
||||
|
@ -0,0 +1,3 @@ |
||||
web: bundle exec unicorn --config-file config/unicorn.rb --host ${HOST:="127.0.0.1"} --port ${PORT:="8080"} --env ${RAILS_ENV:="development"} |
||||
assets: cd frontend && $(npm bin)/webpack --colors --watch --progress |
||||
worker: bundle exec rake jobs:work |
Before Width: | Height: | Size: 156 KiB |
Before Width: | Height: | Size: 160 KiB |
Before Width: | Height: | Size: 159 KiB |
Before Width: | Height: | Size: 154 KiB |
Before Width: | Height: | Size: 159 KiB |
Before Width: | Height: | Size: 155 KiB |
Before Width: | Height: | Size: 83 KiB After Width: | Height: | Size: 85 KiB |
After Width: | Height: | Size: 4.3 KiB |
After Width: | Height: | Size: 4.3 KiB |
After Width: | Height: | Size: 4.3 KiB |
After Width: | Height: | Size: 4.3 KiB |
After Width: | Height: | Size: 4.3 KiB |
After Width: | Height: | Size: 1.8 KiB |
After Width: | Height: | Size: 18 KiB |
@ -1,87 +0,0 @@ |
||||
//-- copyright
|
||||
// OpenProject is a project management system.
|
||||
// Copyright (C) 2012-2014 the OpenProject Foundation (OPF)
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License version 3.
|
||||
//
|
||||
// OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
|
||||
// Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
// Copyright (C) 2010-2013 the ChiliProject Team
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 2
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
// See doc/COPYRIGHT.rdoc for more details.
|
||||
//++
|
||||
|
||||
module.exports = function($log) { |
||||
|
||||
return { |
||||
settingsPresent: function() { |
||||
return gon && gon.settings; |
||||
}, |
||||
userPreferencesPresent: function() { |
||||
return this.settingsPresent() && gon.settings.hasOwnProperty('user_preferences'); |
||||
}, |
||||
displaySettingsPresent: function() { |
||||
return this.settingsPresent() && gon.settings.hasOwnProperty('display'); |
||||
}, |
||||
displaySettingPresent: function(setting) { |
||||
return this.displaySettingsPresent() |
||||
&& gon.settings.display.hasOwnProperty(setting) |
||||
&& gon.settings.display[setting] != false; |
||||
}, |
||||
accessibilityModeEnabled: function() { |
||||
if (!this.userPreferencesPresent()) { |
||||
$log.error('User preferences are not available.'); |
||||
return false; |
||||
} else { |
||||
return gon.settings.user_preferences.impaired; |
||||
} |
||||
}, |
||||
commentsSortedInDescendingOrder: function() { |
||||
if (!this.userPreferencesPresent()) { |
||||
$log.error('User preferences are not available.'); |
||||
return false; |
||||
} else { |
||||
return gon.settings.user_preferences.others.comments_sorting === 'desc'; |
||||
} |
||||
}, |
||||
isTimezoneSet: function() { |
||||
return this.userPreferencesPresent() && gon.settings.user_preferences.time_zone != ''; |
||||
}, |
||||
timezone: function() { |
||||
return (this.isTimezoneSet()) ? gon.settings.user_preferences.time_zone : ''; |
||||
}, |
||||
dateFormatPresent: function() { |
||||
return this.displaySettingPresent('date_format'); |
||||
}, |
||||
dateFormat: function() { |
||||
return gon.settings.display.date_format; |
||||
}, |
||||
timeFormatPresent: function() { |
||||
return this.displaySettingPresent('time_format'); |
||||
}, |
||||
timeFormat: function() { |
||||
return gon.settings.display.time_format; |
||||
}, |
||||
enabledModulesPresent: function() { |
||||
return this.settingsPresent() && gon.settings.hasOwnProperty('enabled_modules'); |
||||
}, |
||||
isModuleEnabled: function(module) { |
||||
return gon.settings.enabled_modules.indexOf(module) >= 0; |
||||
}, |
||||
}; |
||||
}; |
@ -1,79 +0,0 @@ |
||||
//-- copyright
|
||||
// OpenProject is a project management system.
|
||||
// Copyright (C) 2012-2014 the OpenProject Foundation (OPF)
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License version 3.
|
||||
//
|
||||
// OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
|
||||
// Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
// Copyright (C) 2010-2013 the ChiliProject Team
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 2
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
// See doc/COPYRIGHT.rdoc for more details.
|
||||
//++
|
||||
|
||||
module.exports = function(TimelineTableHelper) { |
||||
|
||||
return { |
||||
restrict: 'E', |
||||
replace: true, |
||||
templateUrl: '/templates/timelines/toolbar.html', |
||||
link: function(scope) { |
||||
scope.currentScaleName = 'monthly'; |
||||
|
||||
scope.updateToolbar = function() { |
||||
scope.slider.slider('value', scope.timeline.zoomIndex + 1); |
||||
scope.currentOutlineLevel = Timeline.OUTLINE_LEVELS[scope.timeline.expansionIndex]; |
||||
scope.currentScaleName = Timeline.ZOOM_SCALES[scope.timeline.zoomIndex]; |
||||
}; |
||||
|
||||
scope.increaseZoom = function() { |
||||
if(scope.currentScaleIndex < Object.keys(Timeline.ZOOM_CONFIGURATIONS).length - 1) { |
||||
scope.currentScaleIndex++; |
||||
} |
||||
}; |
||||
scope.decreaseZoom = function() { |
||||
if(scope.currentScaleIndex > 0) { |
||||
scope.currentScaleIndex--; |
||||
} |
||||
}; |
||||
scope.resetOutline = function(){ |
||||
scope.timeline.expandTo(0); |
||||
}; |
||||
|
||||
scope.$watch('currentScaleName', function(newScaleName, oldScaleName){ |
||||
if (newScaleName !== oldScaleName) { |
||||
scope.currentScale = Timeline.ZOOM_CONFIGURATIONS[scope.currentScaleName].scale; |
||||
scope.timeline.scale = scope.currentScale; |
||||
|
||||
scope.currentScaleIndex = Timeline.ZOOM_SCALES.indexOf(scope.currentScaleName); |
||||
scope.slider.slider('value', scope.currentScaleIndex + 1); |
||||
|
||||
scope.timeline.zoom(scope.currentScaleIndex); // TODO replace event-driven adaption by bindings
|
||||
} |
||||
}); |
||||
|
||||
scope.$watch('currentOutlineLevel', function(outlineLevel, formerLevel) { |
||||
if (outlineLevel !== formerLevel) { |
||||
scope.timeline.expansionIndex = Timeline.OUTLINE_LEVELS.indexOf(outlineLevel); |
||||
scope.timeline.expandToOutlineLevel(outlineLevel); // TODO replace event-driven adaption by bindings
|
||||
TimelineTableHelper.setRowLevelVisibility(scope.rows, scope.timeline.expansionIndex); |
||||
} |
||||
}); |
||||
} |
||||
}; |
||||
} |
@ -1,170 +0,0 @@ |
||||
//-- copyright
|
||||
// OpenProject is a project management system.
|
||||
// Copyright (C) 2012-2014 the OpenProject Foundation (OPF)
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License version 3.
|
||||
//
|
||||
// OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
|
||||
// Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
// Copyright (C) 2010-2013 the ChiliProject Team
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 2
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
// See doc/COPYRIGHT.rdoc for more details.
|
||||
//++
|
||||
|
||||
module.exports = function($injector, $window, $parse) { |
||||
|
||||
function getCssPositionProperties(dropdown, trigger) { |
||||
var hOffset = 0, |
||||
vOffset = 0; |
||||
|
||||
// Styling logic taken from jQuery-dropdown plugin: https://github.com/plapier/jquery-dropdown
|
||||
// (dual MIT/GPL-Licensed)
|
||||
|
||||
// Position the dropdown relative-to-parent or relative-to-document
|
||||
if (dropdown.hasClass('dropdown-relative')) { |
||||
return { |
||||
left: dropdown.hasClass('dropdown-anchor-right') ? |
||||
trigger.position().left - (dropdown.outerWidth(true) - trigger.outerWidth(true)) - parseInt(trigger.css('margin-right')) + hOffset : |
||||
trigger.position().left + parseInt(trigger.css('margin-left')) + hOffset, |
||||
top: trigger.position().top + trigger.outerHeight(true) - parseInt(trigger.css('margin-top')) + vOffset |
||||
}; |
||||
} else { |
||||
return { |
||||
left: dropdown.hasClass('dropdown-anchor-right') ? |
||||
trigger.offset().left - (dropdown.outerWidth() - trigger.outerWidth()) + hOffset : trigger.offset().left + hOffset, |
||||
top: trigger.offset().top + trigger.outerHeight() + vOffset |
||||
}; |
||||
} |
||||
} |
||||
|
||||
return { |
||||
restrict: 'A', |
||||
controller: [function() { |
||||
var dropDownMenuOpened = false; |
||||
|
||||
this.open = function() { |
||||
dropDownMenuOpened = true; |
||||
}; |
||||
this.close = function() { |
||||
dropDownMenuOpened = false; |
||||
}; |
||||
this.opened = function() { |
||||
return dropDownMenuOpened; |
||||
}; |
||||
}], |
||||
link: function(scope, element, attrs, ctrl) { |
||||
var contextMenu = $injector.get(attrs.target), |
||||
locals = {}, |
||||
win = angular.element($window), |
||||
menuElement, |
||||
positionRelativeTo = attrs.positionRelativeTo, |
||||
triggerOnEvent = attrs.triggerOnEvent || 'click'; |
||||
|
||||
/* contextMenu is a mandatory attribute and used to bind a specific context |
||||
menu to the trigger event |
||||
triggerOnEvent allows for binding the event for opening the menu to "click" */ |
||||
|
||||
// prepare locals, these define properties to be passed on to the context menu scope
|
||||
var localKeys = attrs.locals.split(',').map(function(local) { |
||||
return local.trim(); |
||||
}); |
||||
angular.forEach(localKeys, function(key) { |
||||
locals[key] = scope[key]; |
||||
}); |
||||
|
||||
function toggle(event) { |
||||
active() ? close() : open(event); |
||||
} |
||||
|
||||
function active() { |
||||
return contextMenu.active() && ctrl.opened(); |
||||
} |
||||
|
||||
function open(event) { |
||||
ctrl.open(); |
||||
|
||||
contextMenu.open(event.target, locals) |
||||
.then(function(element) { |
||||
menuElement = element; |
||||
angular.element(element).trap(); |
||||
}); |
||||
} |
||||
|
||||
function close() { |
||||
ctrl.close(); |
||||
|
||||
contextMenu.close(); |
||||
} |
||||
|
||||
function positionDropdown() { |
||||
var positionRelativeToElement = positionRelativeTo ? |
||||
element.find(positionRelativeTo) : element; |
||||
|
||||
menuElement.css(getCssPositionProperties(menuElement, positionRelativeToElement)); |
||||
} |
||||
|
||||
element.bind(triggerOnEvent, function(event) { |
||||
event.preventDefault(); |
||||
event.stopPropagation(); |
||||
|
||||
scope.$apply(function() { |
||||
toggle(event); |
||||
}); |
||||
|
||||
// set css position parameters after the digest has been completed
|
||||
if (contextMenu.active()) positionDropdown(); |
||||
|
||||
scope.$root.$broadcast('openproject.markDropdownsAsClosed', element); |
||||
}); |
||||
|
||||
scope.$on('openproject.markDropdownsAsClosed', function(event, target) { |
||||
if (element !== target && ctrl.opened()) { |
||||
scope.$apply(ctrl.close); |
||||
} |
||||
}); |
||||
|
||||
win.on('resize', function(event) { |
||||
if (contextMenu.active() && menuElement && ctrl.opened()) { |
||||
positionDropdown(); |
||||
} |
||||
}); |
||||
|
||||
win.bind('keyup', function(event) { |
||||
if (contextMenu.active() && event.keyCode === 27) { |
||||
scope.$apply(function() { |
||||
close(); |
||||
}); |
||||
} |
||||
}); |
||||
|
||||
function handleWindowClickEvent(event) { |
||||
if (contextMenu.active() && event.button !== 2) { |
||||
|
||||
scope.$apply(function() { |
||||
close(); |
||||
}); |
||||
} |
||||
} |
||||
|
||||
// Firefox treats a right-click as a click and a contextmenu event while other browsers
|
||||
// just treat it as a contextmenu event
|
||||
win.bind('click', handleWindowClickEvent); |
||||
win.bind(triggerOnEvent, handleWindowClickEvent); |
||||
} |
||||
}; |
||||
} |
@ -1,158 +0,0 @@ |
||||
//-- copyright
|
||||
// OpenProject is a project management system.
|
||||
// Copyright (C) 2012-2014 the OpenProject Foundation (OPF)
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License version 3.
|
||||
//
|
||||
// OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
|
||||
// Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
// Copyright (C) 2010-2013 the ChiliProject Team
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 2
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
// See doc/COPYRIGHT.rdoc for more details.
|
||||
//++
|
||||
|
||||
module.exports = function($timeout) { |
||||
return { |
||||
restrict: 'A', |
||||
transclude: false, |
||||
templateUrl: "/templates/components/inplace_editor.html", |
||||
scope: { |
||||
type: "@inedType", |
||||
entity: "=inedEntity", |
||||
attribute: "@inedAttribute" |
||||
}, |
||||
link: link, |
||||
controller: Controller |
||||
}; |
||||
|
||||
function link(scope, element, attrs) { |
||||
element.on("click", ".ined-read-value", function() { |
||||
scope.$apply(function() { |
||||
scope.startEditing(); |
||||
}); |
||||
}); |
||||
element.bind("keydown keypress", function(e) { |
||||
if (e.keyCode == 27) { |
||||
scope.$apply(function() { |
||||
scope.discardEditing(); |
||||
}); |
||||
} |
||||
}); |
||||
|
||||
scope.$on('startEditing', function() { |
||||
$timeout(function() { |
||||
element.find(".ined-input-wrapper input, .ined-input-wrapper textarea").focus(); |
||||
}); |
||||
}); |
||||
scope.$on('finishEditing', function() { |
||||
$timeout(function() { |
||||
element.find(".ined-read-value a").focus(); |
||||
}); |
||||
}); |
||||
} |
||||
|
||||
Controller.$inject = ['$scope', 'WorkPackageService', 'ApiHelper']; |
||||
function Controller($scope, WorkPackageService, ApiHelper) { |
||||
$scope.isEditing = false; |
||||
$scope.isBusy = false; |
||||
$scope.readValue = ""; |
||||
$scope.editTitle = I18n.t('js.inplace.button_edit'); |
||||
$scope.saveTitle = I18n.t('js.inplace.button_save'); |
||||
$scope.saveAndSendTitle = I18n.t('js.inplace.button_save_and_send'); |
||||
$scope.cancelTitle = I18n.t('js.inplace.button_cancel'); |
||||
$scope.error = null; |
||||
|
||||
$scope.startEditing = startEditing; |
||||
$scope.discardEditing = discardEditing; |
||||
$scope.submit = submit; |
||||
$scope.onSuccess = onSuccess; |
||||
$scope.onFail = onFail; |
||||
$scope.onFinally = onFinally; |
||||
|
||||
activate(); |
||||
|
||||
function activate() { |
||||
// ng-model works weird with isolated scope
|
||||
// also it's better to make an intermediate container
|
||||
// to avoid live editing
|
||||
setWriteValue(); |
||||
setReadValue(); |
||||
} |
||||
|
||||
function startEditing() { |
||||
setWriteValue(); |
||||
$scope.isEditing = true; |
||||
$scope.error = null; |
||||
$scope.isBusy = false; |
||||
$scope.$broadcast('startEditing'); |
||||
} |
||||
|
||||
function submit(withEmail) { |
||||
var data = {}; |
||||
data[$scope.attribute] = $scope.dataObject.value; |
||||
data.lockVersion = $scope.entity.props.lockVersion; |
||||
$scope.isBusy = true; |
||||
var result = WorkPackageService.updateWorkPackage($scope.entity, data); |
||||
result.then(function(workPackage) { |
||||
$scope.onSuccess(workPackage); |
||||
}); |
||||
result.catch(function(e) { |
||||
$scope.onFail(e); |
||||
}); |
||||
result.finally(function() { |
||||
$scope.onFinally(); |
||||
}); |
||||
} |
||||
|
||||
function onSuccess(workPackage) { |
||||
angular.extend($scope.entity, workPackage); |
||||
$scope.dataObject.value = $scope.entity.props[$scope.attribute]; |
||||
$scope.error = null; |
||||
setReadValue(); |
||||
finishEditing(); |
||||
$scope.$emit("workPackageRefreshRequired"); |
||||
} |
||||
|
||||
function onFail(e) { |
||||
$scope.error = ApiHelper.getErrorMessage(e); |
||||
} |
||||
|
||||
function onFinally() { |
||||
$scope.isBusy = false; |
||||
} |
||||
|
||||
function discardEditing() { |
||||
finishEditing(); |
||||
} |
||||
|
||||
function finishEditing() { |
||||
$scope.isEditing = false; |
||||
$scope.$broadcast('finishEditing'); |
||||
} |
||||
|
||||
function setWriteValue() { |
||||
$scope.dataObject = { |
||||
value: $scope.entity.props[$scope.attribute] |
||||
}; |
||||
} |
||||
|
||||
function setReadValue() { |
||||
$scope.readValue = $scope.dataObject.value; |
||||
} |
||||
} |
||||
}; |
@ -1,237 +0,0 @@ |
||||
//-- copyright
|
||||
// OpenProject is a project management system.
|
||||
// Copyright (C) 2012-2014 the OpenProject Foundation (OPF)
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License version 3.
|
||||
//
|
||||
// OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
|
||||
// Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
// Copyright (C) 2010-2013 the ChiliProject Team
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 2
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
// See doc/COPYRIGHT.rdoc for more details.
|
||||
//++
|
||||
|
||||
// TODO move to UI components
|
||||
module.exports = function($sce, LABEL_MAX_CHARS, KEY_CODES) { |
||||
return { |
||||
restrict: 'E', |
||||
replace: true, |
||||
scope: { |
||||
selectedTitle: '=', |
||||
groups: '=', |
||||
transitionMethod: '=' |
||||
}, |
||||
templateUrl: '/templates/components/selectable_title.html', |
||||
link: function(scope) { |
||||
scope.$watch('groups', refreshFilteredGroups); |
||||
scope.$watch('selectedId', selectTitle); |
||||
|
||||
function refreshFilteredGroups() { |
||||
if(scope.groups){ |
||||
initFilteredModels(); |
||||
} |
||||
} |
||||
|
||||
function selectTitle() { |
||||
angular.forEach(scope.filteredGroups, function(group) { |
||||
if(group.models.length) { |
||||
angular.forEach(group.models, function(model){ |
||||
model.highlighted = model.id == scope.selectedId; |
||||
}); |
||||
} |
||||
}); |
||||
} |
||||
|
||||
function initFilteredModels() { |
||||
scope.filteredGroups = angular.copy(scope.groups); |
||||
angular.forEach(scope.filteredGroups, function(group) { |
||||
group.models = group.models.map(function(model){ |
||||
return { |
||||
label: model[0], |
||||
labelHtml: $sce.trustAsHtml(truncate(model[0], LABEL_MAX_CHARS)), |
||||
id: model[1], |
||||
highlighted: false |
||||
} |
||||
}); |
||||
}); |
||||
} |
||||
|
||||
function labelHtml(label, filterBy) { |
||||
filterBy = filterBy.toLowerCase(); |
||||
label = truncate(label, LABEL_MAX_CHARS); |
||||
if(label.toLowerCase().indexOf(filterBy) >= 0) { |
||||
var labelHtml = label.substr(0, label.toLowerCase().indexOf(filterBy)) |
||||
+ "<span class='filter-selection'>" + label.substr(label.toLowerCase().indexOf(filterBy), filterBy.length) + "</span>" |
||||
+ label.substr(label.toLowerCase().indexOf(filterBy) + filterBy.length); |
||||
} else { |
||||
var labelHtml = label; |
||||
} |
||||
return $sce.trustAsHtml(labelHtml); |
||||
} |
||||
|
||||
function truncate(text, chars) { |
||||
if (text.length > chars) { |
||||
return text.substr(0, chars) + "..."; |
||||
} |
||||
return text; |
||||
} |
||||
|
||||
function modelIndex(models) { |
||||
return models.map(function(model){ |
||||
return model.id; |
||||
}).indexOf(scope.selectedId); |
||||
} |
||||
|
||||
function performSelect() { |
||||
scope.transitionMethod(scope.selectedId); |
||||
} |
||||
|
||||
function nextNonEmptyGroup(groups, currentGroupIndex) { |
||||
currentGroupIndex = (currentGroupIndex == undefined) ? -1 : currentGroupIndex; |
||||
while(currentGroupIndex < groups.length - 1) { |
||||
if(groups[currentGroupIndex + 1].models.length) { |
||||
return groups[currentGroupIndex + 1]; |
||||
} |
||||
currentGroupIndex = currentGroupIndex + 1; |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
function previousNonEmptyGroup(groups, currentGroupIndex) { |
||||
while(currentGroupIndex > 0) { |
||||
if(groups[currentGroupIndex - 1].models.length) { |
||||
return groups[currentGroupIndex - 1]; |
||||
} |
||||
currentGroupIndex = currentGroupIndex - 1; |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
function getModelPosition(groups, selectedId) { |
||||
for(var group_index = 0; group_index < groups.length; group_index++) { |
||||
var models = groups[group_index].models; |
||||
var model_index = modelIndex(models); |
||||
if(model_index >= 0) { |
||||
return { |
||||
group: group_index, |
||||
model: model_index |
||||
}; |
||||
} |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
function selectNext() { |
||||
var groups = scope.filteredGroups; |
||||
if(!scope.selectedId) { |
||||
var nextGroup = nextNonEmptyGroup(groups); |
||||
scope.selectedId = nextGroup ? nextGroup.models[0].id : 0; |
||||
} else { |
||||
var position = getModelPosition(groups, scope.selectedId); |
||||
if (!position) return; |
||||
var models = groups[position.group].models; |
||||
|
||||
if(position.model == models.length - 1){ // It is the last in the group
|
||||
var nextGroup = nextNonEmptyGroup(groups, position.group); |
||||
if(nextGroup) { |
||||
scope.selectedId = nextGroup.models[0].id; |
||||
} |
||||
} else { |
||||
scope.selectedId = models[position.model + 1].id; |
||||
} |
||||
} |
||||
} |
||||
|
||||
function selectPrevious() { |
||||
var groups = scope.filteredGroups; |
||||
if(scope.selectedId) { |
||||
var position = getModelPosition(groups, scope.selectedId); |
||||
if (!position) return; |
||||
var models = groups[position.group].models; |
||||
|
||||
if(position.model == 0){ // It is the last in the group
|
||||
var previousGroup = previousNonEmptyGroup(groups, position.group); |
||||
if(previousGroup) { |
||||
scope.selectedId = previousGroup.models[previousGroup.models.length - 1].id; |
||||
} |
||||
} else { |
||||
scope.selectedId = models[position.model - 1].id; |
||||
} |
||||
} |
||||
} |
||||
|
||||
function preventDefault(event) { |
||||
event.preventDefault(); |
||||
event.stopPropagation(); |
||||
} |
||||
|
||||
angular.element('#title-filter').bind('click', function(event) { |
||||
preventDefault(event); |
||||
}); |
||||
|
||||
scope.handleSelection = function(event) { |
||||
switch(event.which) { |
||||
case KEY_CODES.enter: |
||||
performSelect(); |
||||
preventDefault(event); |
||||
break; |
||||
case KEY_CODES.down: |
||||
selectNext(); |
||||
preventDefault(event); |
||||
break; |
||||
case KEY_CODES.up: |
||||
selectPrevious(); |
||||
preventDefault(event); |
||||
break; |
||||
default: |
||||
break; |
||||
} |
||||
}; |
||||
|
||||
scope.reload = function(modelId, newTitle) { |
||||
scope.selectedTitle = newTitle; |
||||
scope.reloadMethod(modelId); |
||||
scope.$emit('hideAllDropdowns'); |
||||
}; |
||||
|
||||
scope.filterModels = function(filterBy) { |
||||
initFilteredModels(); |
||||
|
||||
scope.selectedId = 0; |
||||
angular.forEach(scope.filteredGroups, function(group) { |
||||
if(filterBy.length) { |
||||
group.filterBy = filterBy; |
||||
group.models = group.models.filter(function(model){ |
||||
return model.label.toLowerCase().indexOf(filterBy.toLowerCase()) >= 0; |
||||
}); |
||||
|
||||
if(group.models.length) { |
||||
angular.forEach(group.models, function(model){ |
||||
model['labelHtml'] = labelHtml(model.label, filterBy); |
||||
}); |
||||
if(!scope.selectedId) { |
||||
group.models[0].highlighted = true; |
||||
scope.selectedId = group.models[0].id; |
||||
} |
||||
} |
||||
} |
||||
}); |
||||
}; |
||||
} |
||||
}; |
||||
} |
@ -1,126 +0,0 @@ |
||||
//-- copyright
|
||||
// OpenProject is a project management system.
|
||||
// Copyright (C) 2012-2014 the OpenProject Foundation (OPF)
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License version 3.
|
||||
//
|
||||
// OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
|
||||
// Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
// Copyright (C) 2010-2013 the ChiliProject Team
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 2
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
// See doc/COPYRIGHT.rdoc for more details.
|
||||
//++
|
||||
|
||||
// TODO move to UI components
|
||||
module.exports = function ($rootScope, $window, ESC_KEY, FocusHelper) { |
||||
|
||||
function position(dropdown, trigger) { |
||||
var hOffset = 0, |
||||
vOffset = 0; |
||||
|
||||
if( dropdown.length === 0 || !trigger ) return; |
||||
|
||||
// Styling logic taken from jQuery-dropdown plugin: https://github.com/plapier/jquery-dropdown
|
||||
// (dual MIT/GPL-Licensed)
|
||||
|
||||
// Position the dropdown relative-to-parent or relative-to-document
|
||||
if (dropdown.hasClass('dropdown-relative')) { |
||||
leftPosition = dropdown.hasClass('dropdown-anchor-right') ? |
||||
trigger.position().left - (dropdown.outerWidth(true) - trigger.outerWidth(true)) - parseInt(trigger.css('margin-right')) + hOffset : |
||||
trigger.position().left + parseInt(trigger.css('margin-left')) + hOffset; |
||||
|
||||
if (dropdown.hasClass('dropdown-up')) { |
||||
var dropdownHeight = dropdown.outerHeight(true); |
||||
|
||||
dropdown.css({ |
||||
left: leftPosition, |
||||
top: trigger.position().top - dropdownHeight + parseInt(trigger.css('margin-top')) - vOffset |
||||
}); |
||||
} else { |
||||
dropdown.css({ |
||||
left: leftPosition, |
||||
top: trigger.position().top + trigger.outerHeight(true) - parseInt(trigger.css('margin-top')) + vOffset |
||||
}); |
||||
} |
||||
} else { |
||||
dropdown.css({ |
||||
left: dropdown.hasClass('dropdown-anchor-right') ? |
||||
trigger.offset().left - (dropdown.outerWidth() - trigger.outerWidth()) + hOffset : trigger.offset().left + hOffset, |
||||
top: trigger.offset().top + trigger.outerHeight() + vOffset |
||||
}); |
||||
} |
||||
} |
||||
|
||||
function accessDropdown(dropdown) { |
||||
var links = dropdown.find('a'); |
||||
|
||||
if (links.length > 0) { |
||||
angular.element(links[0]).focus(); |
||||
} |
||||
|
||||
angular.element(dropdown).trap(); |
||||
} |
||||
|
||||
return { |
||||
restrict: 'EA', |
||||
scope: { |
||||
dropdownId: '@', |
||||
focusElementId: '@' |
||||
}, |
||||
link: function (scope, element, attributes) { |
||||
var dropdown = jQuery("#" + attributes.dropdownId), |
||||
trigger; |
||||
|
||||
$rootScope.$on('hideAllDropdowns', function(event){ |
||||
jQuery('.dropdown').hide(); |
||||
}); |
||||
|
||||
angular.element($window).on('resize', function(event) { |
||||
if(dropdown.is(':visible')) { |
||||
position(dropdown, trigger); |
||||
} |
||||
}); |
||||
|
||||
element.on('click', function (event) { |
||||
var showDropdown = dropdown.is(':hidden'); |
||||
|
||||
trigger = jQuery(this); |
||||
|
||||
event.preventDefault(); |
||||
event.stopPropagation(); |
||||
|
||||
scope.$emit('hideAllDropdowns'); |
||||
if (showDropdown) dropdown.show(); |
||||
|
||||
position(dropdown, trigger); |
||||
accessDropdown(dropdown); |
||||
|
||||
if(attributes.focusElementId) { |
||||
angular.element('#' + attributes.focusElementId).focus(); |
||||
} |
||||
}); |
||||
|
||||
angular.element(dropdown).on('keyup', function(event) { |
||||
if (event.keyCode === ESC_KEY) { |
||||
scope.$emit('hideAllDropdowns'); |
||||
FocusHelper.focusElement(element); |
||||
} |
||||
}); |
||||
} |
||||
}; |
||||
} |
@ -1,77 +0,0 @@ |
||||
//-- copyright
|
||||
// OpenProject is a project management system.
|
||||
// Copyright (C) 2012-2014 the OpenProject Foundation (OPF)
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License version 3.
|
||||
//
|
||||
// OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
|
||||
// Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
// Copyright (C) 2010-2013 the ChiliProject Team
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 2
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
// See doc/COPYRIGHT.rdoc for more details.
|
||||
//++
|
||||
|
||||
module.exports = function(I18n) { |
||||
|
||||
function makeSliderAccessible(slider) { |
||||
var defaultLabel = angular.element('<span class="hidden-for-sighted">'); |
||||
var sliderLabel = defaultLabel.text(I18n.t('js.timelines.zoom.slider')); |
||||
var sliderHandle = slider.find('a.ui-slider-handle'); |
||||
|
||||
sliderHandle.append(sliderLabel); |
||||
} |
||||
|
||||
// TODO pass options to directive and do not refer to timelines
|
||||
return { |
||||
restrict: 'A', |
||||
link: function(scope, element, attributes) { |
||||
scope.currentScaleIndex = Timeline.ZOOM_SCALES.indexOf(scope.currentScaleName); |
||||
scope.slider = element.slider({ |
||||
min: 1, |
||||
max: Timeline.ZOOM_SCALES.length, |
||||
range: 'min', |
||||
value: scope.currentScaleIndex + 1, |
||||
slide: function(event, ui) { |
||||
scope.currentScaleIndex = ui.value - 1; |
||||
scope.$apply(); |
||||
}, |
||||
change: function(event, ui) { |
||||
scope.currentScaleIndex = ui.value - 1; |
||||
} |
||||
}).css({ |
||||
// top right bottom left
|
||||
'margin': '4px 6px 3px' |
||||
}); |
||||
|
||||
// Slider
|
||||
// TODO integrate angular-ui-slider
|
||||
|
||||
makeSliderAccessible(scope.slider); |
||||
|
||||
scope.$watch('currentScaleIndex', function(newIndex){ |
||||
scope.currentScaleIndex = newIndex; |
||||
|
||||
newScaleName = Timeline.ZOOM_SCALES[newIndex]; |
||||
if (scope.currentScaleName !== newScaleName) { |
||||
scope.currentScaleName = newScaleName; |
||||
} |
||||
}); |
||||
|
||||
} |
||||
}; |
||||
} |
@ -1,200 +0,0 @@ |
||||
//-- copyright
|
||||
// OpenProject is a project management system.
|
||||
// Copyright (C) 2012-2014 the OpenProject Foundation (OPF)
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License version 3.
|
||||
//
|
||||
// OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
|
||||
// Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
// Copyright (C) 2010-2013 the ChiliProject Team
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 2
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
// See doc/COPYRIGHT.rdoc for more details.
|
||||
//++
|
||||
|
||||
module.exports = function($scope, |
||||
I18n, |
||||
WorkPackagesOverviewService, |
||||
TEXT_TYPE, |
||||
VERSION_TYPE, |
||||
CATEGORY_TYPE, |
||||
USER_TYPE, |
||||
USER_FIELDS, |
||||
CustomFieldHelper, |
||||
WorkPackagesHelper, |
||||
PathHelper, |
||||
UserService, |
||||
HookService, |
||||
$q) { |
||||
|
||||
// work package properties
|
||||
|
||||
$scope.userPath = PathHelper.staticUserPath; |
||||
|
||||
function getPropertyValue(property, format) { |
||||
switch(format) { |
||||
case VERSION_TYPE: |
||||
if ($scope.workPackage.props.versionId == undefined) { |
||||
return; |
||||
} |
||||
var versionId = $scope.workPackage.props.versionId, |
||||
versionLinkPresent = !!$scope.workPackage.links.version; |
||||
var versionTitle = versionLinkPresent ? $scope.workPackage.links.version.props.title : $scope.workPackage.props.versionName, |
||||
versionHref = versionLinkPresent ? $scope.workPackage.links.version.href : null; |
||||
return {href: versionHref, title: versionTitle, viewable: versionLinkPresent}; |
||||
break; |
||||
case USER_TYPE: |
||||
return $scope.workPackage.embedded[property]; |
||||
break; |
||||
case CATEGORY_TYPE: |
||||
return $scope.workPackage.embedded[property]; |
||||
break; |
||||
default: |
||||
return getFormattedPropertyValue(property); |
||||
} |
||||
} |
||||
|
||||
function getFormattedPropertyValue(property) { |
||||
if (property === 'date') { |
||||
return getDateProperty(); |
||||
} else { |
||||
return WorkPackagesHelper.formatWorkPackageProperty($scope.workPackage.props[property], property); |
||||
} |
||||
} |
||||
|
||||
function getDateProperty() { |
||||
if ($scope.workPackage.props.startDate || $scope.workPackage.props.dueDate) { |
||||
var displayedStartDate = WorkPackagesHelper.formatWorkPackageProperty($scope.workPackage.props.startDate, 'startDate') || I18n.t('js.label_no_start_date'), |
||||
displayedEndDate = WorkPackagesHelper.formatWorkPackageProperty($scope.workPackage.props.dueDate, 'dueDate') || I18n.t('js.label_no_due_date'); |
||||
|
||||
return displayedStartDate + ' - ' + displayedEndDate; |
||||
} |
||||
} |
||||
|
||||
$scope.groupedAttributes = WorkPackagesOverviewService.getGroupedWorkPackageOverviewAttributes(); |
||||
|
||||
(function setupWorkPackageProperties() { |
||||
var otherAttributes = WorkPackagesOverviewService.getGroupAttributesForGroupedAttributes('other', $scope.groupedAttributes); |
||||
|
||||
angular.forEach($scope.workPackage.props.customProperties, function(customProperty) { |
||||
this.push(customProperty); |
||||
}, otherAttributes); |
||||
|
||||
angular.forEach($scope.groupedAttributes, function(group) { |
||||
var attributesWithValues = []; |
||||
|
||||
angular.forEach(group.attributes, function(attribute) { |
||||
if (typeof attribute == 'string') { |
||||
this.push(getWorkPackageProperty(attribute)); |
||||
} else { |
||||
this.push(getWorkPackageCustomProperty(attribute)); |
||||
} |
||||
}, attributesWithValues); |
||||
|
||||
group.attributes = attributesWithValues; |
||||
}); |
||||
|
||||
// The loops before overwrite the attributes array of group 'other'. Thus,
|
||||
// to get the current values of that array, I need to get that array again.
|
||||
otherAttributes = WorkPackagesOverviewService.getGroupAttributesForGroupedAttributes('other', $scope.groupedAttributes); |
||||
// Sorting the 'other' group is an acutal requirement. So, check if the
|
||||
// requirement has changed before removing this code!
|
||||
otherAttributes.sort(function(a, b) { |
||||
return a.label.toLowerCase().localeCompare(b.label.toLowerCase()); |
||||
}); |
||||
})(); |
||||
|
||||
function getWorkPackageProperty(property) { |
||||
var label = I18n.t('js.work_packages.properties.' + property), |
||||
format = getPropertyFormat(property); |
||||
value = getPropertyValue(property, format); |
||||
|
||||
if (!(value === null || value === undefined)) { |
||||
return getFormattedValueToPresentProperties(property, label, value, format); |
||||
} else { |
||||
var plugInValues = HookService.call('workPackageOverviewAttributes', |
||||
{ type: property, |
||||
workPackage: $scope.workPackage }); |
||||
|
||||
if (plugInValues.length == 0) { |
||||
return getFormattedValueToPresentProperties(property, label, null, format); |
||||
} else { |
||||
for (var x = 0; x < plugInValues.length; x++) { |
||||
return getFormattedValueToPresentProperties(property, label, plugInValues[x], 'dynamic'); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
function getWorkPackageCustomProperty(property) { |
||||
var label = property.name, |
||||
value = (property.value) ? getCustomPropertyValue(property) : null, |
||||
format = property.format; |
||||
|
||||
return getFormattedValueToPresentProperties(property.name, label, value, format); |
||||
} |
||||
|
||||
function getPropertyFormat(property) { |
||||
var format = USER_FIELDS.indexOf(property) === -1 ? TEXT_TYPE : USER_TYPE; |
||||
format = (property === 'versionName') ? VERSION_TYPE : format; |
||||
format = (property === 'category') ? CATEGORY_TYPE : format; |
||||
|
||||
return format; |
||||
} |
||||
|
||||
function getCustomPropertyValue(customProperty) { |
||||
if (!!customProperty.value && customProperty.format === USER_TYPE) { |
||||
return UserService.getUser(customProperty.value); |
||||
} else { |
||||
return CustomFieldHelper.formatCustomFieldValue(customProperty.value, customProperty.format); |
||||
} |
||||
} |
||||
|
||||
function getFormattedValueToPresentProperties(property, label, value, format) { |
||||
var propertyData = { |
||||
property: property, |
||||
label: label, |
||||
format: format, |
||||
value: null |
||||
}; |
||||
|
||||
$q.when(value).then(function(value) { |
||||
propertyData.value = value; |
||||
}); |
||||
|
||||
return propertyData; |
||||
} |
||||
|
||||
// toggles
|
||||
|
||||
$scope.toggleStates = { |
||||
hideFullDescription: true, |
||||
hideAllAttributes: true |
||||
}; |
||||
|
||||
$scope.isGroupEmpty = function(group) { |
||||
return group.attributes.filter(function(element) { |
||||
return !!element.value; |
||||
}).length == 0; |
||||
}; |
||||
|
||||
$scope.anyEmptyWorkPackageValue = function() { |
||||
return $scope.groupedAttributes.filter(function(element) { |
||||
return $scope.isGroupEmpty(element); |
||||
}).length > 0; |
||||
}; |
||||
} |
@ -1,92 +0,0 @@ |
||||
//-- copyright
|
||||
// OpenProject is a project management system.
|
||||
// Copyright (C) 2012-2014 the OpenProject Foundation (OPF)
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License version 3.
|
||||
//
|
||||
// OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
|
||||
// Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
// Copyright (C) 2010-2013 the ChiliProject Team
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 2
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
// See doc/COPYRIGHT.rdoc for more details.
|
||||
//++
|
||||
|
||||
module.exports = function($scope, $filter, columnsModal, QueryService, WorkPackageService, WorkPackagesTableService, $rootScope) { |
||||
|
||||
this.name = 'Columns'; |
||||
this.closeMe = columnsModal.deactivate; |
||||
|
||||
$scope.getObjectsData = function(term, result) { |
||||
var filtered = $filter('filter')($scope.availableColumnsData.filter(function(column) { |
||||
//Note: very special case; if such columns shall multiple, we better add a field
|
||||
// to the query model hash of available columns
|
||||
return column.id != "id"; |
||||
}), {label: term}); |
||||
var sorted = $filter('orderBy')(filtered, 'label'); |
||||
return result(sorted); |
||||
}; |
||||
|
||||
// Data conversion for select2
|
||||
function convertColumnsForSelect2(columns) { |
||||
return columns.map(function(column){ |
||||
return { id: column.name, label: column.title, other: column.title }; |
||||
}); |
||||
} |
||||
function getColumnIdentifiersFromSelection(selectedColumnsData) { |
||||
return selectedColumnsData.map(function(column) { return column.id; }); |
||||
} |
||||
|
||||
// Selected Columns
|
||||
var selectedColumns = QueryService.getSelectedColumns(); |
||||
var previouslySelectedColumnNames = selectedColumns |
||||
.map(function(column){ return column.name; }); |
||||
|
||||
function getNewlyAddedColumns() { |
||||
return selectedColumns.select(function(column){ |
||||
return previouslySelectedColumnNames.indexOf(column.name) < 0; |
||||
}); |
||||
} |
||||
|
||||
$scope.selectedColumnsData = convertColumnsForSelect2(selectedColumns); |
||||
|
||||
// Available selectable Columns
|
||||
QueryService.loadAvailableColumns() |
||||
.then(function(availableColumns){ |
||||
$scope.availableColumns = availableColumns; |
||||
$scope.availableColumnsData = convertColumnsForSelect2(availableColumns); |
||||
}); |
||||
|
||||
|
||||
$scope.updateSelectedColumns = function(){ |
||||
// Note: Can't directly manipulate selected columns because select2 returns a new array when you change the values:(
|
||||
QueryService.setSelectedColumns(getColumnIdentifiersFromSelection($scope.selectedColumnsData)); |
||||
|
||||
// Augment work packages with new columns data
|
||||
var addedColumns = getNewlyAddedColumns(), |
||||
currentWorkPackages = WorkPackagesTableService.getRowsData(), |
||||
groupBy = WorkPackagesTableService.getGroupBy(); |
||||
|
||||
if(groupBy.length === 0) groupBy = undefined; // don't pass an empty string as groupBy
|
||||
|
||||
if(addedColumns.length) { |
||||
$rootScope.refreshWorkPackages = WorkPackageService.augmentWorkPackagesWithColumnsData(currentWorkPackages, addedColumns, groupBy); |
||||
} |
||||
|
||||
columnsModal.deactivate(); |
||||
}; |
||||
} |
@ -1,154 +0,0 @@ |
||||
//-- copyright
|
||||
// OpenProject is a project management system.
|
||||
// Copyright (C) 2012-2014 the OpenProject Foundation (OPF)
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License version 3.
|
||||
//
|
||||
// OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
|
||||
// Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
// Copyright (C) 2010-2013 the ChiliProject Team
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 2
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
// See doc/COPYRIGHT.rdoc for more details.
|
||||
//++
|
||||
|
||||
module.exports = function($scope, $state, latestTab, workPackage, I18n, RELATION_TYPES, RELATION_IDENTIFIERS, $q, WorkPackagesHelper, PathHelper, UsersHelper, ConfigurationService, CommonRelationsHandler, ChildrenRelationsHandler, ParentRelationsHandler) { |
||||
$scope.$on('$stateChangeSuccess', function(event, toState){ |
||||
latestTab.registerState(toState.name); |
||||
}); |
||||
|
||||
$scope.$on('workPackageRefreshRequired', function(event, toState){ |
||||
refreshWorkPackage(); |
||||
}); |
||||
|
||||
// initialization
|
||||
setWorkPackageScopeProperties(workPackage); |
||||
|
||||
$scope.I18n = I18n; |
||||
$scope.$parent.preselectedWorkPackageId = $scope.workPackage.props.id; |
||||
$scope.maxDescriptionLength = 800; |
||||
|
||||
function refreshWorkPackage() { |
||||
workPackage.links.self |
||||
.fetch({force: true}) |
||||
.then(setWorkPackageScopeProperties); |
||||
} |
||||
$scope.refreshWorkPackage = refreshWorkPackage; // expose to child controllers
|
||||
|
||||
// Inform parent that work package is loaded so back url can be maintained
|
||||
$scope.$emit('workPackgeLoaded'); |
||||
|
||||
function outputMessage(message, isError) { |
||||
$scope.$emit('flashMessage', { |
||||
isError: !!isError, |
||||
text: message |
||||
}); |
||||
} |
||||
|
||||
function outputError(error) { |
||||
outputMessage(error.message, true); |
||||
} |
||||
|
||||
$scope.outputMessage = outputMessage; // expose to child controllers
|
||||
$scope.outputError = outputError; // expose to child controllers
|
||||
|
||||
function setWorkPackageScopeProperties(workPackage){ |
||||
$scope.workPackage = workPackage; |
||||
|
||||
$scope.isWatched = !!workPackage.links.unwatchChanges; |
||||
$scope.toggleWatchLink = workPackage.links.watchChanges === undefined ? workPackage.links.unwatchChanges : workPackage.links.watchChanges; |
||||
$scope.watchers = workPackage.embedded.watchers; |
||||
|
||||
// activities and latest activities
|
||||
$scope.activitiesSortedInDescendingOrder = ConfigurationService.commentsSortedInDescendingOrder(); |
||||
$scope.activities = displayedActivities($scope.workPackage); |
||||
|
||||
// watchers
|
||||
$scope.watchers = workPackage.embedded.watchers; |
||||
|
||||
// Author
|
||||
$scope.author = workPackage.embedded.author; |
||||
$scope.authorPath = PathHelper.staticUserPath($scope.author.props.id); |
||||
$scope.authorActive = UsersHelper.isActive($scope.author); |
||||
|
||||
// Attachments
|
||||
$scope.attachments = workPackage.embedded.attachments; |
||||
|
||||
// relations
|
||||
$q.all(WorkPackagesHelper.getParent(workPackage)).then(function(parents) { |
||||
var relationsHandler = new ParentRelationsHandler(workPackage, parents, "parent"); |
||||
$scope.wpParent = relationsHandler; |
||||
}); |
||||
|
||||
$q.all(WorkPackagesHelper.getChildren(workPackage)).then(function(children) { |
||||
var relationsHandler = new ChildrenRelationsHandler(workPackage, children); |
||||
$scope.wpChildren = relationsHandler; |
||||
}); |
||||
|
||||
for (var key in RELATION_TYPES) { |
||||
if (RELATION_TYPES.hasOwnProperty(key)) { |
||||
(function(key) { |
||||
$q.all(WorkPackagesHelper.getRelationsOfType(workPackage, RELATION_TYPES[key])).then(function(relations) { |
||||
var relationsHandler = new CommonRelationsHandler(workPackage, |
||||
relations, |
||||
RELATION_IDENTIFIERS[key]); |
||||
$scope[key] = relationsHandler; |
||||
}); |
||||
})(key); |
||||
} |
||||
} |
||||
|
||||
// Author
|
||||
$scope.author = workPackage.embedded.author; |
||||
} |
||||
|
||||
$scope.toggleWatch = function() { |
||||
$scope.toggleWatchLink |
||||
.fetch({ ajax: $scope.toggleWatchLink.props }) |
||||
.then(refreshWorkPackage, outputError); |
||||
}; |
||||
|
||||
$scope.canViewWorkPackageWatchers = function() { |
||||
return !!($scope.workPackage && $scope.workPackage.embedded.watchers !== undefined); |
||||
}; |
||||
|
||||
function displayedActivities(workPackage) { |
||||
var activities = workPackage.embedded.activities; |
||||
activities.splice(0, 1); // remove first activity (assumes activities are sorted chronologically)
|
||||
if ($scope.activitiesSortedInDescendingOrder) { |
||||
activities.reverse(); |
||||
} |
||||
return activities; |
||||
} |
||||
|
||||
// toggles
|
||||
|
||||
$scope.toggleStates = { |
||||
hideFullDescription: true, |
||||
hideAllAttributes: true |
||||
}; |
||||
|
||||
function getFocusAnchorLabel(tab, workPackage) { |
||||
var tabLabel = I18n.t('js.work_packages.tabs.' + tab); |
||||
var params = { tab: tabLabel, type: workPackage.props.type, subject: workPackage.props.subject }; |
||||
|
||||
return I18n.t('js.label_work_package_details_you_are_here', params); |
||||
} |
||||
|
||||
$scope.focusAnchorLabel = getFocusAnchorLabel($state.current.url.replace(/\//, ''), $scope.workPackage); |
||||
|
||||
} |
@ -1,165 +0,0 @@ |
||||
//-- copyright
|
||||
// OpenProject is a project management system.
|
||||
// Copyright (C) 2012-2014 the OpenProject Foundation (OPF)
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License version 3.
|
||||
//
|
||||
// OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
|
||||
// Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
// Copyright (C) 2010-2013 the ChiliProject Team
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 2
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
// See doc/COPYRIGHT.rdoc for more details.
|
||||
//++
|
||||
|
||||
module.exports = function(I18n, columnsModal, exportModal, saveModal, settingsModal, shareModal, sortingModal, groupingModal, QueryService, AuthorisationService, $window, $state, $timeout){ |
||||
|
||||
return { |
||||
restrict: 'AE', |
||||
scope: true, |
||||
link: function(scope, element, attributes) { |
||||
angular.element($window).bind('click', function() { |
||||
scope.$emit('hideAllDropdowns'); |
||||
}); |
||||
|
||||
scope.$watch('query.displaySums', function(newValue, oldValue) { |
||||
$timeout(function() { |
||||
scope.displaySumsLabel = (newValue) ? I18n.t('js.toolbar.settings.hide_sums') |
||||
: I18n.t('js.toolbar.settings.display_sums'); |
||||
}); |
||||
}); |
||||
|
||||
scope.saveQuery = function(event){ |
||||
if(scope.query.isNew()){ |
||||
if( allowQueryAction(event, 'create') ){ |
||||
scope.$emit('hideAllDropdowns'); |
||||
saveModal.activate(); |
||||
} |
||||
} else { |
||||
if( allowQueryAction(event, 'update') ) { |
||||
QueryService.saveQuery() |
||||
.then(function(data){ |
||||
scope.$emit('flashMessage', data.status); |
||||
$state.go('work-packages.list', { query_id: scope.query.id, query: null }, { notify: false }); |
||||
}); |
||||
} |
||||
} |
||||
}; |
||||
|
||||
scope.deleteQuery = function(event){ |
||||
if( allowQueryAction(event, 'delete') && preventNewQueryAction(event) && deleteConfirmed() ){ |
||||
QueryService.deleteQuery() |
||||
.then(function(data){ |
||||
settingsModal.deactivate(); |
||||
scope.$emit('flashMessage', data.status); |
||||
$state.go('work-packages.list', { query_id: null, query: null }, { reload: true }); |
||||
}); |
||||
} |
||||
}; |
||||
|
||||
// Modals
|
||||
scope.showSaveAsModal = function(event){ |
||||
if( allowQueryAction(event, 'create') ) { |
||||
showExistingQueryModal.call(saveModal, event); |
||||
} |
||||
}; |
||||
|
||||
scope.showShareModal = function(event){ |
||||
if (allowQueryAction(event, 'publicize') || allowQueryAction(event, 'star')) { |
||||
showExistingQueryModal.call(shareModal, event); |
||||
} |
||||
} |
||||
|
||||
scope.showSettingsModal = function(event){ |
||||
if( allowQueryAction(event, 'update') ) { |
||||
showExistingQueryModal.call(settingsModal, event); |
||||
} |
||||
}; |
||||
|
||||
scope.showExportModal = function(event){ |
||||
if( allowWorkPackageAction(event, 'export') ) { |
||||
showModal.call(exportModal); |
||||
} |
||||
}; |
||||
|
||||
scope.showColumnsModal = function(){ |
||||
showModal.call(columnsModal); |
||||
}; |
||||
|
||||
scope.showGroupingModal = function(){ |
||||
showModal.call(groupingModal); |
||||
}; |
||||
|
||||
scope.showSortingModal = function(){ |
||||
showModal.call(sortingModal); |
||||
}; |
||||
|
||||
scope.toggleDisplaySums = function(){ |
||||
scope.$emit('hideAllDropdowns'); |
||||
scope.query.displaySums = !scope.query.displaySums; |
||||
|
||||
// This eventually calls the resize event handler defined in the
|
||||
// WorkPackagesTable directive and ensures that the sum row at the
|
||||
// table footer is properly displayed.
|
||||
angular.element($window).trigger('resize'); |
||||
}; |
||||
|
||||
function preventNewQueryAction(event){ |
||||
if (event && scope.query.isNew()) { |
||||
event.preventDefault(); |
||||
event.stopPropagation(); |
||||
return false; |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
function showModal() { |
||||
scope.$emit('hideAllDropdowns'); |
||||
this.activate(); |
||||
} |
||||
|
||||
function showExistingQueryModal(event) { |
||||
if( preventNewQueryAction(event) ){ |
||||
scope.$emit('hideAllDropdowns'); |
||||
this.activate(); |
||||
} |
||||
} |
||||
|
||||
function allowQueryAction(event, action) { |
||||
return allowAction(event, 'query', action); |
||||
} |
||||
|
||||
function allowWorkPackageAction(event, action) { |
||||
return allowAction(event, 'work_package', action); |
||||
} |
||||
|
||||
function allowAction(event, modelName, action) { |
||||
if(AuthorisationService.can(modelName, action)){ |
||||
return true; |
||||
} else { |
||||
event.preventDefault(); |
||||
event.stopPropagation(); |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
function deleteConfirmed() { |
||||
return $window.confirm(I18n.t('js.text_query_destroy_confirmation')); |
||||
} |
||||
} |
||||
}; |
||||
} |
@ -1,86 +0,0 @@ |
||||
//-- copyright
|
||||
// OpenProject is a project management system.
|
||||
// Copyright (C) 2012-2014 the OpenProject Foundation (OPF)
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License version 3.
|
||||
//
|
||||
// OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
|
||||
// Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
// Copyright (C) 2010-2013 the ChiliProject Team
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 2
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
// See doc/COPYRIGHT.rdoc for more details.
|
||||
//++
|
||||
|
||||
require('./config'); |
||||
require('./controllers'); |
||||
require('./directives'); |
||||
require('./filters'); |
||||
require('./helpers'); |
||||
require('./models'); |
||||
require('./services'); |
||||
require('./tabs'); |
||||
require('./view_models'); |
||||
|
||||
angular.module('openproject.workPackages') |
||||
.factory('ColumnContextMenu', [ |
||||
'ngContextMenu', |
||||
function(ngContextMenu) { |
||||
|
||||
return ngContextMenu({ |
||||
controller: 'ColumnContextMenuController', |
||||
controllerAs: 'contextMenu', |
||||
templateUrl: '/templates/work_packages/column_context_menu.html', |
||||
container: '.work-packages--list-table-area' |
||||
}); |
||||
} |
||||
]) |
||||
.controller('ColumnContextMenuController', [ |
||||
'$scope', |
||||
'ColumnContextMenu', |
||||
'I18n', |
||||
'QueryService', |
||||
'WorkPackagesTableHelper', |
||||
'WorkPackagesTableService', |
||||
'columnsModal', |
||||
require('./column-context-menu') |
||||
]) |
||||
.constant('PERMITTED_CONTEXT_MENU_ACTIONS', ['edit', 'watch', 'log_time', |
||||
'duplicate', 'move', 'copy', 'delete' |
||||
]) |
||||
.factory('WorkPackageContextMenu', [ |
||||
'ngContextMenu', |
||||
function(ngContextMenu) { |
||||
|
||||
return ngContextMenu({ |
||||
controller: 'WorkPackageContextMenuController', |
||||
controllerAs: 'contextMenu', |
||||
templateUrl: '/templates/work_packages/work_package_context_menu.html' |
||||
}); |
||||
} |
||||
]) |
||||
.controller('WorkPackageContextMenuController', [ |
||||
'$scope', |
||||
'WorkPackagesTableHelper', |
||||
'WorkPackageContextMenuHelper', |
||||
'WorkPackageService', |
||||
'WorkPackagesTableService', |
||||
'I18n', |
||||
'$window', |
||||
'PERMITTED_CONTEXT_MENU_ACTIONS', |
||||
require('./work-package-context-menu') |
||||
]); |
@ -0,0 +1,54 @@ |
||||
//-- copyright
|
||||
// OpenProject is a project management system.
|
||||
// Copyright (C) 2012-2015 the OpenProject Foundation (OPF)
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License version 3.
|
||||
//
|
||||
// OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
|
||||
// Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
// Copyright (C) 2010-2013 the ChiliProject Team
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 2
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
// See doc/COPYRIGHT.rdoc for more details.
|
||||
//++
|
||||
|
||||
(function ($) { |
||||
$(function() { |
||||
$('.timelines-x-update-color').each(function() { |
||||
var preview, input, func, target; |
||||
|
||||
preview = $(this); |
||||
target = preview.data('target'); |
||||
if(target) { |
||||
input = $(target); |
||||
} else { |
||||
input = preview.next('input'); |
||||
} |
||||
|
||||
if (input.length === 0) { |
||||
return; |
||||
} |
||||
|
||||
func = function () { |
||||
preview.css('background-color', input.val()); |
||||
}; |
||||
|
||||
input.keyup(func).change(func).focus(func); |
||||
func(); |
||||
}); |
||||
}); |
||||
}(jQuery)); |
@ -0,0 +1,129 @@ |
||||
//-- copyright
|
||||
// OpenProject is a project management system.
|
||||
// Copyright (C) 2012-2015 the OpenProject Foundation (OPF)
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License version 3.
|
||||
//
|
||||
// OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
|
||||
// Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
// Copyright (C) 2010-2013 the ChiliProject Team
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 2
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
// See doc/COPYRIGHT.rdoc for more details.
|
||||
//++
|
||||
(function($) { |
||||
/* |
||||
* @see /app/views/custom_fields/_form.html.erb |
||||
*/ |
||||
$(function() { |
||||
var customFieldForm = $('#custom_field_form'); |
||||
|
||||
if (customFieldForm.length === 0) { |
||||
return; |
||||
} |
||||
|
||||
// collect the nodes involved
|
||||
var format = $('#custom_field_field_format'), |
||||
lengthField = $('#custom_field_length'), |
||||
regexpField = $('#custom_field_regexp'), |
||||
possibleValues = $('#custom_field_possible_values_attributes'), |
||||
defaultValueFields = $('#custom_field_default_value_attributes'), |
||||
spanDefaultTextMulti = $('#default_value_text_multi'), |
||||
spanDefaultTextSingle = $('#default_value_text_single'), |
||||
spanDefaultBool = $('#default_value_bool'); |
||||
|
||||
var deactivate = function(element) { |
||||
element.hide().find('input, textarea').not('.destroy_flag').attr('disabled', true); |
||||
}, |
||||
activate = function(element) { |
||||
element.show().find('input, textarea').not('.destroy_flag').removeAttr('disabled'); |
||||
}, |
||||
toggleVisibility = function(method, args) { |
||||
var fields = Array.prototype.slice.call(args); |
||||
$.each(fields, function(idx, field) { |
||||
field.closest('.form--field, .form--grouping')[method](); |
||||
}); |
||||
}, |
||||
hide = function() { toggleVisibility('hide', arguments); }, |
||||
show = function() { toggleVisibility('show', arguments); }, |
||||
toggleFormat = function() { |
||||
var searchable = $('#searchable_container'), |
||||
unsearchable = function() { searchable.attr('checked', false).hide(); }; |
||||
|
||||
// defaults (reset these fields before doing anything else)
|
||||
$.each([spanDefaultBool, spanDefaultTextSingle], function(idx, element) { |
||||
deactivate(element); |
||||
}); |
||||
show(defaultValueFields); |
||||
activate(spanDefaultTextMulti); |
||||
|
||||
switch (format.val()) { |
||||
case 'list': |
||||
hide(lengthField, regexpField); |
||||
show(searchable); |
||||
activate(possibleValues); |
||||
break; |
||||
case 'bool': |
||||
activate(spanDefaultBool); |
||||
deactivate(spanDefaultTextMulti); |
||||
deactivate(possibleValues); |
||||
hide(lengthField, regexpField, searchable); |
||||
unsearchable(); |
||||
break; |
||||
case 'date': |
||||
activate(spanDefaultTextSingle); |
||||
deactivate(spanDefaultTextMulti); |
||||
deactivate(possibleValues); |
||||
hide(lengthField, regexpField); |
||||
unsearchable(); |
||||
break; |
||||
case 'float': |
||||
case 'int': |
||||
activate(spanDefaultTextSingle); |
||||
deactivate(spanDefaultTextMulti); |
||||
deactivate(possibleValues); |
||||
show(lengthField, regexpField); |
||||
unsearchable(); |
||||
break; |
||||
case 'user': |
||||
case 'version': |
||||
deactivate(defaultValueFields); |
||||
deactivate(possibleValues); |
||||
hide(lengthField, regexpField, defaultValueFields); |
||||
unsearchable(); |
||||
break; |
||||
default: |
||||
show(lengthField, regexpField, searchable); |
||||
deactivate(possibleValues); |
||||
break; |
||||
} |
||||
}; |
||||
|
||||
// assign the switch format function to the select field
|
||||
format.on('change', toggleFormat).trigger('change'); |
||||
}); |
||||
|
||||
$(function() { |
||||
var localeSelectors = $('.locale_selector'); |
||||
|
||||
localeSelectors.change(function () { |
||||
var lang = $(this).val(), |
||||
span = $(this).closest('.translation'); |
||||
span.attr('lang', lang); |
||||
}).trigger('change'); |
||||
}); |
||||
}(jQuery)); |
@ -0,0 +1,53 @@ |
||||
//-- copyright
|
||||
// OpenProject is a project management system.
|
||||
// Copyright (C) 2012-2015 the OpenProject Foundation (OPF)
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License version 3.
|
||||
//
|
||||
// OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
|
||||
// Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
// Copyright (C) 2010-2013 the ChiliProject Team
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 2
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
// See doc/COPYRIGHT.rdoc for more details.
|
||||
//++
|
||||
(function($) { |
||||
$(function() { |
||||
/* |
||||
* See /app/views/timelog/_date_range.html.erb |
||||
*/ |
||||
if ($('#date-range').length < 1) { |
||||
return; |
||||
} |
||||
var intervalInputs = $('#to, #from'), |
||||
// select
|
||||
period = $('#period'), |
||||
// radio buttons
|
||||
periodOptionList = $('#period_type_list'), |
||||
periodOptionInterval = $('#period_type_interval'); |
||||
|
||||
var activateRadiobutton = function(radioButton) { |
||||
return function() { |
||||
radioButton.attr('checked', true); |
||||
}; |
||||
}; |
||||
|
||||
|
||||
intervalInputs.on('click focus', activateRadiobutton(periodOptionInterval)); |
||||
period.on('click focus', activateRadiobutton(periodOptionList)); |
||||
}); |
||||
}(jQuery)); |
@ -1,196 +0,0 @@ |
||||
//-- copyright
|
||||
// OpenProject is a project management system.
|
||||
// Copyright (C) 2012-2014 the OpenProject Foundation (OPF)
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License version 3.
|
||||
//
|
||||
// OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
|
||||
// Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
// Copyright (C) 2010-2013 the ChiliProject Team
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 2
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
// See doc/COPYRIGHT.rdoc for more details.
|
||||
//++
|
||||
|
||||
//= require mousetrap
|
||||
|
||||
(function($){ |
||||
|
||||
var accessibleListSelector = "table.list, table.keyboard-accessible-list"; |
||||
var accessibleRowSelector = "table.list tr, table.keyboard-accessible-list tr"; |
||||
|
||||
|
||||
var menu_sidebar = function() { |
||||
return $('div#menu-sidebar'); |
||||
}; |
||||
|
||||
var we_are_in_project = function() { |
||||
return menu_sidebar().size() === 1; |
||||
}; |
||||
|
||||
var show_help_modal = function(){ |
||||
var relative_url_root = jQuery('body').data('relative_url_root'); |
||||
var template_path = relative_url_root + 'help/keyboard_shortcuts'; |
||||
modalHelperInstance.createModal(template_path); |
||||
}; |
||||
|
||||
var go_overview = function(){ |
||||
if (we_are_in_project()) { |
||||
menu_sidebar().find('.overview')[0].click(); |
||||
} |
||||
}; |
||||
|
||||
var go_my_page = function(){ |
||||
var my_page = $('.account-nav .my-page'); |
||||
if (my_page.size() === 1) { |
||||
my_page[0].click(); |
||||
} |
||||
}; |
||||
|
||||
var go_work_packages = function(){ |
||||
if (we_are_in_project()) { |
||||
menu_sidebar().find('.work-packages')[0].click(); |
||||
} |
||||
}; |
||||
|
||||
var go_timelines = function(){ |
||||
if (we_are_in_project()) { |
||||
menu_sidebar().find('.timelines')[0].click(); |
||||
} |
||||
}; |
||||
|
||||
var go_wiki = function(){ |
||||
if (we_are_in_project()) { |
||||
menu_sidebar().find('.Wiki')[0].click(); |
||||
} |
||||
}; |
||||
|
||||
var go_activity = function(){ |
||||
if (we_are_in_project()) { |
||||
menu_sidebar().find('.activity')[0].click(); |
||||
} |
||||
}; |
||||
|
||||
var go_calendar = function(){ |
||||
if (we_are_in_project()) { |
||||
menu_sidebar().find('.calendar')[0].click(); |
||||
} |
||||
}; |
||||
|
||||
var go_news = function(){ |
||||
if (we_are_in_project()) { |
||||
menu_sidebar().find('.news')[0].click(); |
||||
} |
||||
}; |
||||
|
||||
var go_edit = function(){ |
||||
edit_link = $('[accesskey=3]')[0]; |
||||
if (edit_link !== undefined) { |
||||
edit_link.click(); |
||||
} |
||||
}; |
||||
|
||||
var open_more_menu = function(){ |
||||
more_menu = $('[accesskey=7]')[0]; |
||||
if (more_menu !== undefined) { |
||||
more_menu.click(); |
||||
} |
||||
}; |
||||
|
||||
var go_preview = function(){ |
||||
preview_link = $('[accesskey=1]')[0]; |
||||
if (preview_link !== undefined) { |
||||
preview_link.click(); |
||||
} |
||||
}; |
||||
|
||||
var new_work_package = function(){ |
||||
if (we_are_in_project()) { |
||||
menu_sidebar().find('.new-work-package')[0].click(); |
||||
} |
||||
}; |
||||
|
||||
var search_project = function(){ |
||||
$('#project-search-container').parents('li.drop-down').click(); |
||||
}; |
||||
|
||||
var search_global = function(){ |
||||
$('#search_wrap .search_field').focus(); |
||||
}; |
||||
|
||||
var find_list_in_page = function(){ |
||||
var dom_lists, focus_elements; |
||||
focus_elements = []; |
||||
dom_lists = $(accessibleListSelector); |
||||
dom_lists.find('tbody tr').each(function(index, tr){ |
||||
var first_link = $(tr).find('a:visible')[0]; |
||||
if ( first_link !== undefined ) { focus_elements.push(first_link); } |
||||
}); |
||||
return focus_elements; |
||||
}; |
||||
|
||||
var focus_item_offset = function(offset){ |
||||
var list, index; |
||||
list = find_list_in_page(); |
||||
if (list === null) { return; } |
||||
index = list.indexOf($(document.activeElement).parents(accessibleRowSelector).find('a:visible')[0]); |
||||
$(list[(index+offset+list.length) % list.length]).focus(); |
||||
}; |
||||
|
||||
var focus_next_item = function(){ |
||||
focus_item_offset(1); |
||||
}; |
||||
|
||||
var focus_previous_item = function(){ |
||||
focus_item_offset(-1); |
||||
}; |
||||
|
||||
|
||||
Mousetrap.bind('?', function(){ show_help_modal(); return false; }); |
||||
|
||||
Mousetrap.bind('g o', function(){ go_overview(); return false; }); |
||||
Mousetrap.bind('g m', function(){ go_my_page(); return false; }); |
||||
Mousetrap.bind('g w p', function(){ go_work_packages(); return false; }); |
||||
Mousetrap.bind('g w i', function(){ go_wiki(); return false; }); |
||||
Mousetrap.bind('g a', function(){ go_activity(); return false; }); |
||||
Mousetrap.bind('g c', function(){ go_calendar(); return false; }); |
||||
Mousetrap.bind('g n', function(){ go_news(); return false; }); |
||||
Mousetrap.bind('g t', function(){ go_timelines(); return false; }); |
||||
Mousetrap.bind('g e', function(){ go_edit(); return false; }); |
||||
Mousetrap.bind('g p', function(){ go_preview(); return false; }); |
||||
|
||||
Mousetrap.bind('n w p', function(){ new_work_package(); return false; }); |
||||
Mousetrap.bind('j', function(){ focus_next_item(); return false; }); |
||||
Mousetrap.bind('k', function(){ focus_previous_item(); return false; }); |
||||
Mousetrap.bind('m', function(){ open_more_menu(); return false; }); |
||||
|
||||
Mousetrap.bind('p', function(){ search_project(); return false; }); |
||||
Mousetrap.bind('s', function(){ search_global(); return false; }); |
||||
|
||||
jQuery(function(){ |
||||
// simulated hover effect on table lists when using the keyboard
|
||||
var tables = jQuery(accessibleListSelector); |
||||
if (tables.size() === 0) { return; } |
||||
tables.on('blur', 'tr *', function(){ |
||||
jQuery(this).parents(accessibleRowSelector).removeClass('keyboard_hover'); |
||||
}); |
||||
tables.on('focus', 'tr *', function(){ |
||||
jQuery(this).parents(accessibleRowSelector).addClass('keyboard_hover'); |
||||
}); |
||||
}); |
||||
|
||||
})(jQuery); |
@ -0,0 +1,41 @@ |
||||
//-- copyright
|
||||
// OpenProject is a project management system.
|
||||
// Copyright (C) 2012-2015 the OpenProject Foundation (OPF)
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License version 3.
|
||||
//
|
||||
// OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
|
||||
// Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
// Copyright (C) 2010-2013 the ChiliProject Team
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 2
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
// See doc/COPYRIGHT.rdoc for more details.
|
||||
//++
|
||||
|
||||
(function($) { |
||||
$(function() { |
||||
/* |
||||
* @see /app/views/search/index.html.erb |
||||
*/ |
||||
if ($('#search-filter').length < 1) { |
||||
return; |
||||
} |
||||
|
||||
$('#search-input').focus(); |
||||
|
||||
}); |
||||
}(jQuery)); |