diff --git a/.rubocop.yml b/.rubocop.yml index 151ba2e17e9..5ae61c918bb 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -125,7 +125,7 @@ LineEndConcatenation: Enabled: false LineLength: - Max: 99 + Max: 100 MethodLength: Enabled: false diff --git a/Gemfile b/Gemfile index a31e8e23106..45961b4ae2c 100644 --- a/Gemfile +++ b/Gemfile @@ -41,6 +41,9 @@ gem 'omniauth' gem 'request_store', "~> 1.1.0" gem 'gravatar_image_tag', '~> 1.2.0' +gem 'warden', '~> 1.2' +gem 'warden-basic_auth', '~> 0.2.0' + # TODO: adds #auto_link which was deprecated in rails 3.1 gem 'rails_autolink', '~> 1.1.6' gem "will_paginate", '~> 3.0' diff --git a/README.md b/README.md index a662c0f4b58..2df84acfe06 100644 --- a/README.md +++ b/README.md @@ -45,10 +45,10 @@ The [OpenProject Foundation (OPF)](https://community.openproject.org/projects/op ## Repository -This repository contains two main branches: +This repository contains several main branches: * `dev`: The main development branch. We try to keep it stable in the sense of all tests are passing, but we don't recommend it for production systems. -* `stable`: Contains the latest stable release that we recommend for production use. Use this if you always want the latest version of OpenProject. +* `stable/`: Contains the latest stable release for a specific version. We recommend to use this for production use. Example: `stable/4.1`. ## License diff --git a/app/controllers/search_controller.rb b/app/controllers/search_controller.rb index 875db46fec4..0c3ea217784 100644 --- a/app/controllers/search_controller.rb +++ b/app/controllers/search_controller.rb @@ -33,7 +33,7 @@ class SearchController < ApplicationController def index @question = params[:q] || '' @question.strip! - @all_words = params[:all_words] || (params[:submit] ? false : true) + @all_words = params[:all_words] || !params[:submit] @titles_only = !params[:titles_only].nil? projects_to_search = diff --git a/app/controllers/work_packages_controller.rb b/app/controllers/work_packages_controller.rb index 5e620a5617f..22186c72c3d 100644 --- a/app/controllers/work_packages_controller.rb +++ b/app/controllers/work_packages_controller.rb @@ -425,7 +425,7 @@ class WorkPackagesController < ApplicationController end def send_notifications? - params[:send_notification] == '0' ? false : true + params[:send_notification] != '0' end def per_page_param diff --git a/app/controllers/workflows_controller.rb b/app/controllers/workflows_controller.rb index 82d666e11ab..0e2ec7dd7d3 100644 --- a/app/controllers/workflows_controller.rb +++ b/app/controllers/workflows_controller.rb @@ -58,7 +58,7 @@ class WorkflowsController < ApplicationController end end - @used_statuses_only = (params[:used_statuses_only] == '0' ? false : true) + @used_statuses_only = params[:used_statuses_only] != '0' if @type && @used_statuses_only && @type.statuses.any? @statuses = @type.statuses end diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index c6f3e236656..df61a35ade8 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -502,7 +502,10 @@ module ApplicationHelper when 6 '6' # Saturday else - '' # use language + # use language (pass a blank string into the JSON object, + # as the datepicker implementation checks for numbers in + # /frontend/app/misc/datepicker-defaults.js:34) + '""' end # FIXME: Get rid of this abomination js = "var CS = { lang: '#{current_language.to_s.downcase}', firstDay: #{start_of_week} };" diff --git a/app/helpers/sort_helper.rb b/app/helpers/sort_helper.rb index 5d896bf14b2..031e638212f 100644 --- a/app/helpers/sort_helper.rb +++ b/app/helpers/sort_helper.rb @@ -143,8 +143,15 @@ module SortHelper def normalize! @criteria ||= [] - @criteria = @criteria.map { |s| s = s.to_a; [s.first, (s.last == false || s.last == 'desc') ? false : true] } - @criteria = @criteria.select { |k, _o| @available_criteria.has_key?(k) } if @available_criteria + @criteria = @criteria.map { |s| + s = s.to_a + [s.first, !(s.last == false || s.last == 'desc')] + } + + if @available_criteria + @criteria = @criteria.select { |k, _o| @available_criteria.has_key?(k) } + end + @criteria.slice!(3) self end diff --git a/app/models/enumeration.rb b/app/models/enumeration.rb index c1913131626..9c64a6b2676 100644 --- a/app/models/enumeration.rb +++ b/app/models/enumeration.rb @@ -149,7 +149,7 @@ class Enumeration < ActiveRecord::Base # Are the new and previous fields equal? def self.same_active_state?(new, previous) - new = (new == '1' ? true : false) + new = new == '1' new == previous end diff --git a/app/models/mail_handler.rb b/app/models/mail_handler.rb index e1b657a121e..e8cf8f3ddfa 100644 --- a/app/models/mail_handler.rb +++ b/app/models/mail_handler.rb @@ -48,7 +48,7 @@ class MailHandler < ActionMailer::Base # Status overridable by default @@handler_options[:allow_override] << 'status' unless @@handler_options[:issue].has_key?(:status) - @@handler_options[:no_permission_check] = (@@handler_options[:no_permission_check].to_s == '1' ? true : false) + @@handler_options[:no_permission_check] = @@handler_options[:no_permission_check].to_s == '1' email.force_encoding('ASCII-8BIT') if email.respond_to?(:force_encoding) super email diff --git a/app/models/system_user.rb b/app/models/system_user.rb index b2388eb6274..ef540739866 100644 --- a/app/models/system_user.rb +++ b/app/models/system_user.rb @@ -62,7 +62,7 @@ class SystemUser < User # There should be only one SystemUser in the database def validate_unique_system_user - errors.add :base, 'A SystemUser already exists.' if SystemUser.find(:first) + errors.add :base, 'A SystemUser already exists.' if SystemUser.any? end # Overrides a few properties diff --git a/app/models/user.rb b/app/models/user.rb index 55becf50d47..f6aabe994aa 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -740,7 +740,7 @@ class User < Principal end def self.system - system_user = SystemUser.find(:first) + system_user = SystemUser.first if system_user.nil? (system_user = SystemUser.new.tap do |u| u.lastname = 'System' diff --git a/app/views/boards/index.html.erb b/app/views/boards/index.html.erb index 7b63e3435e6..61b6555b64d 100644 --- a/app/views/boards/index.html.erb +++ b/app/views/boards/index.html.erb @@ -47,12 +47,10 @@ See doc/COPYRIGHT.rdoc for more details. <%= board.topics_count %> <%= board.messages_count %> - - <% if board.last_message %> - <%= authoring board.last_message.created_on, board.last_message.author %>
- <%= link_to_message board.last_message %> - <% end %> -
+ <% if board.last_message %> + <%= authoring board.last_message.created_on, board.last_message.author %>
+ <%= link_to_message board.last_message %> + <% end %> <% end %> diff --git a/app/views/help/wiki_syntax_detailed.html.erb b/app/views/help/wiki_syntax_detailed.html.erb index d2ea097c5b8..78d789643ce 100644 --- a/app/views/help/wiki_syntax_detailed.html.erb +++ b/app/views/help/wiki_syntax_detailed.html.erb @@ -236,6 +236,16 @@ To go live, all you need to add is a database and a web server. {{toc}} => left aligned toc {{>toc}} => right aligned toc +

Acronyms

+

Display tooltip for acronym by entering tooltip in parantheses after upper case +acronym.

+
+WHO(World Health Organisation) => Displays "World Health Organisation" as
+tooltip of "WHO"
+
+

+ WHO +

Macros

OpenProject has the following builtin macros:

diff --git a/app/views/my/_sidebar.html.erb b/app/views/my/_sidebar.html.erb index dd08b56ebb7..d27a9953c77 100644 --- a/app/views/my/_sidebar.html.erb +++ b/app/views/my/_sidebar.html.erb @@ -44,19 +44,18 @@ See doc/COPYRIGHT.rdoc for more details. (<%= link_to l(:button_reset), {:action => 'reset_rss_key'}, :method => :post %>)

<% end %> -<% if Setting.rest_api_enabled? %> -

<%= l(:label_api_access_key) %>

-
- <%= link_to_function(l(:button_show), "$('api-access-key').toggle();")%> -
<%= h(@user.api_key) %>
-
- <%= javascript_tag("$('api-access-key').hide();") %> -

- <% if @user.api_token %> - <%= l(:label_api_access_key_created_on, distance_of_time_in_words(Time.now, @user.api_token.created_on)) %> - <% else %> - <%= l(:label_missing_api_access_key) %> - <% end %> - (<%= link_to l(:button_reset), {:action => 'reset_api_key'}, :method => :post %>) -

-<% end %> + +

<%= l(:label_api_access_key) %>

+
+ <%= link_to_function(l(:button_show), "$('api-access-key').toggle();")%> +
<%= h(@user.api_key) %>
+
+<%= javascript_tag("$('api-access-key').hide();") %> +

+ <% if @user.api_token %> + <%= l(:label_api_access_key_created_on, distance_of_time_in_words(Time.now, @user.api_token.created_on)) %> + <% else %> + <%= l(:label_missing_api_access_key) %> + <% end %> + (<%= link_to l(:button_reset), {:action => 'reset_api_key'}, :method => :post %>) +

diff --git a/config/configuration.yml.example b/config/configuration.yml.example index 0ceeede6cd0..05a7c361d41 100644 --- a/config/configuration.yml.example +++ b/config/configuration.yml.example @@ -277,6 +277,14 @@ default: # generated and sent to the user who then has to change their password upon login. disable_password_choice: false + # You can configure a global set of credentials to authenticate towards + # API v3 via basic auth. Note that this will grant admin access. Use with care + # and make sure the password does not leak. + # authentication: + # global_basic_auth: + # user: admin + # password: admin + # specific configuration options for production environment # that overrides the default ones # production: diff --git a/config/initializers/warden.rb b/config/initializers/warden.rb new file mode 100644 index 00000000000..85dc7990b8e --- /dev/null +++ b/config/initializers/warden.rb @@ -0,0 +1,24 @@ +require 'open_project/authentication' + +# Strategies provided by OpenProject: +require 'open_project/authentication/strategies/warden/basic_auth_failure' +require 'open_project/authentication/strategies/warden/global_basic_auth' +require 'open_project/authentication/strategies/warden/user_basic_auth' +require 'open_project/authentication/strategies/warden/session' + +strategies = { + basic_auth_failure: OpenProject::Authentication::Strategies::Warden::BasicAuthFailure, + global_basic_auth: OpenProject::Authentication::Strategies::Warden::GlobalBasicAuth, + user_basic_auth: OpenProject::Authentication::Strategies::Warden::UserBasicAuth, + session: OpenProject::Authentication::Strategies::Warden::Session +} + +strategies.each do |name, clazz| + Warden::Strategies.add name, clazz +end + +include OpenProject::Authentication::Scope + +OpenProject::Authentication.update_strategies(API_V3) do |_strategies| + [:global_basic_auth, :user_basic_auth, :basic_auth_failure, :session] +end diff --git a/config/locales/de.yml b/config/locales/de.yml index f5e1faee630..2a2749165d9 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -1685,6 +1685,7 @@ de: lock_version: "Sperrversion" errors: code_401: "Sie müssen sich authentifizieren, um auf die Ressource zugreifen zu können." + code_401_wrong_credentials: "Die von Ihnen benutzten Zugangsdaten sind nicht korrekt." code_403: "Sie sind nicht berechtigt auf diese Ressource zuzugreifen." code_404: "Die angeforderte Ressource konnte nicht gefunden werden." code_409: "Die Ressource konnte wegen parallelen Zugriffs nicht aktualisiert werden." diff --git a/config/locales/en.yml b/config/locales/en.yml index 73be5f7dc95..b1ffe2cd13d 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -1677,6 +1677,7 @@ en: lock_version: "Lock Version" errors: code_401: "You need to be authenticated to access this resource." + code_401_wrong_credentials: "You did not provide the correct credentials." code_403: "You are not authorized to access this resource." code_404: "The requested resource could not be found." code_409: "Couldn\'t update the resource because of conflicting modifications." diff --git a/doc/CONFIGURATION.md b/doc/CONFIGURATION.md index 4bff000debf..f395cf32ae3 100644 --- a/doc/CONFIGURATION.md +++ b/doc/CONFIGURATION.md @@ -86,6 +86,7 @@ storage config above like this: * [`hidden_menu_items`](#hidden-menu-items) (default: {}) * [`disabled_modules`](#disabled-modules) (default: []) * [`blacklisted_routes`](#blacklisted-routes) (default: []) +* [`global_basic_auth`](#global-basic-auth) ### disable password login @@ -186,7 +187,7 @@ OPENPROJECT_HIDDEN__MENU__ITEMS_ADMIN__MENU='roles types' *default: []* -You can blacklist specific routes +You can blacklist specific routes The following example forbid all routes for above disabled menu: ``` @@ -237,6 +238,21 @@ The option to use a string is mostly relevant for when you want to override the OPENPROJECT_DISABLED__MODULES='backlogs meetings' ``` +### global basic auth + +*default: none* + +You can define a global set of credentials used to authenticate towards API v3. +Example section for `configuration.yml`: + +``` +default: + authentication: + global_basic_auth: + user: admin + password: admin +``` + ## Email configuration * `email_delivery_method`: The way emails should be delivered. Possible values: `smtp` or `sendmail` diff --git a/doc/QUICK_START.md b/doc/QUICK_START.md index 5c853b1f17e..29137daabc2 100644 --- a/doc/QUICK_START.md +++ b/doc/QUICK_START.md @@ -43,8 +43,8 @@ These are generic (and condensed) installation instructions for the **current de * Git * Database (MySQL 5.x/PostgreSQL 8.x) * Ruby 2.1.x -* [Node.js] (version v0.10.x) -* [Bundler] (version 1.5.1 or higher required) +* Node.js (version v0.10.x) +* Bundler (version 1.5.1 or higher required) ### Install Dependencies diff --git a/doc/apiv3-documentation.apib b/doc/apiv3-documentation.apib index 1c216357cfe..f99a468a5bf 100644 --- a/doc/apiv3-documentation.apib +++ b/doc/apiv3-documentation.apib @@ -93,7 +93,7 @@ For the future we plan to add authentication modes based on OAuth2 and OpenID Co Links to other resources in the API are represented uniformly by so called link objects. -## Properties +## Local Properties | Property | Description | Type | Required | Nullable | Default | |:---------:| ------------------------------------------------------------------------ | ------- |:--------:|:--------:| ------- | @@ -207,8 +207,9 @@ embedded errors or simply state that multiple errors occured. * `urn:openproject-org:api:v3:errors:InvalidRequestBody` (**HTTP 400**) - The format of the request body did not match the servers expectation * `urn:openproject-org:api:v3:errors:InvalidRenderContext` (**HTTP 400**) - The client specified a rendering context that does not exist -* `urn:openproject-org:api:v3:errors:InvalidUserStatusTransition` (**HTTP 400**) The client used an invalid transition in the attempt to change the status of a user account. -* `urn:openproject-org:api:v3:errors:MissingPermission` (**HTTP 401** / **HTTP 403**) - The client does not have the needed permissions to perform the requested action +* `urn:openproject-org:api:v3:errors:InvalidUserStatusTransition` (**HTTP 400**) - The client used an invalid transition in the attempt to change the status of a user account. +* `urn:openproject-org:api:v3:errors:Unauthenticated` (**HTTP 401**) - The client has to authenticate to access the requested resource. +* `urn:openproject-org:api:v3:errors:MissingPermission` (**HTTP 403**) - The client does not have the needed permissions to perform the requested action * `urn:openproject-org:api:v3:errors:NotFound` (**HTTP 404**) - Default for HTTP 404 when no further information is available * `urn:openproject-org:api:v3:errors:UpdateConflict` (**HTTP 409**) - The resource changed between GET-ing it and performing an update on it * `urn:openproject-org:api:v3:errors:TypeNotSupported` (**HTTP 415**) - The request contained data in an unsupported media type (Content-Type) @@ -295,7 +296,7 @@ pagination can be found below the links table. A collection also carries meta information like the total count of elements in the collection or - in case of a paginated collection - the amount of elements returned in this response and action links to retrieve the remaining elements. -## Properties +## Local Properties | Property | Description | Type | Availability | |:--------:| --------------------------------------------------------------- | ------- | --------------------------- | @@ -435,7 +436,7 @@ Cursor based pagination is therefore less suited for use cases where you want to # Group Activities -## Properties: +## Local Properties: | Property | Description | Type | Constraints | Supported operations | | :---------: | ------------- | ---- | ----------- | -------------------- | | id | Activity id | Integer | x > 0 | READ | @@ -551,7 +552,7 @@ Updates an activity's comment and, on success, returns the updated activity. # Group Attachments -## Properties: +## Local Properties: | Property | Description | Type | Constraints | Supported operations | | :---------: | ------------- | ---- | ----------- | -------------------- | | id | Attachment's id | Integer | x > 0 | READ | @@ -613,7 +614,7 @@ Updates an activity's comment and, on success, returns the updated activity. | project | The project of this category | Project | not null | READ | | defaultAssignee | Default assignee for work packages of this category | User | | READ | -## Properties +## Local Properties | Property | Description | Type | Constraints | Supported operations | | :--------: | ------------- | ------- | ----------- | -------------------- | | id | Category id | Integer | x > 0 | READ | @@ -1075,7 +1076,7 @@ The request body is the actual string that shall be rendered as HTML string. |:---------:|-------------------------------------------- | ------------- | --------------------- | -------------------- | | self | This priority | Priority | not null | READ | -## Properties +## Local Properties | Property | Description | Type | Constraints | Supported operations | | :---------: | ------------------------------------------- | ---------- | ----------- | -------------------- | | id | Priority id | Integer | x > 0 | READ | @@ -1238,7 +1239,7 @@ The request body is the actual string that shall be rendered as HTML string. | types | Types available in this project | Types | not null | READ | | versions | Versions available in this project | Versions | not null | READ | -## Properties: +## Local Properties: | Property | Description | Type | Constraints | Supported operations | | :---------: | ------------- | ---- | ----------- | -------------------- | | id | Projects's id | Integer | x > 0 | READ | @@ -1485,7 +1486,7 @@ For more details and all possible responses see the general specification of [Fo # Group Queries -## Properties: +## Local Properties: | Property | Description | Type | Constraints | Supported operations | | :---------: | ------------- | ---- | ----------- | -------------------- | | id | Query id | Integer | x > 0 | READ | @@ -1749,7 +1750,7 @@ The `allowedValues` can either contain a list of canonical links or just a singl This is an optimization to allow efficient handling of both small resource lists (that can be enumerated inline) and large resource lists (requiring one or more separate requests). -## Properties: +## Local Properties: | Property | Description | Type | Default | |:-----------------:| ---------------------------------------------------------------------------------- | -------- | ------- | @@ -1845,7 +1846,7 @@ This is an example of how a schema might look like. Note that this endpoint does |:-------------:|-------------------------- | ------------- | ----------- | -------------------- | | self | This status | Status | not null | READ | -## Properties +## Local Properties | Property | Description | Type | Constraints | Supported operations | | :--------: | ------------- | ------- | ----------- | -------------------- | | id | Status id | Integer | x > 0 | READ | @@ -2046,7 +2047,7 @@ This is an example of how a schema might look like. Note that this endpoint does |:-------------:|-------------------------- | ------------- | ----------- | -------------------- | | self | This string object | StringObject | not null | READ | -## Properties +## Local Properties | Property | Description | Type | Constraints | Supported operations | |:----------------:| ---------------------------------------------- | -------- | ----------- | -------------------- | | value | The value of the string | String | | READ | @@ -2083,7 +2084,7 @@ e.g. to be able to provide `allowedValues` for a string typed property. |:-------------:|-------------------------- | ------------- | ----------- | -------------------- | | self | This type | Type | not null | READ | -## Properties +## Local Properties | Property | Description | Type | Constraints | Supported operations | |:----------------:| ---------------------------------------------- | -------- | ----------- | -------------------- | | id | Type id | Integer | x > 0 | READ | @@ -2319,7 +2320,7 @@ This endpoint lists the types that are *available* in a given project. |:---------:|-------------------------------------------- | ------------- | --------------------- | -------------------- | | self | This user | User | not null | READ | -## Properties: +## Local Properties: | Property | Description | Type | Constraints | Supported operations | Condition | | :---------: | ------------- | ---- | ----------- | -------------------- | ------------------------- | | id | User's id | Integer | x > 0 | READ | | @@ -2546,7 +2547,7 @@ Permanently deletes the specified user account. | definingProject | The project to which the version belongs | Project | only present if the project is visible for the current user | READ | | availableInProjects | Projects where this version can be used | Projects | not null | READ | -## Properties +## Local Properties | Property | Description | Type | Constraints | Supported operations | | :---------: | --------------------------------------------- | ----------- | ----------- | -------------------- | | id | Version id | Integer | x > 0 | READ | @@ -2742,7 +2743,7 @@ Note that due to sharing this might be more than the versions *defined* by that | type | The type of the work package | Type | not null | READ / WRITE | | | version | The version associated to the work package | Version | | READ / WRITE | | -## Properties: +## Local Properties: | Property | Description | Type | Constraints | Supported operations | Condition | | :--------------: | ------------------------------------------------------ | ----------- | ------------------------------------------------------------------------------------------------------ | -------------------- | -------------------------------- | diff --git a/extra/svn/reposman.rb b/extra/svn/reposman.rb index 88b1b6d087d..ae8241ae149 100755 --- a/extra/svn/reposman.rb +++ b/extra/svn/reposman.rb @@ -205,7 +205,7 @@ def set_owner_and_rights(project, repos_path, &block) end def other_read_right?(file) - (File.stat(file).mode & 0007).zero? ? false : true + !(File.stat(file).mode & 0007).zero? end def owner_name(file) diff --git a/features/step_definitions/custom_web_steps.rb b/features/step_definitions/custom_web_steps.rb index 3a9561e96d5..984e820a039 100644 --- a/features/step_definitions/custom_web_steps.rb +++ b/features/step_definitions/custom_web_steps.rb @@ -60,7 +60,7 @@ end Then /^"([^"]*)" should (not )?be selectable from "([^"]*)"$/ do |value, negative, select_id| # more page.evaluate ugliness find(:xpath, '//body') - bool = negative ? false : true + bool = !negative (page.evaluate_script("$('#{select_id}').select('option[value=#{value}]').first.disabled") =~ /^#{bool}$/).should be_present end diff --git a/features/step_definitions/general_steps.rb b/features/step_definitions/general_steps.rb index daf21e61885..1e5b7a9101b 100644 --- a/features/step_definitions/general_steps.rb +++ b/features/step_definitions/general_steps.rb @@ -214,8 +214,8 @@ Given /^there are the following issue status:$/ do |table| table.hashes.each_with_index do |t, i| status = Status.find_by(name: t['name']) status = Status.new name: t['name'] if status.nil? - status.is_closed = t['is_closed'] == 'true' ? true : false - status.is_default = t['is_default'] == 'true' ? true : false + status.is_closed = t['is_closed'] == 'true' + status.is_default = t['is_default'] == 'true' status.position = t['position'] ? t['position'] : i status.default_done_ratio = t['default_done_ratio'] status.save! diff --git a/features/step_definitions/password_steps.rb b/features/step_definitions/password_steps.rb index 7932360f158..728f4fb602b 100644 --- a/features/step_definitions/password_steps.rb +++ b/features/step_definitions/password_steps.rb @@ -143,7 +143,7 @@ def set_user_attribute(login, attribute, value) end Given /^the user "(.+)" is(not |) forced to change his password$/ do |login, disable| - set_user_attribute(login, :force_password_change, (disable == 'not ') ? false : true) + set_user_attribute(login, :force_password_change, disable != 'not ') end Given /^I use the first existing token to request a password reset$/ do diff --git a/features/step_definitions/web_steps.rb b/features/step_definitions/web_steps.rb index 90a9f7dbbad..742dfb5cec7 100644 --- a/features/step_definitions/web_steps.rb +++ b/features/step_definitions/web_steps.rb @@ -319,7 +319,7 @@ end Then /^there should be a( disabled)? "(.+)" field( visible| invisible)?$/ do |disabled, fieldname, visible| # Checking for a disabled field will only work for field with labels where the label # has a correctly filled "for" attribute - visibility = visible && visible.include?('invisible') ? false : true + visibility = visible && !visible.include?('invisible') if disabled # disabled fields can not be found via find_field diff --git a/frontend/app/ui_components/wiki-toolbar-directive.js b/frontend/app/ui_components/wiki-toolbar-directive.js index e2081522937..f504ec80cf5 100644 --- a/frontend/app/ui_components/wiki-toolbar-directive.js +++ b/frontend/app/ui_components/wiki-toolbar-directive.js @@ -32,6 +32,7 @@ module.exports = function() { 'menubar=no, status=no, scrollbars=yes"); return false;', HELP_LINK_HTML = jQuery('