diff --git a/.github/workflows/codeql-scan-core.yml b/.github/workflows/codeql-scan-core.yml index 851878a55db2..39af5c08b057 100644 --- a/.github/workflows/codeql-scan-core.yml +++ b/.github/workflows/codeql-scan-core.yml @@ -1,35 +1,43 @@ name: codeql on: + push: + branches: [ "dev", "release/*", "stable/*" ] pull_request: - branches: - - dev - - release/* + branches: [ "dev", "release/*", "stable/*" ] schedule: - - cron: '55 5 * * 1-5' + - cron: '32 1 * * 2' jobs: analyze: name: Analyze - runs-on: ubuntu-latest + runs-on: 'ubuntu-latest' + timeout-minutes: 120 permissions: + # required for all workflows + security-events: write + + # only required for workflows in private repositories actions: read contents: read - security-events: write strategy: fail-fast: false matrix: - language: [ 'javascript', 'ruby' ] + language: [ 'javascript-typescript', 'ruby' ] steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Initialize CodeQL - uses: github/codeql-action/init@v2 + uses: github/codeql-action/init@v3 with: languages: ${{ matrix.language }} + # For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs + queries: security-extended,security-and-quality - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 + uses: github/codeql-action/analyze@v3 + with: + category: "/language:${{matrix.language}}" diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 494934e0eb18..937c42cd3c66 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -10,8 +10,8 @@ on: - v* workflow_dispatch: inputs: - version: - description: "The version to release. Note that this happens by default on the tag push. Only run this action when something went wrong!" + tag: + description: "The tag to release. Note that this happens by default on the tag push. Only run this action when something went wrong!" required: true permissions: @@ -23,7 +23,7 @@ env: jobs: build: if: github.repository == 'opf/openproject' - runs-on: ubuntu-latest + runs-on: [ self-hosted, aws, ubuntu22, x64, 2XL ] strategy: matrix: include: @@ -33,17 +33,32 @@ jobs: target: slim - platform: linux/amd64 target: all-in-one + - platform: linux/ppc64le + bim_support: false + target: all-in-one - platform: linux/arm64/v8 bim_support: false target: all-in-one steps: + - name: Extract version + id: extract_version + run: | + if [[ ${{ github.event_name }} == 'push' ]]; then + TAG_REF=${GITHUB_REF#refs/tags/} + elif [[ ${{ github.event_name }} == 'workflow_dispatch' ]]; then + TAG_REF=${{ inputs.tag }} + fi + + VERSION=${TAG_REF#v} + echo "Version: $VERSION" + echo "::set-output name=version::$VERSION" - name: Checkout current release if: ${{ github.event_name == 'push' }} uses: actions/checkout@v3 - name: Checkout specific version if: ${{ github.event_name != 'push' }} with: - ref: ${{ inputs.version }} + ref: ${{ inputs.tag }} uses: actions/checkout@v3 - name: Prepare docker files run: | @@ -62,6 +77,8 @@ jobs: id: meta uses: docker/metadata-action@v4 with: + tags: | + type=semver,pattern={{version}},value=${{ steps.extract_version.outputs.version }} images: | ${{ env.REGISTRY_IMAGE }} - name: Build image @@ -142,13 +159,17 @@ jobs: uses: docker/metadata-action@v4 with: images: ${{ env.REGISTRY_IMAGE }} + labels: | + io.artifacthub.package.readme-url="https://www.openproject.org/docs/installation-and-operations/installation/docker/" + org.opencontainers.image.documentation="https://www.openproject.org/docs/" + org.opencontainers.image.vendor="OpenProject GmbH" flavor: | latest=false suffix=${{ steps.set_suffix.outputs.suffix }} tags: | - type=semver,pattern={{version}} - type=semver,pattern={{major}}.{{minor}} - type=semver,pattern={{major}} + type=semver,pattern={{version}},value=${{ steps.extract_version.outputs.version }} + type=semver,pattern={{major}}.{{minor}},value=${{ steps.extract_version.outputs.version }} + type=semver,pattern={{major}},value=${{ steps.extract_version.outputs.version }} type=raw,value=dev,priority=200,enable={{is_default_branch}} - name: Login to Docker Hub uses: docker/login-action@v2 diff --git a/README.md b/README.md index 0f9a689fbba0..539858a17d69 100644 --- a/README.md +++ b/README.md @@ -62,10 +62,6 @@ See [COPYRIGHT](COPYRIGHT) and [LICENSE](LICENSE) files for details. Thanks to Vincent Le Moign and his fabulous Minicons icons on [webalys.com](http://www.webalys.com/minicons/icons-free-pack.php). -### Lato Font - -Thanks to Łukasz Dziedzic (aka "tyPoland") for his 'Lato' font. - ### OpenProject icon font Published and created by the OpenProject Foundation (OPF) under [Creative Commons Attribution 3.0 Unported License](http://creativecommons.org/licenses/by/3.0/) with icons from the following sources diff --git a/app/controllers/work_packages/bulk_controller.rb b/app/controllers/work_packages/bulk_controller.rb index 4bf0a689fd5c..b0495d346c58 100644 --- a/app/controllers/work_packages/bulk_controller.rb +++ b/app/controllers/work_packages/bulk_controller.rb @@ -85,9 +85,13 @@ def destroy def setup_edit @available_statuses = @projects.map { |p| Workflow.available_statuses(p) }.inject(&:&) - @custom_fields = @projects.map(&:all_work_package_custom_fields).inject(&:&) @assignables = @responsibles = Principal.possible_assignee(@projects) @types = @projects.map(&:types).inject(&:&) + + # Display only the custom fields that are enabled on the projects and on types too. + @custom_fields = + @projects.map(&:all_work_package_custom_fields).inject(&:&) & + WorkPackageCustomField.joins(:types).where(types: @types) end def destroy_work_packages(work_packages) diff --git a/app/models/queries/operators/concerns/contains_all_values.rb b/app/models/queries/operators/concerns/contains_all_values.rb index 0fe722085fbd..78a2b1cf28c1 100644 --- a/app/models/queries/operators/concerns/contains_all_values.rb +++ b/app/models/queries/operators/concerns/contains_all_values.rb @@ -35,7 +35,7 @@ def sql_for_field(values, db_table, db_field) values .first .split(/\s+/) - .map { |substr| "#{db_table}.#{db_field} ILIKE '%#{connection.quote_string(substr)}%'" } + .map { |token| "#{db_table}.#{db_field} ILIKE '%#{OpenProject::SqlSanitization.quoted_sanitized_sql_like(token)}%'" } .join(' AND ') end end diff --git a/app/models/work_package/pdf_export/markdown.rb b/app/models/work_package/pdf_export/markdown.rb index 19f573f25080..7cea0021c56c 100644 --- a/app/models/work_package/pdf_export/markdown.rb +++ b/app/models/work_package/pdf_export/markdown.rb @@ -91,7 +91,7 @@ def handle_unknown_html_tag(_tag, _node, opts) end def warn(text, element, node) - Rails.logger.warn "PDF-Export: #{text}\nGot #{element} at #{node.sourcepos.inspect}\n\n" + Rails.logger.warn "PDF-Export: #{text}\nGot #{element} at #{node.source_position.inspect}\n\n" end end diff --git a/app/services/copy/dependency.rb b/app/services/copy/dependency.rb index b92350ef7091..9076775914ef 100644 --- a/app/services/copy/dependency.rb +++ b/app/services/copy/dependency.rb @@ -84,6 +84,8 @@ def perform(params:) copy_dependency(params:) rescue StandardError => e Rails.logger.error { "Failed to copy dependency #{self.class.identifier}: #{e.message}" } + ::OpenProject.logger.error e + result.success = false result.errors.add(:base, :could_not_be_copied, dependency: self.class.human_name) end diff --git a/app/services/users/login_service.rb b/app/services/users/login_service.rb index ac41c18ec662..cf2384453070 100644 --- a/app/services/users/login_service.rb +++ b/app/services/users/login_service.rb @@ -48,9 +48,9 @@ def call! User.current = user set_autologin_cookie if autologin_requested - - successful_login end + + successful_login end private diff --git a/app/services/work_packages/set_attributes_service.rb b/app/services/work_packages/set_attributes_service.rb index aff89c852f0e..aef4758227ba 100644 --- a/app/services/work_packages/set_attributes_service.rb +++ b/app/services/work_packages/set_attributes_service.rb @@ -313,6 +313,8 @@ def reassign_type return if available_types.include?(work_package.type) && work_package.type work_package.type = available_types.first + update_duration + unify_milestone_dates reassign_status assignable_statuses end diff --git a/app/services/work_packages/shared/update_ancestors.rb b/app/services/work_packages/shared/update_ancestors.rb index 21d11eff700f..5d673b7a2b54 100644 --- a/app/services/work_packages/shared/update_ancestors.rb +++ b/app/services/work_packages/shared/update_ancestors.rb @@ -51,8 +51,13 @@ def update_ancestors_all_attributes(work_packages) end def update_each_ancestor(work_packages, changes) - work_packages.map do |wp| - inherit_to_ancestors(wp, changes) + updated_work_package_ids = Set.new + work_packages.filter_map do |wp| + next if updated_work_package_ids.include?(wp.id) + + result = inherit_to_ancestors(wp, changes) + updated_work_package_ids = updated_work_package_ids.merge(result.all_results.map(&:id)) + result end end diff --git a/app/views/versions/_overview.html.erb b/app/views/versions/_overview.html.erb index db32deeac1bd..effd5ca9b5d0 100644 --- a/app/views/versions/_overview.html.erb +++ b/app/views/versions/_overview.html.erb @@ -54,7 +54,9 @@ See COPYRIGHT and LICENSE files for more details. <% end %> <% if version.work_packages.count > 0 %> - <%= progress_bar([version.closed_percent, version.completed_percent], width: '40%', legend: ('%0.0f' % version.completed_percent)) %> + <% closed = version.closed_percent %> + <% done = version.completed_percent - closed %> + <%= progress_bar([closed, done], width: '40%', legend: ('%0.0f' % version.completed_percent)) %>
<%= link_to_if(version.closed_issues_count > 0,
t(:label_x_closed_work_packages_abbr, count: version.closed_issues_count),
diff --git a/config/locales/crowdin/cs.seeders.yml b/config/locales/crowdin/cs.seeders.yml
index 3c0b712c76af..9c592ac25f0f 100644
--- a/config/locales/crowdin/cs.seeders.yml
+++ b/config/locales/crowdin/cs.seeders.yml
@@ -45,7 +45,7 @@ cs:
item_0:
name: Editor pracovních balíčků
item_1:
- name: Work package commenter
+ name: Komentář pracovního balíčku
item_2:
name: Prohlížeč pracovních balíčků
project_roles:
@@ -132,32 +132,32 @@ cs:
welcome:
title: Vítejte v OpenProject!
text: |
- OpenProject is the leading open source project management software. It supports classic, agile as well as hybrid project management and gives you full control over your data.
+ OpenProject je hlavní open source software pro správu projektů. Podporuje klasické, agilní i hybridní řízení projektů a dává vám plnou kontrolu nad vašimi daty.
- Core features and use cases:
+ Základní funkce a použití případů:
- * [Project Portfolio Management](https://www.openproject.org/collaboration-software-features/project-portfolio-management/)
- * [Project Planning and Scheduling](https://www.openproject.org/collaboration-software-features/project-planning-scheduling/)
- * [Task Management and Issue Tracking](https://www.openproject.org/collaboration-software-features/task-management/)
- * [Agile Boards (Scrum and Kanban)](https://www.openproject.org/collaboration-software-features/agile-project-management/)
+ * [Project Portfolio Management](https://www.openproject. rg/collaboration-software-features/project-portfolio-management/)
+ * [Plánování projektů a plánování](https://www.openproject.org/collaboration-software-features/project-planning-scheduling/)
+ * [Správa úloh a sledování problémů](https://www.openproject.org/collaboration-software-features/task-management/)
+ * [Agile Boards (Scrum and Kanban)](https://www. penproject.org/collaboration-software-features/agile-project-management/)
* [Requirements Management and Release Planning](https://www.openproject.org/collaboration-software-features/product-development/)
- * [Time and Cost Tracking, Budgets](https://www.openproject.org/collaboration-software-features/time-tracking/)
- * [Team Collaboration and Documentation](https://www.openproject.org/collaboration-software-features/team-collaboration/)
+ * [Time and Cost Tracking, Budgets](https://www.openproject. rg/collaboration-software-features/time-tracking/)
+ * [Team Collaboration and Documentation](https://www.openproject. rg/collaboration-software-features/tým-collaboration/)
- Welcome to the future of project management.
+ Vítejte v budoucnosti řízení projektu.
- For Admins: You can change this welcome text [here]({{opSetting:base_url}}/admin/settings/general).
+ Pro administrátory: Můžete změnit uvítací text [here]({{opSetting:base_url}}/admin/settings/general).
projects:
demo-project:
name: Demo projekt
- status_explanation: All tasks are on schedule. The people involved know their tasks. The system is completely set up.
- description: This is a short summary of the goals of this demo project.
+ status_explanation: Všechny úkoly probíhají podle harmonogramu. Zúčastněné osoby znají své úkoly. Systém je kompletně nastaven.
+ description: Toto je krátké shrnutí cílů tohoto demo projektu.
news:
item_0:
title: Vítejte ve vašem demo projektu
summary: |
- We are glad you joined.
- In this module you can communicate project news to your team members.
+ Jsme rádi, že jste se připojili.
+ V tomto modulu můžete sdělit zprávy o projektu členům vašeho týmu.
description: Aktuální novinky
categories:
item_0: Kategorie 1 (bude změněno v nastavení projektu)
@@ -179,7 +179,7 @@ cs:
item_0:
name: Seznam přání
item_1:
- name: Short list
+ name: Krátký seznam
item_2:
name: Seznam priorit pro dnešek
item_3:
@@ -195,21 +195,7 @@ cs:
options:
name: Začínáme
text: |
- We are glad you joined! We suggest to try a few things to get started in OpenProject.
-
- Discover the most important features with our [Guided Tour]({{opSetting:base_url}}/projects/demo-project/work_packages/?start_onboarding_tour=true).
-
- _Try the following steps:_
-
- 1. *Invite new members to your project*: → Go to [Members]({{opSetting:base_url}}/projects/demo-project/members) in the project navigation.
- 2. *View the work in your project*: → Go to [Work packages]({{opSetting:base_url}}/projects/demo-project/work_packages) in the project navigation.
- 3. *Create a new work package*: → Go to [Work packages → Create]({{opSetting:base_url}}/projects/demo-project/work_packages/new).
- 4. *Create and update a project plan*: → Go to [Project plan]({{opSetting:base_url}}/projects/demo-project/work_packages?query_id=##query.id:demo_project__query__project_plan) in the project navigation.
- 5. *Activate further modules*: → Go to [Project settings → Modules]({{opSetting:base_url}}/projects/demo-project/settings/modules).
- 6. *Complete your tasks in the project*: → Go to [Work packages → Tasks]({{opSetting:base_url}}/projects/demo-project/work_packages/details/##wp.id:set_date_and_location_of_conference/overview?query_id=##query.id:demo_project__query__tasks).
- Here you will find our [User Guides](https://www.openproject.org/docs/user-guide/).
- Please let us know if you have any questions or need support. Contact us: [support[at]openproject.com](mailto:support@openproject.com).
item_5:
options:
name: Pracovní balíčky
@@ -220,7 +206,7 @@ cs:
item_0:
subject: Zahájení projektu
item_1:
- subject: Organize open source conference
+ subject: Spravovat open source konferenci
children:
item_0:
subject: Nastavit datum a místo konference
@@ -228,9 +214,9 @@ cs:
item_0:
subject: Poslat pozvánku řečníkům
item_1:
- subject: Contact sponsoring partners
+ subject: Kontaktovat sponzorské partnery
item_2:
- subject: Create sponsorship brochure and hand-outs
+ subject: Vytvořte sponzorskou brožuru a podklady
item_1:
subject: Pozvat účastníky konference
item_2:
@@ -243,24 +229,24 @@ cs:
item_0:
subject: Nahrát prezentace na webové stránky
item_1:
- subject: Party for conference supporters :-)
+ subject: Party pro podporovatele konferencí :-)
description: |-
- * [ ] Beer
- * [ ] Snacks
- * [ ] Music
- * [ ] Even more beer
+ * [ ] Pivo
+ * [ ] Pivo
+ * [ ] Hudba
+ * [ ] Ještě více piva
item_4:
subject: Ukončení projektu
scrum-project:
name: Projekt Scrum
- status_explanation: All tasks are on schedule. The people involved know their tasks. The system is completely set up.
- description: This is a short summary of the goals of this demo Scrum project.
+ status_explanation: Všechny úkoly a dílčí projekty probíhají podle harmonogramu. Zúčastněné osoby znají své úkoly. Systém je kompletně nastaven.
+ description: Toto je krátké shrnutí cílů tohoto demo Scrum projektu.
news:
item_0:
title: Vítejte ve vašem Scrum demo projektu
summary: |
- We are glad you joined.
- In this module you can communicate project news to your team members.
+ Jsme rádi, že jste se připojili.
+ V tomto modulu můžete sdělit zprávy o projektu členům vašeho týmu.
versions:
item_0:
name: Bug Backlog
@@ -331,14 +317,14 @@ cs:
name: Úkoly
boards:
kanban:
- name: Kanban board
+ name: Kanban tabule
basic:
name: Tabule úkolů
lists:
item_0:
name: Seznam přání
item_1:
- name: Short list
+ name: Krátký seznam
item_2:
name: Seznam priorit pro dnešek
item_3:
@@ -424,48 +410,5 @@ cs:
item_16:
subject: Vydání v2.0
wiki: |
- ### Sprint planning meeting
-
- _Please document here topics to the Sprint planning meeting_
-
- * Time boxed (8 h)
- * Input: Product Backlog
- * Output: Sprint Backlog
-
- * Divided into two additional time boxes of 4 h:
-
- * The Product Owner presents the [Product Backlog]({{opSetting:base_url}}/projects/your-scrum-project/backlogs) and the priorities to the team and explains the Sprint Goal, to which the team must agree. Together, they prioritize the topics from the Product Backlog which the team will take care of in the next sprint. The team commits to the discussed delivery.
- * The team plans autonomously (without the Product Owner) in detail and breaks down the tasks from the discussed requirements to consolidate a [Sprint Backlog]({{opSetting:base_url}}/projects/your-scrum-project/backlogs).
-
-
- ### Daily Scrum meeting
-
- _Please document here topics to the Daily Scrum meeting_
-
- * Short, daily status meeting of the team.
- * Time boxed (max. 15 min).
- * Stand-up meeting to discuss the following topics from the Task board.
- * What do I plan to do until the next Daily Scrum?
- * What has blocked my work (Impediments)?
- * Scrum Master moderates and notes down Sprint Impediments.
- * Product Owner may participate may participate in order to stay informed.
-
- ### Sprint Review meeting
-
- _Please document here topics to the Sprint Review meeting_
-
- * Time boxed (4 h).
- * A maximum of one hour of preparation time per person.
- * The team shows the product owner and other interested persons what has been achieved in this sprint.
- * Important: no dummies and no PowerPoint! Just finished product functionality (Increments) should be demonstrated.
- * Feedback from Product Owner, stakeholders and others is desired and will be included in further work.
- * Based on the demonstrated functionalities, the Product Owner decides to go live with this increment or to develop it further. This possibility allows an early ROI.
-
-
- ### Sprint Retrospective
- _Please document here topics to the Sprint Retrospective meeting_
- * Time boxed (3 h).
- * After Sprint Review, will be moderated by Scrum Master.
- * The team discusses the sprint: what went well, what needs to be improved to be more productive for the next sprint or even have more fun.
diff --git a/config/locales/crowdin/cs.yml b/config/locales/crowdin/cs.yml
index 8cb8a820e3b4..c576e818848b 100644
--- a/config/locales/crowdin/cs.yml
+++ b/config/locales/crowdin/cs.yml
@@ -65,14 +65,14 @@ cs:
theme_warning: Změna motivu přepíše váš vlastní styl. Vzhled pak bude ztracen. Jste si jisti, že chcete pokračovat?
enterprise:
upgrade_to_ee: "Upgradovat na Enterprise Edici"
- add_token: "Upload an Enterprise edition support token"
+ add_token: "Nahrát podpůrný token Enterprise Edition"
delete_token_modal:
- text: "Are you sure you want to remove the current Enterprise edition token used?"
+ text: "Jste si jisti, že chcete odstranit použitý aktuální token verze Enterprise?"
title: "Odstranit Token"
replace_token: "Nahradit aktuální podpůrný token"
order: "Objednat Enterprise Edici"
- paste: "Paste your Enterprise edition support token"
- required_for_feature: "This add-on is only available with an active Enterprise edition support token."
+ paste: "Vložte svůj podpůrný token Enterprise Edition"
+ required_for_feature: "Tato funkce je dostupná pouze s aktivním podpůrným tokenem pro Enterprise Edition."
enterprise_link: "Pro více informací klikněte zde."
start_trial: "Začít zkušební verzi"
book_now: "Rezervujte nyní"
@@ -202,20 +202,20 @@ cs:
reorder_alphabetical: "Změnit pořadí abecedně"
reorder_confirmation: "Varování: Aktuální pořadí dostupných hodnot bude ztraceno. Pokračovat?"
instructions:
- is_required: "Mark the custom field as required. This will make it mandatory to fill in the field when creating new or updating existing resources."
- is_for_all: "Mark the custom field as available in all existing and new projects."
- searchable: "Include the field values when using the global search functionality."
- editable: "Allow the field to be editable by users themselves."
- visible: "Make field visible for all users (non-admins) in the project overview and displayed in the project details widget on the Project Overview."
+ is_required: "Označit vlastní pole jako povinné. Bude povinné vyplnit pole při vytváření nových nebo aktualizaci existujících zdrojů."
+ is_for_all: "Označit vlastní pole jako dostupné ve všech existujících a nových projektech."
+ searchable: "Zahrnout hodnoty polí při použití globální funkce vyhledávání."
+ editable: "Umožnit editaci pole samotnými uživateli."
+ visible: "Zviditelnit pole pro všechny uživatele (neadminy) v přehledu projektu a zobrazit ve widgetu podrobností projektu v přehledu projektu."
is_filter: >
- Allow the custom field to be used in a filter in work package views. Note that only with 'For all projects' selected, the custom field will show up in global views.
+ Povolit použití vlastního pole ve filtru v zobrazení pracovního balíčku. Všimněte si, že pouze s vybraným 'pro všechny projekty' se vlastní pole zobrazí v globálních zobrazeních.
tab:
no_results_title_text: V současné době nejsou žádná vlastní pole.
no_results_content_text: Vytvořit nové vlastní pole
concatenation:
single: "nebo"
global_search:
- placeholder: "Search in %{app_title}"
+ placeholder: "Hledat v %{app_title}"
overwritten_tabs:
wiki_pages: "Wiki"
messages: "Fórum"
@@ -281,17 +281,17 @@ cs:
no_results_content_text: Přidání člena do projektu
invite_by_mail: "Poslat pozvánku do %{mail}"
send_invite_to: "Odeslat pozvánky"
- no_modify_on_shared: "You currently cannot modify or remove shared memberships through the member page. Use the sharing modal instead."
+ no_modify_on_shared: "Momentálně nemůžete měnit nebo odebrat sdílená členství přes stránku člena. Používejte místo toho modal sdílení."
columns:
- shared: "Shared"
+ shared: "Sdílené"
filters:
- all_shares: 'All shares'
+ all_shares: 'Všechny akcie'
menu:
all: 'Vše'
invited: 'Pozvané'
locked: 'Uzamčeno'
project_roles: 'Projektové role'
- wp_shares: 'Work package shares'
+ wp_shares: 'Sdílení pracovních balíčků'
groups: 'Skupiny'
my:
access_token:
@@ -373,7 +373,7 @@ cs:
settings: "Nastavení"
form_configuration: "Konfigurace formuláře"
more_info_text_html: >
- Enterprise edition allows you to customize form configuration with these additional add-ons:
%{set_protocol}
, but the request is an %{actual_protocol}
request. This will result in errors! You will need to set the following configuration value: %{setting_value}
. Please see the installation documentation on how to set this configuration.
+ Vaše aplikace běží s režimem HTTPS nastaveným na %{set_protocol}
, ale žádost je %{actual_protocol}
požadavek. To povede k chybám! Budete muset nastavit následující hodnotu konfigurace: %{setting_value}
. Přečtěte si prosím dokumentaci o instalaci , jak nastavit tuto konfiguraci.
hostname_mismatch:
title: "Nastavení hostname se neshoduje"
text_html: >
- Your application is running with its host name setting set to %{set_hostname}
, but the request is a %{actual_hostname}
hostname. This will result in errors! Go to System settings and change the "Host name" setting to correct this.
+ Vaše aplikace běží s nastavením názvu hostitele nastaveným na %{set_hostname}
, ale žádost je %{actual_hostname}
název hostitele. To bude mít za následek chyby! Přejděte do Nastavení systému a změňte nastavení "Název hostitele" pro opravu.
menu_item: "Položka nabídky"
menu_item_setting: "Viditelnost"
wiki_menu_item_for: 'Položka nabídky pro stránku wiki "%{title}"'
@@ -3121,14 +3121,14 @@ cs:
other: "%{count} uživatelů"
filter:
project_member: 'Člen projektu'
- not_project_member: 'Not project member'
- project_group: 'Project group'
- not_project_group: 'Not project group'
+ not_project_member: 'Není členem projektu'
+ project_group: 'Skupina projektů'
+ not_project_group: 'Není skupina projektů'
role: 'Role'
type: 'Typ'
- label_search: "Search for users to invite"
+ label_search: "Hledat uživatele pro pozvání"
label_search_placeholder: "Hledat podle uživatele nebo e-mailové adresy"
- label_toggle_all: "Toggle all shares"
+ label_toggle_all: "Přepnout všechny sdílené"
permissions:
comment: "Komentář"
comment_description: "Může zobrazit a komentovat tento pracovní balíček."
@@ -3139,29 +3139,29 @@ cs:
view_description: "Může zobrazit tento pracovní balíček."
remove: "Odebrat"
share: "Sdílet"
- text_empty_search_description: "There are no users with the current filter criteria."
+ text_empty_search_description: "Neexistují žádní uživatelé s aktuálními kritérii filtru."
text_empty_search_header: "Nenašli jsme žádné odpovídající výsledky."
- text_empty_state_description: "The work package has not been shared with anyone yet."
- text_empty_state_header: "No shared members."
+ text_empty_state_description: "Pracovní balíček zatím nebyl s nikým sdílen."
+ text_empty_state_header: "Žádní sdílení členové."
text_user_limit_reached: "Adding additional users will exceed the current limit. Please contact an administrator to increase the user limit to ensure external users are able to access this work package."
text_user_limit_reached_admins: 'Adding additional users will exceed the current limit. Please upgrade your plan to be able to add more users.'
warning_user_limit_reached: >
Adding additional users will exceed the current limit. Please contact an administrator to increase the user limit to ensure external users are able to access this work package.
warning_user_limit_reached_admin: >
Adding additional users will exceed the current limit. Please upgrade your plan to be able to ensure external users are able to access this work package.
- warning_no_selected_user: "Please select users to share this work package with"
- warning_locked_user: "The user %{user} is locked and cannot be shared with"
+ warning_no_selected_user: "Vyberte uživatele pro sdílení tohoto pracovního balíčku "
+ warning_locked_user: "Uživatel %{user} je uzamčen a nemůže být s ním sdíleno"
user_details:
locked: "Uzamčený uživatel"
invited: "Pozvánka odeslána"
resend_invite: "Znovu odeslat."
- invite_resent: "Invite has been resent"
+ invite_resent: "Pozvánka byla znovu odeslána"
not_project_member: "Není členem projektu"
- project_group: "Group members might have additional privileges (as project members)"
- not_project_group: "Group (shared with all members)"
- additional_privileges_project: "Might have additional privileges (as project member)"
- additional_privileges_group: "Might have additional privileges (as group member)"
- additional_privileges_project_or_group: "Might have additional privileges (as project or group member)"
+ project_group: "Členové skupiny mohou mít dodatečná práva (jako členové projektu)"
+ not_project_group: "Skupina (sdílená se všemi členy)"
+ additional_privileges_project: "Může mít další oprávnění (jako člen projektu)"
+ additional_privileges_group: "Může mít dodatečná oprávnění (jako člen skupiny)"
+ additional_privileges_project_or_group: "Může mít dodatečná oprávnění (jako člen skupiny)"
working_days:
info: >
Days that are not selected are skipped when scheduling work packages (and not included in the day count). These can be overriden at a work-package level.
@@ -3169,7 +3169,7 @@ cs:
Dates added to the list below are considered non-working and skipped when scheduling work packages.
change_button: "Změnit pracovní dny"
warning: >
- Changing which days of the week are considered working days or non-working days can affect the start and finish days of all work packages in all projects in this instance. %{ext_example}
) or mime types (e.g., %{mime_example}
). %{set_protocol}
, but the request is an %{actual_protocol}
request. This will result in errors! You will need to set the following configuration value: %{setting_value}
. Please see the installation documentation on how to set this configuration.
+ hostname_mismatch:
+ title: "Hostname setting mismatch"
+ text_html: >
+ Your application is running with its host name setting set to %{set_hostname}
, but the request is a %{actual_hostname}
hostname. This will result in errors! Go to System settings and change the "Host name" setting to correct this.
+ menu_item: "Menu item"
+ menu_item_setting: "Visibility"
+ wiki_menu_item_for: 'Menu item for wikipage "%{title}"'
+ wiki_menu_item_setting: "Visibility"
+ wiki_menu_item_new_main_item_explanation: >
+ You are deleting the only main wiki menu item. You now have to choose a wiki page for which a new main item will be generated. To delete the wiki the wiki module can be deactivated by project administrators.
+ wiki_menu_item_delete_not_permitted: The wiki menu item of the only wiki page cannot be deleted.
+ #TODO: merge with work_packages top level key
+ work_package:
+ updated_automatically_by_child_changes: |
+ _Updated automatically by changing values within child work package %{child}_
+ destroy:
+ info: "Deleting the work package is an irreversible action."
+ title: "Delete the work package"
+ sharing:
+ count:
+ zero: "0 users"
+ one: "1 user"
+ other: "%{count} users"
+ filter:
+ project_member: 'Project member'
+ not_project_member: 'Not project member'
+ project_group: 'Project group'
+ not_project_group: 'Not project group'
+ role: 'Role'
+ type: 'Type'
+ label_search: "Search for users to invite"
+ label_search_placeholder: "Search by user or email address"
+ label_toggle_all: "Toggle all shares"
+ permissions:
+ comment: "Comment"
+ comment_description: "Can view and comment this work package."
+ denied: "You don't have permissions to share work packages."
+ edit: "Edit"
+ edit_description: "Can view, comment and edit this work package."
+ view: "View"
+ view_description: "Can view this work package."
+ remove: "Remove"
+ share: "Share"
+ text_empty_search_description: "There are no users with the current filter criteria."
+ text_empty_search_header: "We couldn't find any matching results."
+ text_empty_state_description: "The work package has not been shared with anyone yet."
+ text_empty_state_header: "No shared members."
+ text_user_limit_reached: "Adding additional users will exceed the current limit. Please contact an administrator to increase the user limit to ensure external users are able to access this work package."
+ text_user_limit_reached_admins: 'Adding additional users will exceed the current limit. Please upgrade your plan to be able to add more users.'
+ warning_user_limit_reached: >
+ Adding additional users will exceed the current limit. Please contact an administrator to increase the user limit to ensure external users are able to access this work package.
+ warning_user_limit_reached_admin: >
+ Adding additional users will exceed the current limit. Please upgrade your plan to be able to ensure external users are able to access this work package.
+ warning_no_selected_user: "Please select users to share this work package with"
+ warning_locked_user: "The user %{user} is locked and cannot be shared with"
+ user_details:
+ locked: "Locked user"
+ invited: "Invite sent. "
+ resend_invite: "Resend."
+ invite_resent: "Invite has been resent"
+ not_project_member: "Not a project member"
+ project_group: "Group members might have additional privileges (as project members)"
+ not_project_group: "Group (shared with all members)"
+ additional_privileges_project: "Might have additional privileges (as project member)"
+ additional_privileges_group: "Might have additional privileges (as group member)"
+ additional_privileges_project_or_group: "Might have additional privileges (as project or group member)"
+ working_days:
+ info: >
+ Days that are not selected are skipped when scheduling work packages (and not included in the day count). These can be overriden at a work-package level.
+ instance_wide_info: >
+ Dates added to the list below are considered non-working and skipped when scheduling work packages.
+ change_button: "Change working days"
+ warning: >
+ Changing which days of the week are considered working days or non-working days can affect the start and finish days of all work packages in all projects in this instance. +```shell apt-get install subversion libapache2-mod-perl2 libapache2-svn a2enmod proxy proxy_http dav dav_svn -+``` ### Permissions @@ -274,10 +274,10 @@ We can exploit git-http-backend to serve Git repositories through HTTP(s) with A This method additionally requires the `cgi` Apache module to be installed. The following commands are required for Debian / Ubuntu, please adjust accordingly for other distributions: -
+```shell apt-get install git libapache2-mod-perl2 a2enmod proxy proxy_http cgi -+``` You need to locate the location of the `git-http-backend` CGI wrapper shipping with the Git installation. Depending on your installation, it may reside in `/usr/libexec/git-core/git-http-backend`. @@ -293,77 +293,78 @@ Thus, if you use a separate user for Apache and OpenProject, they need to reside We provide an example apache configuration. Some details are explained inline as comments. - # Load OpenProject per module used to authenticate requests against the user database. - # Be sure that the OpenProjectAuthentication.pm script is located in your perl path. - PerlSwitches -I/srv/www/perl-lib -T - PerlLoadModule Apache::OpenProjectAuthentication - -
/var/log/apache2/error.log+You can find the error logs for apache here: `/var/log/apache2/error.log` -The OpenProject logfile can be found here: -
/home/openproject/openproject/log/production.log+The OpenProject logfile can be found here: `/home/openproject/openproject/log/production.log` If an error occurs, it should be logged there. @@ -441,10 +439,9 @@ If you need to restart the server (for example after a configuration change), do * **When accessing OpenProject, I get an error page. How do I find out what went wrong?** - Things can go wrong on different levels. You can find the apache error logs here: -
/var/log/apache2/error.log- The OpenProject log can be found here: -
/home/openproject/openproject/log/production.log+ Things can go wrong on different levels. You can find the apache error logs here: `/var/log/apache2/error.log` + + The OpenProject log can be found here: `/home/openproject/openproject/log/production.log` * **I cannot solve an error, not even with the log files. How do I get help?** diff --git a/docs/installation-and-operations/installation/packaged/README.md b/docs/installation-and-operations/installation/packaged/README.md index b790e43fea99..49f057e687df 100644 --- a/docs/installation-and-operations/installation/packaged/README.md +++ b/docs/installation-and-operations/installation/packaged/README.md @@ -450,7 +450,7 @@ If you have a separate server that is terminating SSL and only forwarding/proxyi - Finally, to let OpenProject know that it should create links with 'https' when no request is available (for example, when sending emails), you need to set the following setting: `openproject config:set SERVER_PROTOCOL_FORCE_HTTPS="true"` followed by an `openproject configure`. This ensures that OpenProject responds correctly with secure cookies even though it was not configured for https in the server configuration. -Here an example for external SSL/TLS terminaltion with apache (httpd): +Here an example for external SSL/TLS termination with apache (httpd): > **Note:** There is [another example](../docker/#1-virtual-host-root) for external SSL/TLS termination for **docker-compose** installations @@ -555,7 +555,7 @@ Also, this setting will control what is the default language for new users if th With this last step confirmed, the OpenProject wizard will complete, and apply all the configuration options that you have just selected. This might take a few minutes depending on your machine and internet connection, as OpenProject might need to install additional packages (such as the web server, database) depending on your selections. -In case this process crashes or exits with an obvious error, please keep the output and send your configuration from `/etc/openproject/installer.dat` (removing any passwords from it) to us at support@openproject.com , or [reach out to the community forums](https://community.openproject.com/projects/openproject/forums). +In case this process crashes or exits with an obvious error, please keep the output and send your configuration from `/etc/openproject/installer.dat` (removing any passwords from it) to us at support@openproject.com , or [reach out to the community forums](https://community.openproject.org/projects/openproject/forums). When this process completes, it will have started the internal application and web servers, the background jobs to process work-intensive jobs, and set up the connection to the database. diff --git a/docs/installation-and-operations/misc/textile-migration/README.md b/docs/installation-and-operations/misc/textile-migration/README.md index d4b034999b5a..4e4a17be2178 100644 --- a/docs/installation-and-operations/misc/textile-migration/README.md +++ b/docs/installation-and-operations/misc/textile-migration/README.md @@ -15,7 +15,7 @@ You need to run this migration on an OpenProject version < 13.0, as the conversi ## Dependencies -We depend on `pandoc` (https://pandoc.org/) for the conversion of all formattable fields in OpenProject. It provides automated means to migrate between many input and output formats, in our case from Textile to GitHub-flavored Markdown. +We depend on `pandoc` (https://pandoc.org) for the conversion of all formattable fields in OpenProject. It provides automated means to migrate between many input and output formats, in our case from Textile to GitHub-flavored Markdown. If you do not have an executable pandoc version of at least version 2.0 in your path, OpenProject will try download an AMD64 static linked binary for pandoc (Currently, this would be version 2.3.2). This version will be made available to OpenProject through `
and @ did not prevent code execution in the work package description. - The “Spent time” link on the work package table caused an error 404 in subfolder installations - ([#24427](https://community.openproject.com/wp/24427)). + ([#24427](https://community.openproject.org/wp/24427)). - Line breaks were not displayed in the work package description - ([#24428](https://community.openproject.com/wp/24428)). + ([#24428](https://community.openproject.org/wp/24428)). - Timeline - Timelines which were displayed in aggregation were not shown when loaded initially. - Projects - Projects could not be copied - ([#24323](https://community.openproject.com/wp/24323)). + ([#24323](https://community.openproject.org/wp/24323)). - Search - The search displayed only case-sensitive results - ([#24282](https://community.openproject.com/wp/24282)). + ([#24282](https://community.openproject.org/wp/24282)). - The pagination in the search results was broken - ([#24345](https://community.openproject.com/wp/24345)). + ([#24345](https://community.openproject.org/wp/24345)). - Other - A deprecation warning was displayed whenever a cronjob for incoming emails was invoked - ([#24306](https://community.openproject.com/wp/24306)). + ([#24306](https://community.openproject.org/wp/24306)). - Several design bugs have been fixed - ([#24263](https://community.openproject.com/wp/24263), - [#24274](https://community.openproject.com/wp/24274), - [#24286](https://community.openproject.com/wp/24286), - [#24289](https://community.openproject.com/wp/24289), - [#24297](https://community.openproject.com/wp/24297), - [#24301](https://community.openproject.com/wp/24301), - [#24334](https://community.openproject.com/wp/24334), - [#24335](https://community.openproject.com/wp/24335), - [#24339](https://community.openproject.com/wp/24339), - [#24372](https://community.openproject.com/wp/24372), - [#24373](https://community.openproject.com/wp/24373)). + ([#24263](https://community.openproject.org/wp/24263), + [#24274](https://community.openproject.org/wp/24274), + [#24286](https://community.openproject.org/wp/24286), + [#24289](https://community.openproject.org/wp/24289), + [#24297](https://community.openproject.org/wp/24297), + [#24301](https://community.openproject.org/wp/24301), + [#24334](https://community.openproject.org/wp/24334), + [#24335](https://community.openproject.org/wp/24335), + [#24339](https://community.openproject.org/wp/24339), + [#24372](https://community.openproject.org/wp/24372), + [#24373](https://community.openproject.org/wp/24373)). Thanks a lot to the community, in particular to Marc Vollmer, Markus Hillenbrand, Nicolai Daniel and Christophe Mornet for [reporting bugs](../../../development/report-a-bug/)! For further information on the release, please refer to the -[Changelog v.6.1.1](https://community.openproject.com/versions/821) +[Changelog v.6.1.1](https://community.openproject.org/versions/821) or take a look at [GitHub](https://github.com/opf/openproject/tree/v6.1.1). diff --git a/docs/release-notes/6/6-1-2/README.md b/docs/release-notes/6/6-1-2/README.md index 4ab8449939ec..bc6a41a8a751 100644 --- a/docs/release-notes/6/6-1-2/README.md +++ b/docs/release-notes/6/6-1-2/README.md @@ -14,20 +14,20 @@ recommend to update your OpenProject installation to this version. ## Features (5) - Added missing auth fields to user - endpoint [24503](https://community.openproject.com/wp/24503). + endpoint [24503](https://community.openproject.org/wp/24503). - Allow users to be uniquely identified by - login [24504](https://community.openproject.com/wp/24504). + login [24504](https://community.openproject.org/wp/24504). - Configuration option to hide login field during signup (email - only) [24505](https://community.openproject.com/wp/24505/relations). + only) [24505](https://community.openproject.org/wp/24505/relations). - Configuration option for registration footer - [24404](https://community.openproject.com/wp/24404). + [24404](https://community.openproject.org/wp/24404). - Remove length constraints of category - name [24446](https://community.openproject.com/wp/24446). + name [24446](https://community.openproject.org/wp/24446). ## Bug fixes (16) You can find a detailed list of the bug -fixes [here.](https://community.openproject.com/versions/822) +fixes [here.](https://community.openproject.org/versions/822) ## Credits diff --git a/docs/release-notes/6/6-1-3/README.md b/docs/release-notes/6/6-1-3/README.md index 11893294f4f5..bb044b8e5046 100644 --- a/docs/release-notes/6/6-1-3/README.md +++ b/docs/release-notes/6/6-1-3/README.md @@ -15,11 +15,11 @@ your OpenProject installation to this version. - Users who have multiple roles which grant the “View work packages” permission could not view all work packages in a project - ([#24509](https://community.openproject.com/wp/24509)). + ([#24509](https://community.openproject.org/wp/24509)). This error has been fixed. For further information on the release, please refer to the -[Changelog v.6.1.3](https://community.openproject.com/versions/826) +[Changelog v.6.1.3](https://community.openproject.org/versions/826) or take a look at [GitHub](https://github.com/opf/openproject/tree/v6.1.3). diff --git a/docs/release-notes/6/6-1-4/README.md b/docs/release-notes/6/6-1-4/README.md index f6fcdf326141..20c79203166d 100644 --- a/docs/release-notes/6/6-1-4/README.md +++ b/docs/release-notes/6/6-1-4/README.md @@ -16,22 +16,22 @@ your OpenProject installation to this ## Bug fixes (7) - Work package filter for subprojects not working - ([#24550](https://community.openproject.com/wp/24550)). + ([#24550](https://community.openproject.org/wp/24550)). - Last updated work package information is always shown in UTC - ([#24498](https://community.openproject.com/wp/24498)). + ([#24498](https://community.openproject.org/wp/24498)). - Design error on system settings page - ([#24497](https://community.openproject.com/wp/24497)). + ([#24497](https://community.openproject.org/wp/24497)). - Missing translation on workflow administration page - ([#24495](https://community.openproject.com/wp/24495)). + ([#24495](https://community.openproject.org/wp/24495)). - Very long custom field names break design on custom field settings page - ([#24407](https://community.openproject.com/wp/24407)). + ([#24407](https://community.openproject.org/wp/24407)). - Filter “Show all work packages” on MyPage did not work correctly. - Project filter was lost on the second page of the search results page. For further information on the release, please refer to the -[Changelog v.6.1.4](https://community.openproject.com/versions/827) +[Changelog v.6.1.4](https://community.openproject.org/versions/827) or take a look at [GitHub](https://github.com/opf/openproject/tree/v6.1.4). diff --git a/docs/release-notes/6/6-1-5/README.md b/docs/release-notes/6/6-1-5/README.md index eef5f1ca5eb9..1f6ca0355baa 100644 --- a/docs/release-notes/6/6-1-5/README.md +++ b/docs/release-notes/6/6-1-5/README.md @@ -14,7 +14,7 @@ your OpenProject installation to this version. ## Features (1) - The OpenProject Favicon was updated to a new color - ([#24459](https://community.openproject.com/wp/24459)). + ([#24459](https://community.openproject.org/wp/24459)). ## Bug fixes (11) @@ -22,32 +22,32 @@ your OpenProject installation to this version. caused an error. - The breadcrumb was partially hidden when following the link to activities - ([#24477](https://community.openproject.com/wp/24477)). + ([#24477](https://community.openproject.org/wp/24477)). - The work package toolbar menu was not visible on small screens - ([#24679](https://community.openproject.com/wp/24679)). + ([#24679](https://community.openproject.org/wp/24679)). - Work package split screen on mobile was not displayed correctly - ([#24699](https://community.openproject.com/wp/24699)). + ([#24699](https://community.openproject.org/wp/24699)). - An error message related to remaining hours was shown when editing child work packages - ([#24553](https://community.openproject.com/wp/24553)). + ([#24553](https://community.openproject.org/wp/24553)). - Sorting by date in time reports and cost reports did not work correctly - ([#24567](https://community.openproject.com/wp/24567)). + ([#24567](https://community.openproject.org/wp/24567)). - Duplicated wiki pages could not be removed - ([#24582](https://community.openproject.com/wp/24582)). + ([#24582](https://community.openproject.org/wp/24582)). - Error shown when editing a user and using a reverse proxy server - ([#24622](https://community.openproject.com/wp/24622)). + ([#24622](https://community.openproject.org/wp/24622)). - Inactive users were shown on the homescreen of the OpenProject instance - ([#24657](https://community.openproject.com/wp/24657)). + ([#24657](https://community.openproject.org/wp/24657)). - Links in the breadcrumb were missing - ([#24706](https://community.openproject.com/wp/24706), - [#24676](https://community.openproject.com/wp/24676)). + ([#24706](https://community.openproject.org/wp/24706), + [#24676](https://community.openproject.org/wp/24676)). - The PDF export showed an internal error when using certain font types. For further information on the release, please refer to the -[Changelog v.6.1.5](https://community.openproject.com/versions/828) +[Changelog v.6.1.5](https://community.openproject.org/versions/828) or take a look at [GitHub](https://github.com/opf/openproject/tree/v6.1.5). diff --git a/docs/release-notes/7/7-0-0/README.md b/docs/release-notes/7/7-0-0/README.md index fff1968c84ad..9e910673a942 100644 --- a/docs/release-notes/7/7-0-0/README.md +++ b/docs/release-notes/7/7-0-0/README.md @@ -16,7 +16,7 @@ table, multi-select custom fields and much more. ## New integrated Gantt chart / timeline OpenProject 7.0 introduces a new Gantt chart which is integrated in the -work package table ([#13785](https://community.openproject.com/wp/13785)). +work package table ([#13785](https://community.openproject.org/wp/13785)). The new timeline is much more interactive and user-friendly than the old timeline. @@ -27,7 +27,7 @@ timeline. You can display hierarchies on the work package table and collapse and expand them -([#24647](https://community.openproject.com/wp/24647)). +([#24647](https://community.openproject.org/wp/24647)). @@ -35,7 +35,7 @@ expand them With OpenProject 7.0 you can configure which attributes are displayed for a work package type -([#24123](https://community.openproject.com/wp/24123)). +([#24123](https://community.openproject.org/wp/24123)). You can therefore control which attributes are shown and which are hidden by default. @@ -47,7 +47,7 @@ hidden by default. The work package table now supports filtering based on fixed dates. This affects all date attributes (e.g. start / due date, created on / updated on) -([#22585](https://community.openproject.com/projects/telekom/work_packages/22585)). +([#22585](https://community.openproject.org/projects/telekom/work_packages/22585)). @@ -56,7 +56,7 @@ on) The header navigation in OpenProject is updated and displays the current project. Additionally, the logo has been centered and existing menus have been reordered -([#24465](https://community.openproject.com/projects/design/work_packages/24465)). +([#24465](https://community.openproject.org/projects/design/work_packages/24465)). @@ -64,7 +64,7 @@ have been reordered As an administrator you can archive and delete projects right from the project settings -([#24913](https://community.openproject.com/wp/24913)). +([#24913](https://community.openproject.org/wp/24913)). @@ -72,7 +72,7 @@ project settings With the zen mode on the work package table, you can maximize the available screen real estate by hiding the side and top navigation -([#18216](https://community.openproject.com/wp/18216)). +([#18216](https://community.openproject.org/wp/18216)). This provides a cleaner and larger user interface to work with. @@ -83,7 +83,7 @@ This provides a cleaner and larger user interface to work with. Users of the OpenProject [Enterprise on-premises](https://www.openproject.org/enterprise-edition/) and [Enterprise cloud](https://www.openproject.org/hosting/) can create multi-select custom fields -([#24793](https://community.openproject.com/wp/24793)). +([#24793](https://community.openproject.org/wp/24793)). With these custom fields you can select multiple values for work package custom fields at once and also filter based on them. @@ -96,8 +96,8 @@ Users of the OpenProject Enterprise cloud and Enterprise on-premises edition can their own company’s logo instead of the OpenProject logo. Additionally, you can change the colors by using a custom color scheme -([#18099](https://community.openproject.com/projects/gmbh/work_packages/18099), -[#24460](https://community.openproject.com/projects/gmbh/work_packages/24460)). +([#18099](https://community.openproject.org/projects/gmbh/work_packages/18099), +[#24460](https://community.openproject.org/projects/gmbh/work_packages/24460)). @@ -115,5 +115,5 @@ user experience for users accessing OpenProject on a mobile device. OpenProject 7.0 contains a large number of bugs fixes. For an extensive overview of bug fixes please refer to the [following -list](https://community.openproject.com/projects/openproject/work_packages?query_props=%7B%22c%22:%5B%22id%22,%22subject%22,%22type%22,%22status%22,%22assignee%22%5D,%22p%22:%22openproject%22,%22t%22:%22parent:desc%22,%22f%22:%5B%7B%22n%22:%22version%22,%22o%22:%22%253D%22,%22t%22:%22list_optional%22,%22v%22:%22750%22%7D,%7B%22n%22:%22type%22,%22o%22:%22%253D%22,%22t%22:%22list_model%22,%22v%22:%221%22%7D,%7B%22n%22:%22subprojectId%22,%22o%22:%22*%22,%22t%22:%22list_subprojects%22,%22v%22:%5B%5D%7D%5D,%22pa%22:1,%22pp%22:20%7D). +list](https://community.openproject.org/projects/openproject/work_packages?query_props=%7B%22c%22:%5B%22id%22,%22subject%22,%22type%22,%22status%22,%22assignee%22%5D,%22p%22:%22openproject%22,%22t%22:%22parent:desc%22,%22f%22:%5B%7B%22n%22:%22version%22,%22o%22:%22%253D%22,%22t%22:%22list_optional%22,%22v%22:%22750%22%7D,%7B%22n%22:%22type%22,%22o%22:%22%253D%22,%22t%22:%22list_model%22,%22v%22:%221%22%7D,%7B%22n%22:%22subprojectId%22,%22o%22:%22*%22,%22t%22:%22list_subprojects%22,%22v%22:%5B%5D%7D%5D,%22pa%22:1,%22pp%22:20%7D). diff --git a/docs/release-notes/7/7-0-1/README.md b/docs/release-notes/7/7-0-1/README.md index f361ae235985..03a070fc5a57 100644 --- a/docs/release-notes/7/7-0-1/README.md +++ b/docs/release-notes/7/7-0-1/README.md @@ -15,47 +15,47 @@ your OpenProject installation to this version. ## Bug fixes (15) - The page navigation in the forums was not displayed - ([#25463](https://community.openproject.com/wp/25463)) + ([#25463](https://community.openproject.org/wp/25463)) - The Zen mode raised a JS error on iOS - ([#25461](https://community.openproject.com/wp/25461)) + ([#25461](https://community.openproject.org/wp/25461)) - The mobile dropdown menus closed on click on a child menu item - ([#25460](https://community.openproject.com/wp/25460)) + ([#25460](https://community.openproject.org/wp/25460)) - Error on position attribute (cannot write read-only attributes) when copying work package - ([#25458](https://community.openproject.com/wp/25458)) + ([#25458](https://community.openproject.org/wp/25458)) - Work package inline-create fails when subproject filter is active - ([#25455](https://community.openproject.com/wp/25455)) + ([#25455](https://community.openproject.org/wp/25455)) - Show loading indicator earlier when switching queries through dropdown - ([#25454](https://community.openproject.com/wp/25454)) + ([#25454](https://community.openproject.org/wp/25454)) - Button text alignment for meeting and budget create button wrong - ([#25447](https://community.openproject.com/wp/25447)) + ([#25447](https://community.openproject.org/wp/25447)) - Costs (Budget) filter not applied on saved query - ([#25446](https://community.openproject.com/wp/25446)) + ([#25446](https://community.openproject.org/wp/25446)) - Project settings not accessible with a project user custom field - ([#25442](https://community.openproject.com/wp/25442)) + ([#25442](https://community.openproject.org/wp/25442)) - Version custom field of type “List” could not be assigned - ([#25439](https://community.openproject.com/wp/25439)) + ([#25439](https://community.openproject.org/wp/25439)) - Moving columns left/right while retaining default column set did not save - ([#25438](https://community.openproject.com/wp/25438)) + ([#25438](https://community.openproject.org/wp/25438)) - The drop down menu of the mobile create button opened in the wrong direction - ([#25433](https://community.openproject.com/wp/25433)) + ([#25433](https://community.openproject.org/wp/25433)) - Inline edit text inputs did not take up the entire possible width - ([#25430](https://community.openproject.com/wp/25430)) + ([#25430](https://community.openproject.org/wp/25430)) - Sums cannot be displayed on second query unless deactivated first - ([#25420](https://community.openproject.com/wp/25420)) + ([#25420](https://community.openproject.org/wp/25420)) - Subject and back button in fullscreen view were not aligned correctly - ([#25378](https://community.openproject.com/wp/25378)) + ([#25378](https://community.openproject.org/wp/25378)) Thanks a lot to the community, in particular to Mike Lewis and Harsha BS for reporting and fixing bugs! For further information on the release, please refer to the [Changelog -v7.0.1](https://community.openproject.com/versions/924) +v7.0.1](https://community.openproject.org/versions/924) or take a look at [GitHub](https://github.com/opf/openproject/tree/v7.0.1). diff --git a/docs/release-notes/7/7-0-2/README.md b/docs/release-notes/7/7-0-2/README.md index cd8ed8afeec9..7cbb7e49c550 100644 --- a/docs/release-notes/7/7-0-2/README.md +++ b/docs/release-notes/7/7-0-2/README.md @@ -17,24 +17,24 @@ We recommend the update to the current version. ## Bug fixes (6) - \[Firefox only\] Work packages subject only show three dots - ([#25520](https://community.openproject.com/wp/25520)) + ([#25520](https://community.openproject.org/wp/25520)) - Work packages in list cannot be selected next to subject (in hierarchy mode) - ([#25493](https://community.openproject.com/wp/25493)) + ([#25493](https://community.openproject.org/wp/25493)) - “View” link on repository page links to landing page - ([#25487](https://community.openproject.com/wp/25487)) + ([#25487](https://community.openproject.org/wp/25487)) - Custom colors for work package loading animation - ([#25481](https://community.openproject.com/wp/25481)) + ([#25481](https://community.openproject.org/wp/25481)) - Invalid SQL statement produced by watchers filter - ([#25480](https://community.openproject.com/wp/25480)) + ([#25480](https://community.openproject.org/wp/25480)) - Selectable versions for version filter not sorted - ([#25465](https://community.openproject.com/wp/25465)) + ([#25465](https://community.openproject.org/wp/25465)) Thanks a lot to the community, in particular to Peter Spiess-Knafl for reporting bugs! For further information on the release, please refer to the [Changelog -v7.0.2](https://community.openproject.com/versions/837) +v7.0.2](https://community.openproject.org/versions/837) or take a look at [GitHub](https://github.com/opf/openproject/tree/v7.0.2). diff --git a/docs/release-notes/7/7-0-3/README.md b/docs/release-notes/7/7-0-3/README.md index 298611c62d52..a8ac4b4b253a 100644 --- a/docs/release-notes/7/7-0-3/README.md +++ b/docs/release-notes/7/7-0-3/README.md @@ -19,23 +19,23 @@ news](https://www.openproject.org/blog/openproject-7-0-3-released/). - Boolean custom fields were set to true when copying a work package with such a field activated. - ([#25494](https://community.openproject.com/wp/25494)) + ([#25494](https://community.openproject.org/wp/25494)) - Filtering for boolean custom fields did not function properly. - ([#25570](https://community.openproject.com/wp/25570)) + ([#25570](https://community.openproject.org/wp/25570)) - The names of work packages have been escaped needlessly in the relations autocompleter. - ([#25534](https://community.openproject.com/wp/25534)) + ([#25534](https://community.openproject.org/wp/25534)) - The height of the query dropdown no longer exceeds the total available space when lots of queries are saved. - ([#25572](https://community.openproject.com/wp/25572)) + ([#25572](https://community.openproject.org/wp/25572)) - Bulk deleting work packages across more than one project failed with an error. - ([#25569](https://community.openproject.com/wp/25569)) + ([#25569](https://community.openproject.org/wp/25569)) - Removed an unnecessary horizontal scrollbar in the query dropdown. - ([#25593](https://community.openproject.com/wp/25593)) + ([#25593](https://community.openproject.org/wp/25593)) - Path parameters of the repository view are now preserved when the user needed to pass through the login screen first. - ([#25586](https://community.openproject.com/wp/25586)) + ([#25586](https://community.openproject.org/wp/25586)) We recommend the update to the current version. @@ -44,7 +44,7 @@ Seekurity SAS de C.V, Peter F, Jochen Gehlbach and Ole Odendahl for reporting bugs! For further information on the release, please refer to the [Changelog -v7.0.3](https://community.openproject.com/versions/839) +v7.0.3](https://community.openproject.org/versions/839) or take a look at [GitHub](https://github.com/opf/openproject/tree/v7.0.3). diff --git a/docs/release-notes/7/7-1-0/README.md b/docs/release-notes/7/7-1-0/README.md index 3bec1866fcf5..f8195403daca 100644 --- a/docs/release-notes/7/7-1-0/README.md +++ b/docs/release-notes/7/7-1-0/README.md @@ -16,52 +16,52 @@ bug fixes included. ## Features (4) - The style of the sidebar has been updated - ([#25556](https://community.openproject.com/wp/25556)). + ([#25556](https://community.openproject.org/wp/25556)). - The timeline zoom factor is now saved in queries: When you open a saved timeline query the same zoom level as before is shown - ([#25318](https://community.openproject.com/wp/25318)). + ([#25318](https://community.openproject.org/wp/25318)). - As a user of the [Enterprise cloud edition](https://www.openproject.org/hosting/) or [Enterprise on-premises edition](https://www.openproject.org/enterprise-edition/), you can now upload a custom favicon which is shown in the browser. You can also set a touch icon which is shown on smartphones (e.g. when setting a - bookmark)([#25517](https://community.openproject.com/wp/25517)). + bookmark)([#25517](https://community.openproject.org/wp/25517)). - Users of the OpenProject Enterprise cloud and Enterprise on-premises edition can now also set white headers and there are two additional configuration options: Setting the hover background color and the hover font color - ([#25275](https://community.openproject.com/wp/25275)). + ([#25275](https://community.openproject.org/wp/25275)). ## Bug fixes (20) - Deactivated groupings on the work package page were not properly saved in queries. This has been fixed. - ([#25606](https://community.openproject.com/wp/25606)) + ([#25606](https://community.openproject.org/wp/25606)) - When grouping by assignee while the author is shown as a column, the same groups were shown multiple times. This has been resolved. - ([#25605](https://community.openproject.com/wp/25605)) + ([#25605](https://community.openproject.org/wp/25605)) - In some cases type-specific attributes were not shown for work packages. This has been fixed. - ([#25594](https://community.openproject.com/wp/25594)) + ([#25594](https://community.openproject.org/wp/25594)) - Deep links to a repository page redirected back to the root repository page. This has been resolved. - We fixed an error prevented users from scrolling the work package query menu. - ([#25572](https://community.openproject.com/projects/telekom/work_packages/25572)) + ([#25572](https://community.openproject.org/projects/telekom/work_packages/25572)) - When filtering for Boolean work package custom fields incorrect results were shown. This has been resolved. - Bulk deleting work packages which contain time entries caused an error. This has been fixed. - ([#25569](https://community.openproject.com/wp/25569)) + ([#25569](https://community.openproject.org/wp/25569)) - Long text work package custom fields were not shown in correct size in work package fullscreen mode. This has been resolved. - Categories with long names caused rows in the work package table to span multiple lines. This has been fixed. - Exported work package CSV files could not be opened properly if the ID was displayed as the first column. This has been resolved. - ([#25536](https://community.openproject.com/wp/25536)) + ([#25536](https://community.openproject.org/wp/25536)) - Search results for work package relations showed HTML attributes. This has been fixed. - ([#25534](https://community.openproject.com/wp/25534)) + ([#25534](https://community.openproject.org/wp/25534)) - We fixed an error that caused work package attributes to sometimes not be saved properly when editing in quick succession. - There was an error that caused Boolean custom fields to always be @@ -76,10 +76,10 @@ bug fixes included. - When saving an query that has been added to the side menu, the new query was not shown as part of the side menu. We fixed this issue. - Several design bugs have been fixed - ([#25595](https://community.openproject.com/wp/25595), - [#25371](https://community.openproject.com/wp/25371), - [#25356](https://community.openproject.com/wp/25356), - [#25298](https://community.openproject.com/wp/25298)). + ([#25595](https://community.openproject.org/wp/25595), + [#25371](https://community.openproject.org/wp/25371), + [#25356](https://community.openproject.org/wp/25356), + [#25298](https://community.openproject.org/wp/25298)). ## Deprecations @@ -91,7 +91,7 @@ Thanks a lot to the community, in particular to Peter F, Jochen Gehlbach and Ole Odendahl for reporting bugs! For further information on the release, please refer to the [Changelog -v7.1.0](https://community.openproject.com/versions/836) +v7.1.0](https://community.openproject.org/versions/836) or take a look at [GitHub](https://github.com/opf/openproject/tree/v7.1.0). diff --git a/docs/release-notes/7/7-2-0/README.md b/docs/release-notes/7/7-2-0/README.md index e751ae86ade5..ccf204fb1c27 100644 --- a/docs/release-notes/7/7-2-0/README.md +++ b/docs/release-notes/7/7-2-0/README.md @@ -76,5 +76,5 @@ at the label shown next to the *Relations* tab. OpenProject 7.2 contains a large number of bugs fixes. For an extensive overview of bug fixes please refer to the [following -list](https://community.openproject.com/projects/openproject/work_packages?query_props=%7B%22c%22:%5B%22id%22,%22subject%22,%22type%22,%22status%22,%22assignee%22%5D,%22tzl%22:%22days%22,%22hi%22:true,%22t%22:%22parent:desc%22,%22f%22:%5B%7B%22n%22:%22version%22,%22o%22:%22%253D%22,%22v%22:%5B%22824%22%5D%7D,%7B%22n%22:%22type%22,%22o%22:%22%253D%22,%22v%22:%5B%221%22%5D%7D,%7B%22n%22:%22subprojectId%22,%22o%22:%22*%22,%22v%22:%5B%5D%7D%5D,%22pa%22:1,%22pp%22:20%7D). +list](https://community.openproject.org/projects/openproject/work_packages?query_props=%7B%22c%22:%5B%22id%22,%22subject%22,%22type%22,%22status%22,%22assignee%22%5D,%22tzl%22:%22days%22,%22hi%22:true,%22t%22:%22parent:desc%22,%22f%22:%5B%7B%22n%22:%22version%22,%22o%22:%22%253D%22,%22v%22:%5B%22824%22%5D%7D,%7B%22n%22:%22type%22,%22o%22:%22%253D%22,%22v%22:%5B%221%22%5D%7D,%7B%22n%22:%22subprojectId%22,%22o%22:%22*%22,%22v%22:%5B%5D%7D%5D,%22pa%22:1,%22pp%22:20%7D). diff --git a/docs/release-notes/7/7-2-1/README.md b/docs/release-notes/7/7-2-1/README.md index 08d76ff397c0..176d6b119a67 100644 --- a/docs/release-notes/7/7-2-1/README.md +++ b/docs/release-notes/7/7-2-1/README.md @@ -14,28 +14,28 @@ OpenProject 7.2.1 contains several bug fixes. - Wrong query results were shown when switching away from a timeline query - \[[#26086](https://community.openproject.com/wp/26086)\] + \[[#26086](https://community.openproject.org/wp/26086)\] - Cost reports with custom field of type list were rendered using their internal ID, not their option text - \[[#26050](https://community.openproject.com/wp/26050)\] + \[[#26050](https://community.openproject.org/wp/26050)\] - With newer versions of Ruby 2.4., an internal error *LocalJumpError: unexpected return* when accessing the work package page has been - resolved. \[[#26128](https://community.openproject.com/wp/26128)\] + resolved. \[[#26128](https://community.openproject.org/wp/26128)\] ## Visual changes - The subject in work package show view was misaligned - \[[#26073](https://community.openproject.com/wp/26073)\] + \[[#26073](https://community.openproject.org/wp/26073)\] - Additional parent elements in the work package table are rendered only with a different font color, no longer with a opaque background color - \[[#26052](https://community.openproject.com/wp/26052)\] + \[[#26052](https://community.openproject.org/wp/26052)\] Thanks a lot to the community, in particular to Mark Brown for reporting bugs! For further information on the release, please refer to the [Changelog -v7.2.1](https://community.openproject.com/versions/843) +v7.2.1](https://community.openproject.org/versions/843) or take a look at [GitHub](https://github.com/opf/openproject/tree/v7.2.1). diff --git a/docs/release-notes/7/7-2-2/README.md b/docs/release-notes/7/7-2-2/README.md index 3f353bdfcbc5..ac6138dffd4e 100644 --- a/docs/release-notes/7/7-2-2/README.md +++ b/docs/release-notes/7/7-2-2/README.md @@ -12,38 +12,38 @@ - Row highlighting in the work package table and timeline view ceases to work after using the timeline. - \[[#26168](https://community.openproject.com/wp/26168)\] + \[[#26168](https://community.openproject.org/wp/26168)\] - A textile parsing error causes the description field of a work package to no longer be rendered. - \[[#26159](https://community.openproject.com/wp/26159)\] + \[[#26159](https://community.openproject.org/wp/26159)\] - Pending attachments can not be removed from a new work package form. - \[[#26117](https://community.openproject.com/wp/26117)\] + \[[#26117](https://community.openproject.org/wp/26117)\] - Summary field width in the news entry form suggested an allowed value of more than 256 characters. - \[[#26113](https://community.openproject.com/wp/26113)\] + \[[#26113](https://community.openproject.org/wp/26113)\] - Clicking an external link in a work package’s description works, but also shows an error notification in Firefox. - \[[#26163](https://community.openproject.com/wp/26163)\] + \[[#26163](https://community.openproject.org/wp/26163)\] - Usage of a non-transpiled ES6 value causes older browsers to display nothing at all, instead of an “This browser is unsupported” notification. - \[[#26153](https://community.openproject.com/wp/26153)\] + \[[#26153](https://community.openproject.org/wp/26153)\] ## Visual changes - Editing attributes in the table should no longer cause large changes to the column’s width. - \[[#26100](https://community.openproject.com/wp/26100)\] + \[[#26100](https://community.openproject.org/wp/26100)\] - The icons of regular and custom field attributes in the form configuration tab were not identical. - \[[#26129](https://community.openproject.com/wp/26129)\] + \[[#26129](https://community.openproject.org/wp/26129)\] Thanks a lot to the community, in particular to Frank Schmid, Markus Hillenbrand, and Marc Vollmer for reporting bugs! For further information on the 7.2.2 release, please refer to the [Changelog -v7.2.2](https://community.openproject.com/versions/846) +v7.2.2](https://community.openproject.org/versions/846) or take a look at [GitHub](https://github.com/opf/openproject/tree/v7.2.2). @@ -54,8 +54,8 @@ versions, please also upgrade your package source according to the [Download and Installation](https://www.openproject.org/download-and-installation/) page. For more information, please also see ticket -\[[#26144](https://community.openproject.com/wp/26144)\] and [this -forum post](https://community.openproject.com/topics/8114). +\[[#26144](https://community.openproject.org/wp/26144)\] and [this +forum post](https://community.openproject.org/topics/8114). diff --git a/docs/release-notes/7/7-2-3/README.md b/docs/release-notes/7/7-2-3/README.md index 1556028ed43b..3e3df0dfd416 100644 --- a/docs/release-notes/7/7-2-3/README.md +++ b/docs/release-notes/7/7-2-3/README.md @@ -23,7 +23,7 @@ If you want to filter for this exact behavior, a new filter named - **when filtering for a group**: Work packages assigned to this group, and any users within -Bug reference: [#26207](https://community.openproject.com/wp/26207) +Bug reference: [#26207](https://community.openproject.org/wp/26207) diff --git a/docs/release-notes/7/7-3-0/README.md b/docs/release-notes/7/7-3-0/README.md index a1e91fd8bc21..ffbff1cffa87 100644 --- a/docs/release-notes/7/7-3-0/README.md +++ b/docs/release-notes/7/7-3-0/README.md @@ -99,4 +99,4 @@ package to another project. OpenProject 7.3 contains a large number of bugs fixes. For an extensive overview of bug fixes please refer to the -[following list](https://community.openproject.com/projects/openproject/work_packages?query_props=%7B%22c%22:%5B%22id%22,%22subject%22,%22type%22,%22status%22,%22assignee%22%5D,%22tzl%22:%22days%22,%22hi%22:true,%22t%22:%22parent:desc%22,%22f%22:%5B%7B%22n%22:%22version%22,%22o%22:%22%253D%22,%22v%22:%5B%22841%22%5D%7D,%7B%22n%22:%22type%22,%22o%22:%22%253D%22,%22v%22:%5B%221%22%5D%7D,%7B%22n%22:%22subprojectId%22,%22o%22:%22*%22,%22v%22:%5B%5D%7D%5D,%22pa%22:1,%22pp%22:20%7D). +[following list](https://community.openproject.org/projects/openproject/work_packages?query_props=%7B%22c%22:%5B%22id%22,%22subject%22,%22type%22,%22status%22,%22assignee%22%5D,%22tzl%22:%22days%22,%22hi%22:true,%22t%22:%22parent:desc%22,%22f%22:%5B%7B%22n%22:%22version%22,%22o%22:%22%253D%22,%22v%22:%5B%22841%22%5D%7D,%7B%22n%22:%22type%22,%22o%22:%22%253D%22,%22v%22:%5B%221%22%5D%7D,%7B%22n%22:%22subprojectId%22,%22o%22:%22*%22,%22v%22:%5B%5D%7D%5D,%22pa%22:1,%22pp%22:20%7D). diff --git a/docs/release-notes/7/7-3-1/README.md b/docs/release-notes/7/7-3-1/README.md index 7bafa3523715..5636481bcd45 100644 --- a/docs/release-notes/7/7-3-1/README.md +++ b/docs/release-notes/7/7-3-1/README.md @@ -12,11 +12,11 @@ - The settings button did not work in the work package fullscreen create form. - \[[#26393](https://community.openproject.com/wp/26393)\] + \[[#26393](https://community.openproject.org/wp/26393)\] - The wrong meeting time was shown. - \[[#26480](https://community.openproject.com/wp/26480)\] + \[[#26480](https://community.openproject.org/wp/26480)\] - An internal error occurred when exporting a budget as CSV. - \[[#26518](https://community.openproject.com/wp/26518)\] + \[[#26518](https://community.openproject.org/wp/26518)\] - The selected work package was not focused when navigating from the work package table to the fullscreen view and back. - Drag and drop for work package custom field values of type “List” @@ -30,15 +30,15 @@ - There was an additional hashtag shown in the work package breadcrumb. - \[[#26439](https://community.openproject.com/wp/26439)\] + \[[#26439](https://community.openproject.org/wp/26439)\] - There was not enough space between the work package status and type. - \[[#26508](https://community.openproject.com/wp/26508)\] + \[[#26508](https://community.openproject.org/wp/26508)\] Thanks a lot to the community, in particular to Frank Michler, Ottavio Campana and Rob Guinness for reporting bugs! For further information on the 7.3.1 release, please refer to the -[Changelog v7.3.1](https://community.openproject.com/versions/851) +[Changelog v7.3.1](https://community.openproject.org/versions/851) or take a look at [GitHub](https://github.com/opf/openproject/tree/v7.3.1). diff --git a/docs/release-notes/7/7-3-2/README.md b/docs/release-notes/7/7-3-2/README.md index 8ce61fe2d38d..41d41be17d16 100644 --- a/docs/release-notes/7/7-3-2/README.md +++ b/docs/release-notes/7/7-3-2/README.md @@ -12,15 +12,15 @@ - Multi-select values could not properly be selected. This affected for instance work package filters and multi-select custom fields. - \[[#26611](https://community.openproject.com/wp/26611)\] + \[[#26611](https://community.openproject.org/wp/26611)\] - The breadcrumb in the roles and permissions in the administration was not shown properly. - \[[#26563](https://community.openproject.com/wp/26563)\] + \[[#26563](https://community.openproject.org/wp/26563)\] Thanks a lot to the community, in particular to Chris Jornlin and Steve Manning for reporting bugs! For further information on the 7.3.2 release, please refer to -the [Changelog v7.3.2](https://community.openproject.com/versions/852) +the [Changelog v7.3.2](https://community.openproject.org/versions/852) or take a look at [GitHub](https://github.com/opf/openproject/tree/v7.3.2). diff --git a/docs/release-notes/7/7-4-0/README.md b/docs/release-notes/7/7-4-0/README.md index 66b75fc8bdaf..c21d63b23ab0 100644 --- a/docs/release-notes/7/7-4-0/README.md +++ b/docs/release-notes/7/7-4-0/README.md @@ -120,5 +120,5 @@ We optimized the mobile view for the work package view. OpenProject 7.4 contains a large number of bugs fixes. For an extensive overview of bug fixes please refer to the -[following list](https://community.openproject.com/projects/openproject/work_packages?query_props=%7B%22c%22:%5B%22id%22,%22subject%22,%22type%22,%22status%22,%22assignee%22%5D,%22tzl%22:%22days%22,%22hi%22:true,%22g%22:%22%22,%22t%22:%22parent:desc%22,%22f%22:%5B%7B%22n%22:%22version%22,%22o%22:%22%253D%22,%22v%22:%5B%22845%22%5D%7D,%7B%22n%22:%22type%22,%22o%22:%22%253D%22,%22v%22:%5B%221%22%5D%7D,%7B%22n%22:%22subprojectId%22,%22o%22:%22*%22,%22v%22:%5B%5D%7D%5D,%22pa%22:1,%22pp%22:20%7D). +[following list](https://community.openproject.org/projects/openproject/work_packages?query_props=%7B%22c%22:%5B%22id%22,%22subject%22,%22type%22,%22status%22,%22assignee%22%5D,%22tzl%22:%22days%22,%22hi%22:true,%22g%22:%22%22,%22t%22:%22parent:desc%22,%22f%22:%5B%7B%22n%22:%22version%22,%22o%22:%22%253D%22,%22v%22:%5B%22845%22%5D%7D,%7B%22n%22:%22type%22,%22o%22:%22%253D%22,%22v%22:%5B%221%22%5D%7D,%7B%22n%22:%22subprojectId%22,%22o%22:%22*%22,%22v%22:%5B%5D%7D%5D,%22pa%22:1,%22pp%22:20%7D). diff --git a/docs/release-notes/7/7-4-1/README.md b/docs/release-notes/7/7-4-1/README.md index 591e4dc0d2d5..e72090bba8e5 100644 --- a/docs/release-notes/7/7-4-1/README.md +++ b/docs/release-notes/7/7-4-1/README.md @@ -12,12 +12,12 @@ - Synchronized LDAP groups were not properly removed when their associated OpenProject group is removed - \[[#27103](https://community.openproject.com/wp/27103)\] + \[[#27103](https://community.openproject.org/wp/27103)\] - Updates the nokogiri XML parser gem which addresses a Denial-of-Service attack (CVE-2017-15412) For further information on the 7.4.1 release, please refer to -the [Changelog v7.4.1](https://community.openproject.com/versions/855) +the [Changelog v7.4.1](https://community.openproject.org/versions/855) or take a look at [GitHub](https://github.com/opf/openproject/tree/v7.4.1). diff --git a/docs/release-notes/7/7-4-2/README.md b/docs/release-notes/7/7-4-2/README.md index 4b962b8b7315..f8100c1bf641 100644 --- a/docs/release-notes/7/7-4-2/README.md +++ b/docs/release-notes/7/7-4-2/README.md @@ -12,24 +12,24 @@ - Enterprise LDAP group synchronization changed to allow *memberOf* to yield members of an ldap group - [#](https://community.openproject.com/wp/24960 "In repository module (SVN) when clicking on a .js file representation is incorrect")[27271](https://community.openproject.com/wp/27271 "LDAP group synchronization with memberOf filter") + [#](https://community.openproject.org/wp/24960 "In repository module (SVN) when clicking on a .js file representation is incorrect")[27271](https://community.openproject.org/wp/27271 "LDAP group synchronization with memberOf filter") ## Bug fixes (5) - Invalid format render response when accessing a JavaScript file in the repository browser - [#24960](https://community.openproject.com/wp/24960 "In repository module (SVN) when clicking on a .js file representation is incorrect") + [#24960](https://community.openproject.org/wp/24960 "In repository module (SVN) when clicking on a .js file representation is incorrect") - Progress aggregation ignores multiple identical values in subtasks - [#27262](https://community.openproject.com/wp/27262) + [#27262](https://community.openproject.org/wp/27262) - Paragraphs in work package description are collapsed - [#27158](https://community.openproject.com/wp/27158) + [#27158](https://community.openproject.org/wp/27158) - Locked users shown as matches when adding watchers - [#27127](https://community.openproject.com/wp/27127) + [#27127](https://community.openproject.org/wp/27127) - Version sorting by name also sorts by their effective date For further information on the 7.4.2 release, please refer to -the [Changelog v7.4.2](https://community.openproject.com/versions/857) +the [Changelog v7.4.2](https://community.openproject.org/versions/857) or take a look at [GitHub](https://github.com/opf/openproject/tree/v7.4.2). diff --git a/docs/release-notes/7/7-4-3/README.md b/docs/release-notes/7/7-4-3/README.md index 8bc9e8c45da5..1631b2dc8d69 100644 --- a/docs/release-notes/7/7-4-3/README.md +++ b/docs/release-notes/7/7-4-3/README.md @@ -42,9 +42,9 @@ announcement](https://www.ruby-lang.org/en/news/2018/03/28/ruby-2-4-4-released/) ## Changes - A separate icon has been included for the Two-factor authentication - plugin ([#27150](https://community.openproject.com/wp/27150)) + plugin ([#27150](https://community.openproject.org/wp/27150)) - SMTP authentication *none* can now be configured through the system - settings. ([#27284](https://community.openproject.com/wp/27284)) + settings. ([#27284](https://community.openproject.org/wp/27284)) - For further information on the 7.4.3 release, please refer to - the [Changelog v7.4.3](https://community.openproject.com/versions/890) + the [Changelog v7.4.3](https://community.openproject.org/versions/890) or take a look at [GitHub](https://github.com/opf/openproject/tree/v7.4.3). diff --git a/docs/release-notes/7/7-4-4/README.md b/docs/release-notes/7/7-4-4/README.md index e43a50c45246..97b8f57cc9a3 100644 --- a/docs/release-notes/7/7-4-4/README.md +++ b/docs/release-notes/7/7-4-4/README.md @@ -13,29 +13,29 @@ following bug fixes: - Work package modification for regular users on MySQL-based - instances ([#27237](https://community.openproject.com/wp/27237)) + instances ([#27237](https://community.openproject.org/wp/27237)) - Child work packages were not deleted when the parent element is - deleted ([#27280](https://community.openproject.com/wp/27280)) + deleted ([#27280](https://community.openproject.org/wp/27280)) - The fuzzy project autocompletion has been corrected to provide better matching when a substring is matched - ([#27447](https://community.openproject.com/wp/27447)) + ([#27447](https://community.openproject.org/wp/27447)) - The GitHub integration plugin did not properly receive events due to a naming clash - ([#27448](https://community.openproject.com/wp/27448)) + ([#27448](https://community.openproject.org/wp/27448)) - Creating new wiki pages from a wiki link (e.g, *\[\[ Wiki page \]\] *) now retains the correct title instead of the generated - URL slug ([#27462](https://community.openproject.com/wp/27462)) + URL slug ([#27462](https://community.openproject.org/wp/27462)) - A subsequent search for documents in the global search disabled the documents search checkbox - ([#27479](https://community.openproject.com/wp/27479)) + ([#27479](https://community.openproject.org/wp/27479)) - The reset button for RSS tokens generated a new API token instead - ([#27498](https://community.openproject.com/wp/27498)) + ([#27498](https://community.openproject.org/wp/27498)) - Wiki start pages (titled *Wiki*) could not be renamed back if the name was changed at one point - ([#27576](https://community.openproject.com/wp/27576)) + ([#27576](https://community.openproject.org/wp/27576)) @@ -44,15 +44,15 @@ following bug - Meetings plugin: The *close* button of the show page now requires a confirmation before closing - ([#27336](https://community.openproject.com/wp/27336)) + ([#27336](https://community.openproject.org/wp/27336)) - The restriction to create a time entry with at maximum 1000 hours on a single work package has been lifted - ([#27457](https://community.openproject.com/wp/27457)) + ([#27457](https://community.openproject.org/wp/27457)) For more information, please see the [v7.4.4 version in our -community](https://community.openproject.com/versions/924) or take +community](https://community.openproject.org/versions/924) or take a look at [GitHub](https://github.com/opf/openproject/tree/v7.4.4). diff --git a/docs/release-notes/7/7-4-5/README.md b/docs/release-notes/7/7-4-5/README.md index 025ada5fb0d7..67b007fa0081 100644 --- a/docs/release-notes/7/7-4-5/README.md +++ b/docs/release-notes/7/7-4-5/README.md @@ -13,36 +13,36 @@ fixes. We recommend the update to the current version. - Fixed: Cookie *secure* flag was not applied in all cases even when SSL was enabled - ([#27763](https://community.openproject.com/wp/27763)) + ([#27763](https://community.openproject.org/wp/27763)) - Fixed: Calendar widget on *My page* overlapped the project dropdown - ([#27765](https://community.openproject.com/wp/27765)) + ([#27765](https://community.openproject.org/wp/27765)) - Fixed: Removed text formatting other than references in commit - messages ([#27769](https://community.openproject.com/wp/27769)) + messages ([#27769](https://community.openproject.org/wp/27769)) - Fixed: Flashing of content on *My account* on initial page load - ([#25795](https://community.openproject.com/wp/25795)) + ([#25795](https://community.openproject.org/wp/25795)) - Fixed: Chrome where the right column of a two-column work package layout (on larger screens) was not receiving any clicks - ([#27687](https://community.openproject.com/wp/27687)) + ([#27687](https://community.openproject.org/wp/27687)) - Fixed: Updating overridden labor and unit costs reset all other overridden costs to their calculated values - ([#](https://community.openproject.com/wp/27692)[27692](https://community.openproject.com/wp/27692)) + ([#](https://community.openproject.org/wp/27692)[27692](https://community.openproject.org/wp/27692)) - Fixed: Unable to update parent to previous sibling work package in shared hierarchy - ([#27746](https://community.openproject.com/wp/27746)) + ([#27746](https://community.openproject.org/wp/27746)) - Fixed: English language option displayed twice in the administration - ([#27696](https://community.openproject.com/wp/27696), - [#27751](https://community.openproject.com/wp/27751)) + ([#27696](https://community.openproject.org/wp/27696), + [#27751](https://community.openproject.org/wp/27751)) - Improved: Error messages when dependent work package is invalid (e.g., trying to save child with invalid parent) - Improved: Parent wiki pages can be selected when creating new wiki pages through content links - ([#26189](https://community.openproject.com/wp/26189)) + ([#26189](https://community.openproject.org/wp/26189)) For more information, please see the [v7.4.5 version in our -community](https://community.openproject.com/versions/990) or take +community](https://community.openproject.org/versions/990) or take a look at [GitHub](https://github.com/opf/openproject/tree/v7.4.5). diff --git a/docs/release-notes/7/7-4-6/README.md b/docs/release-notes/7/7-4-6/README.md index 6a07b528522b..70a8e85862b8 100644 --- a/docs/release-notes/7/7-4-6/README.md +++ b/docs/release-notes/7/7-4-6/README.md @@ -15,23 +15,23 @@ We recommend the update to the current version. OpenProject 7.4.6 packaged installation introduces support for Ubuntu 18.04. -([#27799](https://community.openproject.com/wp/27799)) +([#27799](https://community.openproject.org/wp/27799)) #### Bug fixes and changes - Fixed: Poor performance when adding several work packages to a large tree - ([#27878](https://community.openproject.com/wp/27878)) + ([#27878](https://community.openproject.org/wp/27878)) - Fixed: Saving filter-selected list Custom Field with single value results in error - ([#27833](https://community.openproject.com/wp/27833)) + ([#27833](https://community.openproject.org/wp/27833)) - Fixed: Progress calculation for parents in bulk edit was not applied - ([#27975](https://community.openproject.com/wp/27975)) + ([#27975](https://community.openproject.org/wp/27975)) - Fixed: CSS columns display in Chrome versions 65 to 66 due to backface-visibility - ([#27823](https://community.openproject.com/wp/27823)) + ([#27823](https://community.openproject.org/wp/27823)) - Improved: Performance on global activities page - ([#27582](https://community.openproject.com/wp/27582)) + ([#27582](https://community.openproject.org/wp/27582)) Special thanks go to all OpenProject contributors for [reporting bugs](../../../development/report-a-bug/) and helping diff --git a/docs/release-notes/7/7-4-7/README.md b/docs/release-notes/7/7-4-7/README.md index 10415730b13a..a6f73c695c37 100644 --- a/docs/release-notes/7/7-4-7/README.md +++ b/docs/release-notes/7/7-4-7/README.md @@ -21,14 +21,14 @@ export modal. - Fixed: \[2FA\] Device ID not transmitted when resending with different channel - \[[#28033](https://community.openproject.com/wp/28033)\] + \[[#28033](https://community.openproject.org/wp/28033)\] - Fixed: \[2FA\] MessageBird: Originator may not be longer than 11 - characters \[[#28034](https://community.openproject.com/wp/28034)\] + characters \[[#28034](https://community.openproject.org/wp/28034)\] - Fixed: \[2FA\] MessageBird: work-package-types/#work-package-form-configuration-premium-featureUser language may be - empty \[[#28035](https://community.openproject.com/wp/28035)\] + empty \[[#28035](https://community.openproject.org/wp/28035)\] - Fixed: \[Styling\] Prevent scrolling body when reaching bottom of project autocompleter - \[[#28039](https://community.openproject.com/wp/28039)\] + \[[#28039](https://community.openproject.org/wp/28039)\] diff --git a/docs/release-notes/8/8-0-0/README.md b/docs/release-notes/8/8-0-0/README.md index a544205e40a3..82f5f3fb61e2 100644 --- a/docs/release-notes/8/8-0-0/README.md +++ b/docs/release-notes/8/8-0-0/README.md @@ -28,7 +28,7 @@ Read below to get a detailed overview of what is new in OpenProject 8. ## WYSIWYG Markdown text editor A new WYSIWYG editor replaces the existing editor in OpenProject -([18039](https://community.openproject.com/wp/18039)). +([18039](https://community.openproject.org/wp/18039)). Based on CKEditor 5, the new editor makes it easy to create and format texts. Users do no longer have to remember textile syntax and can directly see the changes they make. No matter whether you want to add an @@ -46,8 +46,8 @@ pandoc. Navigating within OpenProject is now even easier: The new side navigation -([26824](https://community.openproject.com/wp/26824), -[27828](https://community.openproject.com/wp/27828)) +([26824](https://community.openproject.org/wp/26824), +[27828](https://community.openproject.org/wp/27828)) allows you to easily navigate within projects. To get additional screen real estate, just hide the entire side navigation. In addition, work package views and wiki pages are now much easier to find and navigate @@ -59,7 +59,7 @@ to. With OpenProject 8 you can easily embed work package views and the Gantt chart in wiki pages -([26233](https://community.openproject.com/wp/26233)). +([26233](https://community.openproject.org/wp/26233)). This way you can display key project information (such as the current milestone plan) directly in a wiki page or in the project overview page. @@ -70,7 +70,7 @@ milestone plan) directly in a wiki page or in the project overview page. Looking for a specific document or some text in that document? This is no problem with the new full text search capability for work package attachments -([26817](https://community.openproject.com/wp/26817)). +([26817](https://community.openproject.org/wp/26817)). You can either search by file name of the content of the file from the work package page. This allows you to quickly find all the work packages with certain attachments. @@ -81,7 +81,7 @@ with certain attachments. With OpenProject 8 you can model intelligent workflows using custom actions -([26612](https://community.openproject.com/wp/26612)). +([26612](https://community.openproject.org/wp/26612)). Simply select which actions should be triggered when you click a custom action button. You can e.g. change the assignee, status and priority of a work package with the click of a single button. This gives you a @@ -143,7 +143,7 @@ and ensures that OpenProject is future-proof. OpenProject 8.0 contains a large number of bugs fixes. For an extensive overview of bug fixes please refer to the [following -list](https://community.openproject.com/projects/openproject/work_packages?query_props=%7B%22c%22:%5B%22id%22,%22subject%22,%22type%22,%22status%22,%22assignee%22%5D,%22tzl%22:%22days%22,%22hi%22:false,%22g%22:%22%22,%22t%22:%22parent:desc%22,%22f%22:%5B%7B%22n%22:%22version%22,%22o%22:%22%253D%22,%22v%22:%5B%22818%22%5D%7D,%7B%22n%22:%22type%22,%22o%22:%22%253D%22,%22v%22:%5B%221%22%5D%7D,%7B%22n%22:%22subprojectId%22,%22o%22:%22*%22,%22v%22:%5B%5D%7D%5D,%22pa%22:1,%22pp%22:20%7D). +list](https://community.openproject.org/projects/openproject/work_packages?query_props=%7B%22c%22:%5B%22id%22,%22subject%22,%22type%22,%22status%22,%22assignee%22%5D,%22tzl%22:%22days%22,%22hi%22:false,%22g%22:%22%22,%22t%22:%22parent:desc%22,%22f%22:%5B%7B%22n%22:%22version%22,%22o%22:%22%253D%22,%22v%22:%5B%22818%22%5D%7D,%7B%22n%22:%22type%22,%22o%22:%22%253D%22,%22v%22:%5B%221%22%5D%7D,%7B%22n%22:%22subprojectId%22,%22o%22:%22*%22,%22v%22:%5B%5D%7D%5D,%22pa%22:1,%22pp%22:20%7D). ## Upgrading your installation to OpenProject 8.0. diff --git a/docs/release-notes/8/8-0-1/README.md b/docs/release-notes/8/8-0-1/README.md index 01eba4e16017..48945d49ac2d 100644 --- a/docs/release-notes/8/8-0-1/README.md +++ b/docs/release-notes/8/8-0-1/README.md @@ -10,60 +10,60 @@ # OpenProject 8.0.1 We released -[OpenProject 8.0.1](https://community.openproject.com/versions/1154). +[OpenProject 8.0.1](https://community.openproject.org/versions/1154). The release contains bug fixes from the 8.0 release. We recommend updating to the newest version. #### Bug fixes and changes - Fixed: Highlighting of timeline missing with highlighting mode none - \[[#28564](https://community.openproject.com/wp/28564)\] + \[[#28564](https://community.openproject.org/wp/28564)\] - Fixed: Jumping comment container when reverse activity sorting is activated - Fixed: Signed outgoing webhooks incorrectly set signature header - Fixed: A newline was added to WYSIWYG code blocks when editing a document that contained such blocks - \[[#28609](https://community.openproject.com/wp/28609)\] + \[[#28609](https://community.openproject.org/wp/28609)\] - Fixed: Repository statistics SVG reports were not rendered due to Content-Security-Policy forbidding SVG elements \[#28612\] - Fixed: Regression that did not detect work package links within - braces \[[#28578](https://community.openproject.com/wp/28578)\] + braces \[[#28578](https://community.openproject.org/wp/28578)\] - Fixed: Long-running databases of OpenProject run into PostgreSQL index error while migrating *planning\_element\_type\_colors* indexes to 8.0.0 - \[[#28556](https://community.openproject.com/wp/28556)\] + \[[#28556](https://community.openproject.org/wp/28556)\] - Fixed: Calendar filter toggles not working properly - \[[#28588](https://community.openproject.com/wp/28588)\] + \[[#28588](https://community.openproject.org/wp/28588)\] - Fixed: Repository unfolding directory tree not working properly - \[[#28613](https://community.openproject.com/wp/28613)\] + \[[#28613](https://community.openproject.org/wp/28613)\] - Fixed: Memory leak in repeated work package form requests - \[[#28611](https://community.openproject.com/wp/28611)\] + \[[#28611](https://community.openproject.org/wp/28611)\] - Fixed: Login dropdown labels were styled as buttons on hover - \[[#28616](https://community.openproject.com/wp/28616)\] + \[[#28616](https://community.openproject.org/wp/28616)\] - Fixed: Editing work package after submission with add\_work\_packages permission - \[[#28580](https://community.openproject.com/wp/28580)\] + \[[#28580](https://community.openproject.org/wp/28580)\] - Fixed: Fast click on subsequent query elements in the sidebar result in invalid table - \[[#28539](https://community.openproject.com/wp/28539)\] + \[[#28539](https://community.openproject.org/wp/28539)\] - Fixed: Two scrollbars in activity comments on narrow browser windows - \[[#28553](https://community.openproject.com/wp/28553) + \[[#28553](https://community.openproject.org/wp/28553) - Fixed: Can’t upload attachments on comments with add\_work\_packages - permission \[[#28541](https://community.openproject.com/wp/28541)\] + permission \[[#28541](https://community.openproject.org/wp/28541)\] - Fixed: Collapsing views on global work package page removes entries - \[[#28584](https://community.openproject.com/wp/28584)\] + \[[#28584](https://community.openproject.org/wp/28584)\] - Improved: Restored status column on subelements table of a work - package \[[#28526](https://community.openproject.com/wp/28526)\] + package \[[#28526](https://community.openproject.org/wp/28526)\] - Fixed: Type is invalid when creating new project - \[[#28543](https://community.openproject.com/wp/28543)\] + \[[#28543](https://community.openproject.org/wp/28543)\] #### Contributions diff --git a/docs/release-notes/8/8-0-2/README.md b/docs/release-notes/8/8-0-2/README.md index 85f92bc642d2..ee9d09ba74b6 100644 --- a/docs/release-notes/8/8-0-2/README.md +++ b/docs/release-notes/8/8-0-2/README.md @@ -10,7 +10,7 @@ # OpenProject 8.0.2 We released -[OpenProject 8.0.2](https://community.openproject.com/versions/1154). +[OpenProject 8.0.2](https://community.openproject.org/versions/1154). The release contains several bug fixes and we recommend updating to the newest version. @@ -18,24 +18,24 @@ newest version. - Fixed: Relations cannot be added when OpenProject is running on relative URL root - \[[#28639](https://community.openproject.com/wp/28639)\] + \[[#28639](https://community.openproject.org/wp/28639)\] - Fixed: Cannot select values for custom field filter - \[[#28739](https://community.openproject.com/wp/28739)\] + \[[#28739](https://community.openproject.org/wp/28739)\] - Fixed: Renaming custom field does not invalidate cache - \[[#28738](https://community.openproject.com/wp/28738)\] + \[[#28738](https://community.openproject.org/wp/28738)\] - Fixed: Top menu entries are misaligned in mobile views - \[[#28678](https://community.openproject.com/wp/28678)\] + \[[#28678](https://community.openproject.org/wp/28678)\] - Fixed: Unable to save Sub-Project with Custom Field of Version using parent Version - \[[#28421](https://community.openproject.com/wp/28421)\] + \[[#28421](https://community.openproject.org/wp/28421)\] - Fixed: Toolbar container styling corrected - \[[#28645](https://community.openproject.com/wp/28645)\] + \[[#28645](https://community.openproject.org/wp/28645)\] - Fixed: Content-Disposition was not set for AWS hosted attachments - for non-inlineable images. This resulted in SVGs being displayed + for non-inlinable images. This resulted in SVGs being displayed inline, which opens an SVG XSS attack vector on the AWS domain (NOT on the OpenProject domain). From this version onward, non-image files will receive a forced *attachment* content disposition to diff --git a/docs/release-notes/8/8-1-0/README.md b/docs/release-notes/8/8-1-0/README.md index 12bf42fa7711..489dd793f5bc 100644 --- a/docs/release-notes/8/8-1-0/README.md +++ b/docs/release-notes/8/8-1-0/README.md @@ -53,4 +53,4 @@ time. OpenProject 8.1 contains a large number of bugs fixes. For an extensive overview of bug fixes please refer to the [following -list](https://community.openproject.com/projects/openproject/work_packages?query_props=%7B%22c%22:%5B%22id%22,%22subject%22,%22type%22,%22status%22,%22assignee%22,%22version%22%5D,%22hi%22:true,%22g%22:%22%22,%22t%22:%22parent:asc%22,%22f%22:%5B%7B%22n%22:%22status%22,%22o%22:%22*%22,%22v%22:%5B%5D%7D,%7B%22n%22:%22type%22,%22o%22:%22=%22,%22v%22:%5B%221%22%5D%7D,%7B%22n%22:%22version%22,%22o%22:%22=%22,%22v%22:%5B%22989%22%5D%7D,%7B%22n%22:%22subprojectId%22,%22o%22:%22*%22,%22v%22:%5B%5D%7D%5D,%22pa%22:1,%22pp%22:100%7D). +list](https://community.openproject.org/projects/openproject/work_packages?query_props=%7B%22c%22:%5B%22id%22,%22subject%22,%22type%22,%22status%22,%22assignee%22,%22version%22%5D,%22hi%22:true,%22g%22:%22%22,%22t%22:%22parent:asc%22,%22f%22:%5B%7B%22n%22:%22status%22,%22o%22:%22*%22,%22v%22:%5B%5D%7D,%7B%22n%22:%22type%22,%22o%22:%22=%22,%22v%22:%5B%221%22%5D%7D,%7B%22n%22:%22version%22,%22o%22:%22=%22,%22v%22:%5B%22989%22%5D%7D,%7B%22n%22:%22subprojectId%22,%22o%22:%22*%22,%22v%22:%5B%5D%7D%5D,%22pa%22:1,%22pp%22:100%7D). diff --git a/docs/release-notes/8/8-2-0/README.md b/docs/release-notes/8/8-2-0/README.md index ad194dfc7b79..d19e61c91df1 100644 --- a/docs/release-notes/8/8-2-0/README.md +++ b/docs/release-notes/8/8-2-0/README.md @@ -61,13 +61,13 @@ table](WorkPackage-Table-1024x457.png) ## Technical improvements and bug fixes The OpenProject API now allows you to update times in OpenProject -([#29003](https://community.openproject.com/wp/29003)) +([#29003](https://community.openproject.org/wp/29003)) and delete time entries -([#29029](https://community.openproject.com/wp/29029)), +([#29029](https://community.openproject.org/wp/29029)), OpenProject 8.2 contains a large number of smaller improvements and bug fixes. For an overview, please take a look at the [list of bug -fixes](https://community.openproject.com/projects/openproject/work_packages?query_props=%7B%22c%22%3A%5B%22id%22%2C%22subject%22%2C%22type%22%2C%22status%22%2C%22assignee%22%2C%22version%22%5D%2C%22hi%22%3Atrue%2C%22g%22%3A%22%22%2C%22t%22%3A%22parent%3Aasc%22%2C%22f%22%3A%5B%7B%22n%22%3A%22status%22%2C%22o%22%3A%22*%22%2C%22v%22%3A%5B%5D%7D%2C%7B%22n%22%3A%22version%22%2C%22o%22%3A%22%3D%22%2C%22v%22%3A%5B%221253%22%5D%7D%2C%7B%22n%22%3A%22type%22%2C%22o%22%3A%22%3D%22%2C%22v%22%3A%5B%221%22%5D%7D%2C%7B%22n%22%3A%22subprojectId%22%2C%22o%22%3A%22*%22%2C%22v%22%3A%5B%5D%7D%5D%2C%22pa%22%3A1%2C%22pp%22%3A20%7D). +fixes](https://community.openproject.org/projects/openproject/work_packages?query_props=%7B%22c%22%3A%5B%22id%22%2C%22subject%22%2C%22type%22%2C%22status%22%2C%22assignee%22%2C%22version%22%5D%2C%22hi%22%3Atrue%2C%22g%22%3A%22%22%2C%22t%22%3A%22parent%3Aasc%22%2C%22f%22%3A%5B%7B%22n%22%3A%22status%22%2C%22o%22%3A%22*%22%2C%22v%22%3A%5B%5D%7D%2C%7B%22n%22%3A%22version%22%2C%22o%22%3A%22%3D%22%2C%22v%22%3A%5B%221253%22%5D%7D%2C%7B%22n%22%3A%22type%22%2C%22o%22%3A%22%3D%22%2C%22v%22%3A%5B%221%22%5D%7D%2C%7B%22n%22%3A%22subprojectId%22%2C%22o%22%3A%22*%22%2C%22v%22%3A%5B%5D%7D%5D%2C%22pa%22%3A1%2C%22pp%22%3A20%7D). diff --git a/docs/release-notes/8/8-2-1/README.md b/docs/release-notes/8/8-2-1/README.md index 0acb11076cb0..82742229bdd5 100644 --- a/docs/release-notes/8/8-2-1/README.md +++ b/docs/release-notes/8/8-2-1/README.md @@ -10,7 +10,7 @@ # OpenProject 8.2.1 We released -[OpenProject 8.2.1](https://community.openproject.com/versions/1352). +[OpenProject 8.2.1](https://community.openproject.org/versions/1352). The release contains several bug fixes and we recommend updating to the newest version. @@ -19,39 +19,39 @@ newest version. - Fixed: Long heading in forum overlaps buttons - \[[#28839](https://community.openproject.com/wp/28839)\] + \[[#28839](https://community.openproject.org/wp/28839)\] - Fixed: Wrong error message when updating teaser element on Project Overview page - \[[#29011](https://community.openproject.com/wp/29011)\] + \[[#29011](https://community.openproject.org/wp/29011)\] - Fixed: Page not found displays old OpenProject favicon icon - \[[#29026](https://community.openproject.com/wp/29026)\] + \[[#29026](https://community.openproject.org/wp/29026)\] - Fixed: Incorrect spacings on WP full view (mobile) - \[[#29154](https://community.openproject.com/wp/29154)\] - - Fixed: Mobile notifications hidden by topbar - \[[#29171](https://community.openproject.com/wp/29171)\] + \[[#29154](https://community.openproject.org/wp/29154)\] + - Fixed: Mobile notifications hidden by top bar + \[[#29171](https://community.openproject.org/wp/29171)\] - Fixed: Missing colors for status selector and type indicator in Chrome pdf export - \[[#29175](https://community.openproject.com/wp/29175)\] + \[[#29175](https://community.openproject.org/wp/29175)\] - Fixed: Unnecessary truncation on work package page (split screen) - \[[#29191](https://community.openproject.com/wp/29191)\] - - Fixed: Cost reports: broken scrolling behaviour - \[[#29204](https://community.openproject.com/wp/29204)\] + \[[#29191](https://community.openproject.org/wp/29191)\] + - Fixed: Cost reports: broken scrolling behavior + \[[#29204](https://community.openproject.org/wp/29204)\] - Fixed: Title of default views changes after visiting a work package - full view \[[#29211](https://community.openproject.com/wp/29211)\] + full view \[[#29211](https://community.openproject.org/wp/29211)\] - Fixed: Two column layout not applied on page reload - \[[#29238](https://community.openproject.com/wp/29238)\] + \[[#29238](https://community.openproject.org/wp/29238)\] - Fixed: Work package table header not sticky on MS Edge, Opera, Safari - \[[#29239](https://community.openproject.com/wp/29239)\] + \[[#29239](https://community.openproject.org/wp/29239)\] - Fixed: Work package table hierarchy arrows incorrectly indented on MS - Edge \[[#29242](https://community.openproject.com/wp/29242)\] + Edge \[[#29242](https://community.openproject.org/wp/29242)\] - Changed: When creating version on “Backlogs” page redirect to Backlogs page (not project settings) - \[[#29182](https://community.openproject.com/wp/29182)\] + \[[#29182](https://community.openproject.org/wp/29182)\] - Changed: A security / update warning notification is shown by default for administrators on specific pages. [Please see the configuration diff --git a/docs/release-notes/8/8-3-0/README.md b/docs/release-notes/8/8-3-0/README.md index d28fbfb2a2bc..ffee8286f4a1 100644 --- a/docs/release-notes/8/8-3-0/README.md +++ b/docs/release-notes/8/8-3-0/README.md @@ -10,7 +10,7 @@ # OpenProject 8.3.0 We released -[OpenProject 8.3.0](https://community.openproject.com/versions/1319). +[OpenProject 8.3.0](https://community.openproject.org/versions/1319). The release contains several bug fixes and we recommend updating to the newest version. @@ -71,85 +71,85 @@ Administration \> OAuth applications. #### Bug fixes and changes - Feature: OAuth2 authorization flow - \[[#28952](https://community.openproject.com/wp/28952)\] + \[[#28952](https://community.openproject.org/wp/28952)\] - Feature: Global Search: Autocompletion on work package subjects - \[[#29218](https://community.openproject.com/wp/29218)\] + \[[#29218](https://community.openproject.org/wp/29218)\] - Feature: Auto completion for work package attributes - \[[#29257](https://community.openproject.com/wp/29257)\] + \[[#29257](https://community.openproject.org/wp/29257)\] - Feature: Migrate existing my page data - \[[#29357](https://community.openproject.com/wp/29357)\] + \[[#29357](https://community.openproject.org/wp/29357)\] - Feature: Global search defaults on work packages and shows a table - as result \[[#29388](https://community.openproject.com/wp/29388)\] + as result \[[#29388](https://community.openproject.org/wp/29388)\] - Feature: Better error reporting for bulk edit - \[[#29561](https://community.openproject.com/wp/29561)\] + \[[#29561](https://community.openproject.org/wp/29561)\] - Feature: Automatic calculation of work packages per pagination based on widget height - \[[#29467](https://community.openproject.com/wp/29467)\] + \[[#29467](https://community.openproject.org/wp/29467)\] - Changed: Draw work packages without end date up to the current date in timeline - \[[#25471](https://community.openproject.com/wp/25471)\] + \[[#25471](https://community.openproject.org/wp/25471)\] - Changed: Deactivate option “Use current date as start date for new work packages” by default - \[[#29468](https://community.openproject.com/wp/29468)\] + \[[#29468](https://community.openproject.org/wp/29468)\] - Changed: When sending iCalendar invitation, include email to user who sends out invitation - \[[#29485](https://community.openproject.com/wp/29485)\] + \[[#29485](https://community.openproject.org/wp/29485)\] - Changed: Projects are now being deleted in a background job. - Fixed: Problems when exporting in unified diff - \[[#26599](https://community.openproject.com/wp/26599)\] + \[[#26599](https://community.openproject.org/wp/26599)\] - Fixed: In repository module diff does not escape HTML tags that are present in the compared code - \[[#26614](https://community.openproject.com/wp/26614)\] + \[[#26614](https://community.openproject.org/wp/26614)\] - Fixed: Incompatible browsers warning not shown in IE11 and older FF - \[[#28484](https://community.openproject.com/wp/28484)\] + \[[#28484](https://community.openproject.org/wp/28484)\] - Fixed: Table menu in WYSIWYG editor is cut off on smaller screens - \[[#28815](https://community.openproject.com/wp/28815)\] + \[[#28815](https://community.openproject.org/wp/28815)\] - Fixed: Upgrading reverts protocol to HTTP - \[[#28954](https://community.openproject.com/wp/28954)\] + \[[#28954](https://community.openproject.org/wp/28954)\] - Fixed: Icon texts are not consistently used in tables - \[[#29072](https://community.openproject.com/wp/29072)\] + \[[#29072](https://community.openproject.org/wp/29072)\] - Fixed: Blank circles before work package’s type after upgrading to - 8.1 \[[#29082](https://community.openproject.com/wp/29082)\] + 8.1 \[[#29082](https://community.openproject.org/wp/29082)\] - Fixed: Dependencies for fulltext search in work package attachments not installed with packager installation - \[[#29085](https://community.openproject.com/wp/29085)\] + \[[#29085](https://community.openproject.org/wp/29085)\] - Fixed: Sorting doesn’t work with 8.1 when also using Hierarchy - \[[#29122](https://community.openproject.com/wp/29122)\] + \[[#29122](https://community.openproject.org/wp/29122)\] - Fixed: Very large custom field is killing web browser - \[[#29136](https://community.openproject.com/wp/29136)\] + \[[#29136](https://community.openproject.org/wp/29136)\] - Fixed: Delete projects in delayed job - \[[#29214](https://community.openproject.com/wp/29214)\] + \[[#29214](https://community.openproject.org/wp/29214)\] - Fixed: SVN fails to get changesets in subfolders which start at a revision greater than 1 - \[[#29402](https://community.openproject.com/wp/29402)\] + \[[#29402](https://community.openproject.org/wp/29402)\] - Fixed: “Set Parent” not translated in work package view - \[[#29447](https://community.openproject.com/wp/29447)\] + \[[#29447](https://community.openproject.org/wp/29447)\] - Fixed: WP content does not close right side gap - \[[#29448](https://community.openproject.com/wp/29448)\] + \[[#29448](https://community.openproject.org/wp/29448)\] - Fixed: Redundant type declaration in relations tab - \[[#29460](https://community.openproject.com/wp/29460)\] + \[[#29460](https://community.openproject.org/wp/29460)\] - Fixed: Better error handling on attachment max size exceeded - \[[#29461](https://community.openproject.com/wp/29461)\] + \[[#29461](https://community.openproject.org/wp/29461)\] - Fixed: Improve structure for news section - \[[#29464](https://community.openproject.com/wp/29464)\] + \[[#29464](https://community.openproject.org/wp/29464)\] - Fixed: Editor dropdown is cut off when opened to top - \[[#29482](https://community.openproject.com/wp/29482)\] + \[[#29482](https://community.openproject.org/wp/29482)\] - Fixed: Custom fields for groups throw error message when set - \[[#29486](https://community.openproject.com/wp/29486)\] + \[[#29486](https://community.openproject.org/wp/29486)\] - Fixed: Column shifts when opening autocompleter - \[[#29492](https://community.openproject.com/wp/29492)\] + \[[#29492](https://community.openproject.org/wp/29492)\] - Fixed: Gantt chart not properly aligned when using groups - \[[#29497](https://community.openproject.com/wp/29497)\] + \[[#29497](https://community.openproject.org/wp/29497)\] - Fixed: White space between first table row and header - \[[#29521](https://community.openproject.com/wp/29521)\] + \[[#29521](https://community.openproject.org/wp/29521)\] - Fixed: Different font sizes on WP page - \[[#29528](https://community.openproject.com/wp/29528)\] + \[[#29528](https://community.openproject.org/wp/29528)\] - Fixed: Cannot select category because font is invisible - \[[#29531](https://community.openproject.com/wp/29531)\] + \[[#29531](https://community.openproject.org/wp/29531)\] - Fixed: Search bar too long on mobile Safari browser - \[[#29553](https://community.openproject.com/wp/29553)\] + \[[#29553](https://community.openproject.org/wp/29553)\] - Fixed: Docker incoming-mails not logged - \[[#29575](https://community.openproject.com/wp/29575)\] + \[[#29575](https://community.openproject.org/wp/29575)\] #### Contributions diff --git a/docs/release-notes/8/8-3-1/README.md b/docs/release-notes/8/8-3-1/README.md index ffa9d44be844..d320236cae92 100644 --- a/docs/release-notes/8/8-3-1/README.md +++ b/docs/release-notes/8/8-3-1/README.md @@ -10,7 +10,7 @@ # OpenProject 8.3.1 We released -[OpenProject 8.3.1](https://community.openproject.com/versions/1355). +[OpenProject 8.3.1](https://community.openproject.org/versions/1355). The release contains several bug and security related fixes and we urge updating to the newest version. @@ -24,27 +24,27 @@ and CVE-2019-5420](https://weblog.rubyonrails.org/2019/3/13/Rails-4-2-5-1-5-1-6- - Fixed: Long Work Package titles not wrapped in Cost Reports - \[[#28766](https://community.openproject.com/wp/28766)\] + \[[#28766](https://community.openproject.org/wp/28766)\] - Fixed: Cannot sort by custom field of type “Float” if named “Position” - \[[#29655](https://community.openproject.com/wp/29655)\] + \[[#29655](https://community.openproject.org/wp/29655)\] - Fixed: WorkPackage search results load results thrice and are slow because of it - \[[#29715](https://community.openproject.com/wp/29715)\] + \[[#29715](https://community.openproject.org/wp/29715)\] - Fixed: Internal error when accessing budget detail view - \[[#29718](https://community.openproject.com/wp/29718)\] + \[[#29718](https://community.openproject.org/wp/29718)\] - Fixed: Search page loads slowly initially - \[[#29719](https://community.openproject.com/wp/29719)\] + \[[#29719](https://community.openproject.org/wp/29719)\] - Fixed: Manually set admin flag being unset by SAML authentication - \[[#29720](https://community.openproject.com/wp/29720)\] + \[[#29720](https://community.openproject.org/wp/29720)\] - Fixed: Gantt Zoom buttons are inverted - \[[#29721](https://community.openproject.com/wp/29721)\] + \[[#29721](https://community.openproject.org/wp/29721)\] - Fixed: Attachments deleted on work package update via email - \[[#29722](https://community.openproject.com/wp/29722)\] + \[[#29722](https://community.openproject.org/wp/29722)\] - Changed: Allow instances to define a legal notice link to be - rendered \[[#29697](https://community.openproject.com/wp/29697)\] + rendered \[[#29697](https://community.openproject.org/wp/29697)\] - Changed: Make Gravatar default image configurable again - \[[#29711](https://community.openproject.com/wp/29711)\] + \[[#29711](https://community.openproject.org/wp/29711)\] #### Contributions diff --git a/docs/release-notes/9/9-0-0/README.md b/docs/release-notes/9/9-0-0/README.md index f43cdb23160b..84d250602362 100644 --- a/docs/release-notes/9/9-0-0/README.md +++ b/docs/release-notes/9/9-0-0/README.md @@ -63,7 +63,7 @@ Creating work packages on the global work package table is now easier as well: W Filters and work package attributes are improved and support auto-completion. -For an overview of all new improvements, take a look at the [feature list](https://community.openproject.com/projects/openproject/work_packages?query_props={"c"%3A["id"%2C"subject"%2C"type"%2C"status"%2C"assignee"%2C"version"]%2C"hi"%3Atrue%2C"g"%3A""%2C"t"%3A"id%3Aasc"%2C"f"%3A[{"n"%3A"status"%2C"o"%3A"!"%2C"v"%3A["6"]}%2C{"n"%3A"version"%2C"o"%3A"%3D"%2C"v"%3A["853"]}%2C{"n"%3A"subprojectId"%2C"o"%3A"*"%2C"v"%3A[]}%2C{"n"%3A"type"%2C"o"%3A"%3D"%2C"v"%3A["6"%2C"8"]}]%2C"pa"%3A1%2C"pp"%3A100}). +For an overview of all new improvements, take a look at the [feature list](https://community.openproject.org/projects/openproject/work_packages?query_props={"c"%3A["id"%2C"subject"%2C"type"%2C"status"%2C"assignee"%2C"version"]%2C"hi"%3Atrue%2C"g"%3A""%2C"t"%3A"id%3Aasc"%2C"f"%3A[{"n"%3A"status"%2C"o"%3A"!"%2C"v"%3A["6"]}%2C{"n"%3A"version"%2C"o"%3A"%3D"%2C"v"%3A["853"]}%2C{"n"%3A"subprojectId"%2C"o"%3A"*"%2C"v"%3A[]}%2C{"n"%3A"type"%2C"o"%3A"%3D"%2C"v"%3A["6"%2C"8"]}]%2C"pa"%3A1%2C"pp"%3A100}). @@ -71,7 +71,7 @@ For an overview of all new improvements, take a look at the [feature list](https OpenProject 9.0 contains a large number of bugs fixes. -For an extensive overview of bug fixes please refer to the [following list](https://community.openproject.com/projects/openproject/work_packages?query_props={"c"%3A["id"%2C"subject"%2C"type"%2C"status"%2C"assignee"]%2C"hi"%3Afalse%2C"g"%3A""%2C"t"%3A"id%3Adesc"%2C"f"%3A[{"n"%3A"version"%2C"o"%3A"%3D"%2C"v"%3A["853"]}%2C{"n"%3A"type"%2C"o"%3A"%3D"%2C"v"%3A["1"]}%2C{"n"%3A"subprojectId"%2C"o"%3A"*"%2C"v"%3A[]}]%2C"pa"%3A1%2C"pp"%3A20}). +For an extensive overview of bug fixes please refer to the [following list](https://community.openproject.org/projects/openproject/work_packages?query_props={"c"%3A["id"%2C"subject"%2C"type"%2C"status"%2C"assignee"]%2C"hi"%3Afalse%2C"g"%3A""%2C"t"%3A"id%3Adesc"%2C"f"%3A[{"n"%3A"version"%2C"o"%3A"%3D"%2C"v"%3A["853"]}%2C{"n"%3A"type"%2C"o"%3A"%3D"%2C"v"%3A["1"]}%2C{"n"%3A"subprojectId"%2C"o"%3A"*"%2C"v"%3A[]}]%2C"pa"%3A1%2C"pp"%3A20}). diff --git a/docs/release-notes/9/9-0-1/README.md b/docs/release-notes/9/9-0-1/README.md index 5581bdb06117..bcfa6bda3033 100644 --- a/docs/release-notes/9/9-0-1/README.md +++ b/docs/release-notes/9/9-0-1/README.md @@ -8,23 +8,23 @@ release_date: 2019-06-07 -We released [OpenProject 9.0.1](https://community.openproject.com/versions/1368). +We released [OpenProject 9.0.1](https://community.openproject.org/versions/1368). The release contains several bug fixes and we recommend updating to the newest version. #### Bug fixes and changes -- Fixed: Wiki TOC doesn't render headings properly [[#30245](https://community.openproject.com/wp/30245)] -- Fixed: Doubled files section in meeting agenda [[#30291](https://community.openproject.com/wp/30291)] -- Fixed: Row highlighted by 'Type' makes table text unreadable [[#30298](https://community.openproject.com/wp/30298)] -- Fixed: Cannot copy projects & wrong error message [[#30309](https://community.openproject.com/wp/30309)] -- Fixed: Dark background for getting started tour does not cover entire page [[#30314](https://community.openproject.com/wp/30314)] -- Fixed: JavaScript error when clicking on a link in My Page [[#30343](https://community.openproject.com/wp/30343)] -- Fixed: Highlighting for add relation in Gantt chart not applied properly [[#30354](https://community.openproject.com/wp/30354)] -- Changed: Styled scrollbars in WP views [[#30304](https://community.openproject.com/wp/30304)] -- Changed: Improve print view of cost report via CSS [[#30305](https://community.openproject.com/wp/30305)] -- Changed: Ensure PostgreSQL migration is finished before attachments are re-inserted [[#30352](https://community.openproject.com/wp/30352)] +- Fixed: Wiki TOC doesn't render headings properly [[#30245](https://community.openproject.org/wp/30245)] +- Fixed: Doubled files section in meeting agenda [[#30291](https://community.openproject.org/wp/30291)] +- Fixed: Row highlighted by 'Type' makes table text unreadable [[#30298](https://community.openproject.org/wp/30298)] +- Fixed: Cannot copy projects & wrong error message [[#30309](https://community.openproject.org/wp/30309)] +- Fixed: Dark background for getting started tour does not cover entire page [[#30314](https://community.openproject.org/wp/30314)] +- Fixed: JavaScript error when clicking on a link in My Page [[#30343](https://community.openproject.org/wp/30343)] +- Fixed: Highlighting for add relation in Gantt chart not applied properly [[#30354](https://community.openproject.org/wp/30354)] +- Changed: Styled scrollbars in WP views [[#30304](https://community.openproject.org/wp/30304)] +- Changed: Improve print view of cost report via CSS [[#30305](https://community.openproject.org/wp/30305)] +- Changed: Ensure PostgreSQL migration is finished before attachments are re-inserted [[#30352](https://community.openproject.org/wp/30352)] #### Contributions diff --git a/docs/release-notes/9/9-0-2/README.md b/docs/release-notes/9/9-0-2/README.md index 7d6f6e57b99b..ff58f926dce9 100644 --- a/docs/release-notes/9/9-0-2/README.md +++ b/docs/release-notes/9/9-0-2/README.md @@ -8,17 +8,17 @@ release_date: 2019-06-13 # OpenProject 9.0.2 -We released [OpenProject 9.0.2](https://community.openproject.com/versions/1359). -The release contains several bug fixes and we recommend updating to the newest version. If you're running OpenProject with a relative URL root (e.g., under domain.example.org/openproject), this update should fix [an installation issue related to Sass compilation](https://community.openproject.com/wp/30372) as well as [an error trying to use create new boards](https://community.openproject.com/wp/30370). +We released [OpenProject 9.0.2](https://community.openproject.org/versions/1359). +The release contains several bug fixes and we recommend updating to the newest version. If you're running OpenProject with a relative URL root (e.g., under domain.example.org/openproject), this update should fix [an installation issue related to Sass compilation](https://community.openproject.org/wp/30372) as well as [an error trying to use create new boards](https://community.openproject.org/wp/30370). #### Bug fixes and changes -- **Fixed**: Wiki TOC doesn't render headings properly [[#30245](https://community.openproject.com/wp/30245)] -- **Fixed**: Cannot create new boards in installations with relative_url_root set [[#30370](https://community.openproject.com/wp/30370)] -- **Fixed**: Sass compilation fails on packaged installations with relative_url_root set [[#30372](https://community.openproject.com/wp/30372)] -- **Fixed**: Chrome is logged out when accessing pages with images on S3 storage [[#28652](https://community.openproject.com/wp/28652)] -- **Fixed**: OpenProject logo on My page does not redirect to landing page [[#30376](https://community.openproject.com/wp/30376)] -- **Fixed**: The PDF export is cut off after the first page [[#29929](https://community.openproject.com/wp/29929)] +- **Fixed**: Wiki TOC doesn't render headings properly [[#30245](https://community.openproject.org/wp/30245)] +- **Fixed**: Cannot create new boards in installations with relative_url_root set [[#30370](https://community.openproject.org/wp/30370)] +- **Fixed**: Sass compilation fails on packaged installations with relative_url_root set [[#30372](https://community.openproject.org/wp/30372)] +- **Fixed**: Chrome is logged out when accessing pages with images on S3 storage [[#28652](https://community.openproject.org/wp/28652)] +- **Fixed**: OpenProject logo on My page does not redirect to landing page [[#30376](https://community.openproject.org/wp/30376)] +- **Fixed**: The PDF export is cut off after the first page [[#29929](https://community.openproject.org/wp/29929)] diff --git a/docs/release-notes/9/9-0-3/README.md b/docs/release-notes/9/9-0-3/README.md index 269f728f981e..98fa590c338f 100644 --- a/docs/release-notes/9/9-0-3/README.md +++ b/docs/release-notes/9/9-0-3/README.md @@ -8,42 +8,42 @@ release_date: 2019-07-23 # OpenProject 9.0.3 -We released [OpenProject 9.0.3](https://community.openproject.com/versions/1376). +We released [OpenProject 9.0.3](https://community.openproject.org/versions/1376). The release contains several bug fixes and we recommend updating to the newest version. #### Bug fixes and changes -- Changed: Searching for Custom Fields [[#29756](https://community.openproject.com/wp/29756)] -- Changed: Prevent collisions between users working on the same board [[#30403](https://community.openproject.com/wp/30403)] -- Changed: Do not send email notifications for changes in child work packages [[#30532](https://community.openproject.com/wp/30532)] -- Fixed: Version field flickers [[#30356](https://community.openproject.com/wp/30356)] -- Fixed: Missing translations for boards [[#30367](https://community.openproject.com/wp/30367)] -- Fixed: Work package description not updated after initial edit [[#30373](https://community.openproject.com/wp/30373)] -- Fixed: Parent work package in Gantt chart not displayed correctly [[#30388](https://community.openproject.com/wp/30388)] -- Fixed: Cannot delete date from work packages of a type that is a milestone [[#30390](https://community.openproject.com/wp/30390)] -- Fixed: Work packages in closed version suggest status editable but then nothing happens [[#30396](https://community.openproject.com/wp/30396)] -- Fixed: Wrong language is displayed in some date fields [[#30400](https://community.openproject.com/wp/30400)] -- Fixed: Project Paisy: Connecting functional document fails without error message [[#30404](https://community.openproject.com/wp/30404)] -- Fixed: Button Release to production not visible for Releasemanager [[#30405](https://community.openproject.com/wp/30405)] -- Fixed: Text references to SVN revisions don't create links [[#30415](https://community.openproject.com/wp/30415)] -- Fixed: User with :manage_boards but without :manage_public_queries can create faulty board columns [[#30426](https://community.openproject.com/wp/30426)] -- Fixed: Tag shown on My page for time tracking comments [[#30432](https://community.openproject.com/wp/30432)] -- Fixed: [Error 500] An error occurred on the page you were trying to access [[#30435](https://community.openproject.com/wp/30435)] -- Fixed: OmniAuth login link in top menu not styled properly. [[#30436](https://community.openproject.com/wp/30436)] -- Fixed: Board list not sorted alphabetically [[#30444](https://community.openproject.com/wp/30444)] -- Fixed: Not all multiples of 4096 bytes are folders [[#30450](https://community.openproject.com/wp/30450)] -- Fixed: Search work package hints are not links [[#30457](https://community.openproject.com/wp/30457)] -- Fixed: New API-backed attachments always use content disposition attachment [[#30492](https://community.openproject.com/wp/30492)] -- Fixed: Can not switch to hierarchy mode in work packages list [[#30514](https://community.openproject.com/wp/30514)] -- Fixed: Error when copying a work package [[#30518](https://community.openproject.com/wp/30518)] -- Fixed: Gantt chart: Jump when scheduling finish date of work package with only start date [[#30554](https://community.openproject.com/wp/30554)] -- Fixed: Comma and dot flipped for values in cost report and budgets (German language setting) [[#30574](https://community.openproject.com/wp/30574)] -- Fixed: Inline-create useless when only add_work_packages_permission present [[#30589](https://community.openproject.com/wp/30589)] -- Fixed: Cannot close Arbeitspaket [[#30590](https://community.openproject.com/wp/30590)] -- Fixed: "Login" instead of "Login name" used (causes problems with translations) [[#30591](https://community.openproject.com/wp/30591)] -- Fixed: Board links in sidebar broken [[#30595](https://community.openproject.com/wp/30595)] +- Changed: Searching for Custom Fields [[#29756](https://community.openproject.org/wp/29756)] +- Changed: Prevent collisions between users working on the same board [[#30403](https://community.openproject.org/wp/30403)] +- Changed: Do not send email notifications for changes in child work packages [[#30532](https://community.openproject.org/wp/30532)] +- Fixed: Version field flickers [[#30356](https://community.openproject.org/wp/30356)] +- Fixed: Missing translations for boards [[#30367](https://community.openproject.org/wp/30367)] +- Fixed: Work package description not updated after initial edit [[#30373](https://community.openproject.org/wp/30373)] +- Fixed: Parent work package in Gantt chart not displayed correctly [[#30388](https://community.openproject.org/wp/30388)] +- Fixed: Cannot delete date from work packages of a type that is a milestone [[#30390](https://community.openproject.org/wp/30390)] +- Fixed: Work packages in closed version suggest status editable but then nothing happens [[#30396](https://community.openproject.org/wp/30396)] +- Fixed: Wrong language is displayed in some date fields [[#30400](https://community.openproject.org/wp/30400)] +- Fixed: Project Paisy: Connecting functional document fails without error message [[#30404](https://community.openproject.org/wp/30404)] +- Fixed: Button Release to production not visible for Release manager [[#30405](https://community.openproject.org/wp/30405)] +- Fixed: Text references to SVN revisions don't create links [[#30415](https://community.openproject.org/wp/30415)] +- Fixed: User with :manage_boards but without :manage_public_queries can create faulty board columns [[#30426](https://community.openproject.org/wp/30426)] +- Fixed: Tag shown on My page for time tracking comments [[#30432](https://community.openproject.org/wp/30432)] +- Fixed: [Error 500] An error occurred on the page you were trying to access [[#30435](https://community.openproject.org/wp/30435)] +- Fixed: OmniAuth login link in top menu not styled properly. [[#30436](https://community.openproject.org/wp/30436)] +- Fixed: Board list not sorted alphabetically [[#30444](https://community.openproject.org/wp/30444)] +- Fixed: Not all multiples of 4096 bytes are folders [[#30450](https://community.openproject.org/wp/30450)] +- Fixed: Search work package hints are not links [[#30457](https://community.openproject.org/wp/30457)] +- Fixed: New API-backed attachments always use content disposition attachment [[#30492](https://community.openproject.org/wp/30492)] +- Fixed: Can not switch to hierarchy mode in work packages list [[#30514](https://community.openproject.org/wp/30514)] +- Fixed: Error when copying a work package [[#30518](https://community.openproject.org/wp/30518)] +- Fixed: Gantt chart: Jump when scheduling finish date of work package with only start date [[#30554](https://community.openproject.org/wp/30554)] +- Fixed: Comma and dot flipped for values in cost report and budgets (German language setting) [[#30574](https://community.openproject.org/wp/30574)] +- Fixed: Inline-create useless when only add_work_packages_permission present [[#30589](https://community.openproject.org/wp/30589)] +- Fixed: Cannot close work package [[#30590](https://community.openproject.org/wp/30590)] +- Fixed: "Login" instead of "Login name" used (causes problems with translations) [[#30591](https://community.openproject.org/wp/30591)] +- Fixed: Board links in sidebar broken [[#30595](https://community.openproject.org/wp/30595)] #### Contributions diff --git a/docs/release-notes/9/9-0-4/README.md b/docs/release-notes/9/9-0-4/README.md index 0d10d4696b05..639f489c27c0 100644 --- a/docs/release-notes/9/9-0-4/README.md +++ b/docs/release-notes/9/9-0-4/README.md @@ -20,4 +20,4 @@ Thanks to David Haintz from the SEC Consult Vulnerability Lab (https://www.sec-c #### Contributions -Thanks to David Haintz from [SEC Consult Vulnerability Lab](https://www.sec-consult.com/) for identifying and responsibly disclosing the identified issues. +Thanks to David Haintz from [SEC Consult Vulnerability Lab](https://www.sec-consult.com) for identifying and responsibly disclosing the identified issues. diff --git a/docs/release-notes/README.md b/docs/release-notes/README.md index 054dbf2c7969..c92449582c07 100644 --- a/docs/release-notes/README.md +++ b/docs/release-notes/README.md @@ -14,6 +14,13 @@ Stay up to date and get an overview of the new features included in the releases +## 13.2.1 + +Release date: 2024-01-31 + +[Release Notes](13-2-1/) + + ## 13.2.0 Release date: 2024-01-17 diff --git a/docs/security-and-privacy/processing-of-personal-data/README.md b/docs/security-and-privacy/processing-of-personal-data/README.md index 417be4729129..a0a2df031d43 100644 --- a/docs/security-and-privacy/processing-of-personal-data/README.md +++ b/docs/security-and-privacy/processing-of-personal-data/README.md @@ -170,7 +170,7 @@ Depending on the individual use and permissions of the user the following person - Assignment of a work package to a person - Change history - Person mentioned in a list or project schedule -- Person mentioned in an attributs or text field +- Person mentioned in an attribute or text field - Person mentioned in a linked file - Person mentioned in a linked pull request (i.e. GitHub) @@ -197,7 +197,7 @@ The data listed above is generated upon entering the application. When actually Logfiles are automatically removed based on a first-in-first-out mechanism. This is done to limit the disk space which ensures the server's operation and at the same time serves as a means to erase the log entries once they have served their purpose of supporting operations. By default the retention period is determined by the size of the logfile. Once the logfile reaches its storage limit, the oldest entries are removed. -As such, the log entries are not kept for a fixed period of time. If there are a lot of requests, old entries are removed faster then if there are less requests. Administrators of an OpenProject installation might decide to configure a different behaviour that factors in the age of the log entries. +As such, the log entries are not kept for a fixed period of time. If there are a lot of requests, old entries are removed faster then if there are less requests. Administrators of an OpenProject installation might decide to configure a different behavior that factors in the age of the log entries. #### Technical documentation @@ -388,7 +388,7 @@ flowchart LR #### Purpose -* Create a new work package by sending an email to a configured email adress. +* Create a new work package by sending an email to a configured email address. * Adding a comment to an existing work package by answering to an email notification. * Sending email notifications about updates in OpenProject (e.g [email reminder](../../system-admin-guide/emails-and-notifications/), meeting updates, project invitation, wiki notifications) @@ -642,9 +642,9 @@ OpenProject makes use of technical cookies to identity the browser client and/or | **Cookie name** | **Description** | **Expiry** | **Security flags** | **Implementation** | | ---------------------------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | ----------------------------------------------------- | ------------------------------------------------------------ | -| `_open_project_session` (name is configurable) | contains the information about the logged in user as well as information stored between requests on the user's choices (e.g. the filters for costs are in part stored there) | Session
+ configurable server-sideTTL | secure
httponly
Samesite=Lax
encrypted | [Code ref](https://github.com/opf/openproject/blob/release/13.0/config/initializers/session_store.rb#L34-L39) | -| `autologin` (name is configurable) | (Optional feature, requires opt-in under Administration > Authentication settings)
enables the user to automatically log in again after the session expired (e.g. because the browser was closed). It is set when the user checks the '*Stay logged in*' box in the login form.
| Cookie 1 year
+ server-side token N days (configurable) | secure
httponly
Samesite=Lax
encrypted | [Code ref](https://github.com/opf/openproject/blob/release/13.0/app/controllers/concerns/accounts/user_login.rb#L19C1-L29) | -| `op2fa_remember_token` | the presence of that cookie suppresses the need for the user to provide a second factor upon login for N days (configurable by administration) if the user selects to do so when entering the 2fa information. | N days (configurable) | secure
httponly
Samesite=Lax
encrypted | [Code ref](https://github.com/opf/openproject/blob/release/13.0/modules/two_factor_authentication/app/controllers/concerns/two_factor_authentication/remember_token.rb#L28-L34) | +| `_open_project_session` (name is configurable) | contains the information about the logged in user as well as information stored between requests on the user's choices (e.g. the filters for costs are in part stored there) | Session
+ configurable server-sideTTL | secure
httponly
Samesite=Lax
encrypted | [Code ref](https://github.com/opf/openproject/blob/release/13.0/config/initializers/session_store.rb#L34-L39) | +| `autologin` (name is configurable) | (Optional feature, requires opt-in under Administration > Authentication settings)
enables the user to automatically log in again after the session expired (e.g. because the browser was closed). It is set when the user checks the '*Stay logged in*' box in the login form.
| Cookie 1 year
+ server-side token N days (configurable) | secure
httponly
Samesite=Lax
encrypted | [Code ref](https://github.com/opf/openproject/blob/release/13.0/app/controllers/concerns/accounts/user_login.rb#L19C1-L29) | +| `op2fa_remember_token` | the presence of that cookie suppresses the need for the user to provide a second factor upon login for N days (configurable by administration) if the user selects to do so when entering the 2fa information. | N days (configurable) | secure
httponly
Samesite=Lax
encrypted | [Code ref](https://github.com/opf/openproject/blob/release/13.0/modules/two_factor_authentication/app/controllers/concerns/two_factor_authentication/remember_token.rb#L28-L34) | ## Deletion of personal data diff --git a/docs/system-admin-guide/authentication/ldap-authentication/README.md b/docs/system-admin-guide/authentication/ldap-authentication/README.md index 9bcf7aac1ee7..5cc1fa494a63 100644 --- a/docs/system-admin-guide/authentication/ldap-authentication/README.md +++ b/docs/system-admin-guide/authentication/ldap-authentication/README.md @@ -47,7 +47,7 @@ In the upper section, you have to specify the connection details of your LDAP se - **Verify SSL certificate**: By default, for STARTTLS and LDAPS, SSL certificate trust chains will be verified during connection. As many LDAP servers in our experience use self-signed certificates, checking this option without providing the SSL certificate will fail. However, we recommend you enable this checkbox for any LDAP connections used in production. - - **LDAP server SSL certificate**: If the LDAP server's certificate is not trusted on the system that the OpenProject server runs on, you have the option to specifiy one or multiple PEM-encoded X509 certificates. This certificate might be the LDAP server's own certificate, or an intermediate or root CA that you trust for the sake of this connection. + - **LDAP server SSL certificate**: If the LDAP server's certificate is not trusted on the system that the OpenProject server runs on, you have the option to specify one or multiple PEM-encoded X509 certificates. This certificate might be the LDAP server's own certificate, or an intermediate or root CA that you trust for the sake of this connection. #### LDAP system user credentials diff --git a/docs/system-admin-guide/authentication/oauth-applications/README.md b/docs/system-admin-guide/authentication/oauth-applications/README.md index 4116cbbe2b0b..9eba0bdc283c 100644 --- a/docs/system-admin-guide/authentication/oauth-applications/README.md +++ b/docs/system-admin-guide/authentication/oauth-applications/README.md @@ -26,7 +26,7 @@ You can configure the following options to add your OAuth application: `urn:ietf:wg:oauth:2.0:oob` Postman 9.6 and higher also provides a Web URL that you can use: `https://oauth.pstmn.io/v1/callback`. -3. Set the **Scopes** that the OAuth clien application will be +3. Set the **Scopes** that the OAuth client application will be able to access. Multiple selection is possible. If no scope is checked, per default **api_v3** is assumed. api_v3 is the standard OpenProject API, while diff --git a/docs/system-admin-guide/authentication/openid-providers/README.md b/docs/system-admin-guide/authentication/openid-providers/README.md index 521ce21b9d39..54baa3f65a9d 100644 --- a/docs/system-admin-guide/authentication/openid-providers/README.md +++ b/docs/system-admin-guide/authentication/openid-providers/README.md @@ -167,7 +167,7 @@ At the end of this step, you should have a copy of the Application client ID as Now, head over to OpenProject > Administration > OpenID providers. Click on "New OpenID provider", select the Azure type, enter the client ID and client Secret. -By default, OpenProject will use the Microsoft Graph API endpoint to perform userinfo requests. +By default, OpenProject will use the Microsoft Graph API endpoint to perform user info requests. For that, you will need to enter the correct tenant identifier for your Azure instance. To find the correct value for your instance, [please see this guide](https://learn.microsoft.com/en-us/azure/active-directory/develop/v2-protocols-oidc#find-your-apps-openid-configuration-document-uri). diff --git a/docs/system-admin-guide/authentication/recaptcha/README.md b/docs/system-admin-guide/authentication/recaptcha/README.md index 7d6493e165f3..30ad73f7df77 100644 --- a/docs/system-admin-guide/authentication/recaptcha/README.md +++ b/docs/system-admin-guide/authentication/recaptcha/README.md @@ -18,4 +18,4 @@ You can configure the following options: 3. Insert the **secret key**. 4. Press the blue **Apply** button to save your changes. -![Sys-admin-authentication-recaptcha](Sys-admin-authentication-recaptcha.png) +![Sysadmin authentication reCAPTCHA](Sys-admin-authentication-recaptcha.png) diff --git a/docs/system-admin-guide/authentication/saml/README.md b/docs/system-admin-guide/authentication/saml/README.md index f9ae3f5bd36d..bb3e15fef3ed 100644 --- a/docs/system-admin-guide/authentication/saml/README.md +++ b/docs/system-admin-guide/authentication/saml/README.md @@ -443,7 +443,7 @@ For ADFS, you need add OpenProject as a "relying part trust" entry within the AD - In the ADFS management snap-in, right click on`AD FS -> Relying Party Trusts` , and select `Add Relying Party Trust...` - Select **Claims aware** and hit Start - **Select Data Source**: Choose "Enter data about the relying party manually" and click Next -- **Specifiy Display Name**: Enter "OpenProject" or any arbitrary name for the OpenProject instance you want to identify +- **Specify Display Name**: Enter "OpenProject" or any arbitrary name for the OpenProject instance you want to identify - **Configure Certificate**: Skip this step, unless you explicitly want to enable assertion encryption, whose steps are documented for OpenProject above. - **Configure URL**: Check "Enable support for the SAML 2.0 WebSSO protocol" and enter the URL `https:///auth/saml` @@ -565,7 +565,7 @@ OPENPROJECT_SAML_SAML_IDP__SSO__SERVICE__URL="https:// /r OPENPROJECT_SAML_SAML_IDP__CERT=" " ``` -If you're unsure what the realm value is, go to the menu "Realm settings" and click on "Endpoints -> SAML 2.0 Identity Provider Metadata". This will include URLs for the `SingleSignOnSerivce` and `SingleLogoutService`. +If you're unsure what the realm value is, go to the menu "Realm settings" and click on "Endpoints -> SAML 2.0 Identity Provider Metadata". This will include URLs for the `SingleSignOnService` and `SingleLogoutService`. diff --git a/docs/system-admin-guide/backup/README.md b/docs/system-admin-guide/backup/README.md index 94ae3d970620..83e5e7908b39 100644 --- a/docs/system-admin-guide/backup/README.md +++ b/docs/system-admin-guide/backup/README.md @@ -43,7 +43,7 @@ After having requested the backup, you will receive an email notification with a If the user resetting (or creating) a backup token does not have a password, for instance because they authenticate using Google, the newly generated backup token will only be valid after an initial waiting period. -This is to make sure that no unauthorised user can get their hands on a backup even when accessing +This is to make sure that no unauthorized user can get their hands on a backup even when accessing a logged-in user's desktop. As a system administrator you can skip this period by running the following rake task on the server's terminal: diff --git a/docs/system-admin-guide/calendars-and-dates/README.md b/docs/system-admin-guide/calendars-and-dates/README.md index f0a4ca47074a..90e851163159 100644 --- a/docs/system-admin-guide/calendars-and-dates/README.md +++ b/docs/system-admin-guide/calendars-and-dates/README.md @@ -3,7 +3,7 @@ sidebar_navigation: title: Calendar and dates priority: 940 description: Configure working days, dates formats and calendar subscriptions -keywords: working non-working days work week dates calendars icalendar +keywords: working non-working days work week dates calendars ical icalendar --- # Calendar and dates @@ -59,7 +59,7 @@ We only recommend changing this setting if you are absolutely sure and you are a ### Effect on calendars -The non-working days defined here are coloured differently, generally with a darker background colour, on the [work package date picker](../../user-guide/work-packages/set-change-dates/#working-days-and-duration), [Gantt chart](../../user-guide/gantt-chart/) and the [Team planner](../../user-guide/team-planner/) and [calendar](../../user-guide/calendar/) modules. +The non-working days defined here are colored differently, generally with a darker background color, on the [work package date picker](../../user-guide/work-packages/set-change-dates/#working-days-and-duration), [Gantt chart](../../user-guide/gantt-chart/) and the [Team planner](../../user-guide/team-planner/) and [calendar](../../user-guide/calendar/) modules. ## Date format diff --git a/docs/system-admin-guide/custom-fields/README.md b/docs/system-admin-guide/custom-fields/README.md index 2781cc1bb043..4963ce43de11 100644 --- a/docs/system-admin-guide/custom-fields/README.md +++ b/docs/system-admin-guide/custom-fields/README.md @@ -63,7 +63,7 @@ To **edit an existing custom field** select the appropriate tab and click on the To **delete** a custom field, click on the delete icon next to the respective custom field in the list. -![Edit or delete a custom field in OpenProject adminstration](system-admin-edit-delete-custom-field.png) +![Edit or delete a custom field in OpenProject administration](system-admin-edit-delete-custom-field.png) diff --git a/docs/system-admin-guide/design/pdf-export-styles/README.md b/docs/system-admin-guide/design/pdf-export-styles/README.md index 7aac2bf2fb82..308466235fe2 100644 --- a/docs/system-admin-guide/design/pdf-export-styles/README.md +++ b/docs/system-admin-guide/design/pdf-export-styles/README.md @@ -596,14 +596,14 @@ overview: table: {} ``` -| Key | Description | Data type | -| - | - | - | -| `group_heading` | **Overview group heading**
Styling for the group lavel if grouping is activated
See [Overview group heading](#overview-group-heading) | object | -| `table` | **Overview table**
See [Overview table](#overview-table) | object | +| Key | Description | Data type | +|-----------------|-----------------------------------------------------------------------------------------------------------------------------------------------|-----------| +| `group_heading` | **Overview group heading**
Styling for the group label if grouping is activated
See [Overview group heading](#overview-group-heading) | object | +| `table` | **Overview table**
See [Overview table](#overview-table) | object | ## Overview group heading -Styling for the group lavel if grouping is activated +Styling for the group label if grouping is activated Key: `group_heading` diff --git a/docs/system-admin-guide/emails-and-notifications/README.md b/docs/system-admin-guide/emails-and-notifications/README.md index e018656dca80..39b9198c2090 100644 --- a/docs/system-admin-guide/emails-and-notifications/README.md +++ b/docs/system-admin-guide/emails-and-notifications/README.md @@ -21,7 +21,7 @@ Navigate to **Administration → Emails and notifications**. ![Administration setting email and notifications aggregation](admin-email-aggregation.png) -The setting **User actions aggregated within** specifies a time interval in which all notifications regarding a specific user's actions are bundled into one single notification. Individual actions of a user (e.g. updating a work package twice) are aggregated into a single action if their age difference is less than the specified timespan. They will be displayed as a single action within the application. This will also delay notifications by the same amount of time reducing the number of emails being sent. +The setting **User actions aggregated within** specifies a time interval in which all notifications regarding a specific user's actions are bundled into one single notification. Individual actions of a user (e.g. updating a work package twice) are aggregated into a single action if their age difference is less than the specified time span. They will be displayed as a single action within the application. This will also delay notifications by the same amount of time reducing the number of emails being sent. ## Email notifications settings diff --git a/docs/system-admin-guide/file-storages/README.md b/docs/system-admin-guide/file-storages/README.md index bab32cb69e74..5c36009d83d9 100644 --- a/docs/system-admin-guide/file-storages/README.md +++ b/docs/system-admin-guide/file-storages/README.md @@ -3,7 +3,7 @@ sidebar_navigation: title: File storages priority: 830 description: File storages in OpenProject. -keywords: file storages, nextcloud setup, nextcloud integration, onedrive setup, sharepoint setup, onedrive, sharepoint +keywords: file storages, Nextcloud setup, Nextcloud integration, OneDrive setup, Sharepoint setup, OneDrive, Sharepoint --- # File storages diff --git a/docs/system-admin-guide/integrations/excel-synchronization/README.md b/docs/system-admin-guide/integrations/excel-synchronization/README.md index 9b432a760949..e9576ea99dc8 100644 --- a/docs/system-admin-guide/integrations/excel-synchronization/README.md +++ b/docs/system-admin-guide/integrations/excel-synchronization/README.md @@ -46,7 +46,7 @@ You will then get the relations in your Excel file. Unfortunately, there is no way to create relation with translated terms via API at the moment. You have to use these terms instead: [Relation Edit Form API](../../../api/endpoints/relations/#relation-edit-form) -![allowd-values](image-20211014153150017.png) +![allowed values](image-20211014153150017.png) @@ -91,7 +91,7 @@ Unfortunately, there is no way to create relation with translated terms via API 9. Accept to start the synchronization. 10. You need to select a minimum of columns to start with the synchronization. For column selection, click in the header and open the drop down which opens next to the regular drop down icon: Select the following column headers at a minimum: - **Updatestatus** + **Update status** **Lock Version** **ID** **Subject** @@ -113,7 +113,7 @@ Copy and paste all data accordingly from your existing Excel list to this sheet. -**Download workpackages**: initially downloads all work packages from the selected project (and query). +**Download work packages**: initially downloads all work packages from the selected project (and query). **Upload / update work packages**: makes changes to the work packages, e.g. adding new work packages or changing any information. This option needs to be chosen in order to initially import and existing Excel list. **Show chosen project**: Opens the settings to adapt URL, API key, project or query ID. diff --git a/docs/system-admin-guide/integrations/nextcloud/README.md b/docs/system-admin-guide/integrations/nextcloud/README.md index 92b6af7924cb..f724f589b08a 100644 --- a/docs/system-admin-guide/integrations/nextcloud/README.md +++ b/docs/system-admin-guide/integrations/nextcloud/README.md @@ -117,7 +117,7 @@ In the page that appears, you will see new OAuth values that are once again gene OpenProject will need these values to be able to connect to your Nextcloud instance. -Much like in the previous step, you will need to copy these two generated values (**Nextcloud OAuth client ID** and **Nextcloud OAtuh client secret**) and paste them into OpenProject. +Much like in the previous step, you will need to copy these two generated values (**Nextcloud OAuth client ID** and **Nextcloud OAuth client secret**) and paste them into OpenProject. ![Nextcloud also generates OAuth values that need to be copied to OpenProject](3_2_04-NC_Step_3.png) @@ -135,11 +135,11 @@ As a last step, you will be asked if you want to use automatically managed folde In case you want to use this functionality you will be requested to enter a password. Switch back to Nextcloud and click on **Yes, I have copied these values**. This will open the last step of the process in Nextcloud, where you can also select if you want to use automatically managed folders. Click on **Setup OpenProject user, group and folder** to configure the folders and see the password. Once configured, you can copy the password back to OpenProject. -![Nextcloutd Automatically managed folders setup](nc-project_folders-active_default.png) +![Nextcloud Automatically managed folders setup](nc-project_folders-active_default.png) -![Nextcloutd Automatically managed folders](nc-project_folders-application_password.png) +![Nextcloud Automatically managed folders](nc-project_folders-application_password.png) -> **Important**: You will need to install the [Group folder](https://apps.nextcloud.com/apps/groupfolders) app in Nextcloudin order to have OpenProject automatically managed your Nextcloud folders. Each storage can only have one group folder with the same name. +> **Important**: You will need to install the [Group folder](https://apps.nextcloud.com/apps/groupfolders) app in Nextcloud in order to have OpenProject automatically managed your Nextcloud folders. Each storage can only have one group folder with the same name. At this point, you can click on **Done, complete setup** in both applications and your instance configuration will be completed. @@ -151,7 +151,7 @@ The **OpenProject Integration** page on your Nextcloud tab should also indicate The integration is now complete, and your OpenProject and Nextcloud instances are ready to share information. -Additional settings on this page also allow you, as an administrator, to define default settings for options that are available to each user. These can of course be overriden by a user to their liking: +Additional settings on this page also allow you, as an administrator, to define default settings for options that are available to each user. These can of course be overridden by a user to their liking: ![Admin settings to configure default settings for all users](NC_admin-defaults-user-options.png) diff --git a/docs/system-admin-guide/integrations/one-drive/drive-id-guide/README.md b/docs/system-admin-guide/integrations/one-drive/drive-id-guide/README.md index 565e86fa5739..85070c2676e1 100644 --- a/docs/system-admin-guide/integrations/one-drive/drive-id-guide/README.md +++ b/docs/system-admin-guide/integrations/one-drive/drive-id-guide/README.md @@ -63,7 +63,7 @@ found [here](https://developer.microsoft.com/en-us/graph/graph-explorer). - Click on the `Sign in` button in the top right corner. - Log in with your Microsoft account. - - Make sure to select the correct organisation to log in, as the graph explorer will try to specifically log into the + - Make sure to select the correct organization to log in, as the graph explorer will try to specifically log into the associated tenant. - After a successful login, the resolved tenant will be displayed for a sanity check. - Fetch the hostname of the tenant (e.g. `example.sharepoint.com`) diff --git a/docs/system-admin-guide/manage-work-packages/work-package-settings/README.md b/docs/system-admin-guide/manage-work-packages/work-package-settings/README.md index 7532d50c39c4..5de0dfea780a 100644 --- a/docs/system-admin-guide/manage-work-packages/work-package-settings/README.md +++ b/docs/system-admin-guide/manage-work-packages/work-package-settings/README.md @@ -3,7 +3,7 @@ sidebar_navigation: title: Settings priority: 999 description: Work package settings in OpenProject. -keywords: work package settings, workpackage configuration +keywords: work package settings, work package configuration --- # Work package settings diff --git a/docs/system-admin-guide/system-settings/languages/README.md b/docs/system-admin-guide/system-settings/languages/README.md index baca096d93d8..7a7122956651 100644 --- a/docs/system-admin-guide/system-settings/languages/README.md +++ b/docs/system-admin-guide/system-settings/languages/README.md @@ -7,7 +7,7 @@ keywords: languages --- # Languages -The Languages page lets you select languages you would like to activate from the list of those that are available. These langauges are then available to individual users via their user settings and as the default language for the instance. +The Languages page lets you select languages you would like to activate from the list of those that are available. These languages are then available to individual users via their user settings and as the default language for the instance. ![System Languages](openproject-system-languages.png) diff --git a/docs/system-admin-guide/users-permissions/placeholder-users/README.md b/docs/system-admin-guide/users-permissions/placeholder-users/README.md index 36bc4d6452ed..c9ea51f09c5e 100644 --- a/docs/system-admin-guide/users-permissions/placeholder-users/README.md +++ b/docs/system-admin-guide/users-permissions/placeholder-users/README.md @@ -66,7 +66,7 @@ You can change a placeholder user's name and add it to a project if you click on On the **General** tab you can change the placeholder user's name. In order to be assigned to work packages and participate in a project, a placeholder user has to be a member of a project and needs to be added with a certain role to this project. -On the **Projects** tab, select a project from the drop-down list, choose the [**role(s)**](../roles-permissions) for the placeholder user in this project and click the blue **Add** button. +On the **Projects** tab, select a project from the drop-down list, choose the [role(s)](../roles-permissions) for the placeholder user in this project and click the blue **Add** button. ![add-placeholder-user-to-project](openproject-system-guide-ph-user-new-project.png) diff --git a/docs/system-admin-guide/users-permissions/roles-permissions/README.md b/docs/system-admin-guide/users-permissions/roles-permissions/README.md index 57cc3f8051fa..e13132f091b3 100644 --- a/docs/system-admin-guide/users-permissions/roles-permissions/README.md +++ b/docs/system-admin-guide/users-permissions/roles-permissions/README.md @@ -28,7 +28,7 @@ A user can have one or more roles which grant permissions on different levels. | Scope of the role | Permission examples | Customization options | | ------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ | -| Application-level: Full control of all aspects of the application | - Assign administration privileges to other users
- Create and restore backups in the web interface
- Create and configure an OAuth app
- Configure custom fields
- Archive projects/restore projects
- Configure global roles
- Configure project roles | Cannot be changed | +| Application-level: Full control of all aspects of the application | - Assign administration privileges to other users
- Create and restore backups in the web interface
- Create and configure an OAuth app
- Configure custom fields
- Archive projects/restore projects
- Configure global roles
- Configure project roles | Cannot be changed | ### Global role @@ -36,21 +36,21 @@ A user can have one or more roles which grant permissions on different levels. | Scope of the role | Permission examples | Customization options | | ------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ | -| Application-level: Permissions scoped to specific administrative tasks (not restricted to specific projects) | - Manage users
- Create projects | Administrators can create new global roles and assign global permissions to those role | +| Application-level: Permissions scoped to specific administrative tasks (not restricted to specific projects) | - Manage users
- Create projects | Administrators can create new global roles and assign global permissions to those role | ### Project role -**A project role** is a set of **permissions** that can be assigned to any project member. Multiple roles can be assigned to the same project member.
+**A project role** is a set of **permissions** that can be assigned to any project member. Multiple roles can be assigned to the same project member.
**Note:** If a module is not enabled in a project it is not shown to a user despite having a permission for it. | Scope of the role | Permission examples | Customization options | | ------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ | -| Project-level: Permissions scoped to individual projects (a user can have different roles for individual projects) | - Create work packages (in a project)
- Delete wiki pages (in a specific project) | Create different project roles with individual permission sets | +| Project-level: Permissions scoped to individual projects (a user can have different roles for individual projects) | - Create work packages (in a project)
- Delete wiki pages (in a specific project) | Create different project roles with individual permission sets | ### Non-member -**Non member** is the default role of users of your OpenProject instance who have not been added to a project. This only applies if the project has been set as **[public](../../../user-guide/projects/#set-a-project-to-public)** in the project settings.
+**Non member** is the default role of users of your OpenProject instance who have not been added to a project. This only applies if the project has been set as [public](../../../user-guide/projects/#set-a-project-to-public) in the project settings.
**Note:** The *Non-member* role cannot be deleted. @@ -62,7 +62,7 @@ A user can have one or more roles which grant permissions on different levels. ### Anonymous -OpenProject allows to share project information with **anonymous** users which are not logged in. This is helpful to communicate projects goals and activities with a public community.
+OpenProject allows to share project information with **anonymous** users which are not logged in. This is helpful to communicate projects goals and activities with a public community.
**Note**: This only applies if you disabled the need for authentication for your instance and if the project is set as **public**. The *Anonymous* role cannot be deleted. @@ -95,19 +95,19 @@ To create the new role, click on the grey *Create* button at the bottom of the p Administrators can create new global roles in *Administration* > *Users and permissions* > *Roles and permissions*. In the creation form check the box **Global role**. The form now shows the available global permissions which can be assigned to the new global role: -- **[Create projects](../../../getting-started/projects/#create-a-new-project)** +- [Create projects](../../../getting-started/projects/#create-a-new-project) > **Note:** To create a subproject for an existing project it requires also the project permission "Create subprojects". -- **[Create backups](../../backup/)** +- [Create backups](../../backup/) -- **[Create users](../../users-permissions/users/#create-users)** +- [Create users](../../users-permissions/users/#create-users) -- **[Edit users](../users/)** +- [Edit users](../users/) > **Note:** This allows the *Administrator* to delegate the administration of users to other people that should not have full control of the entire OpenProject installation (Administrator). These users can edit attributes of any users, except administrators. This means they are able to impersonate another user by changing email address to match theirs. This is a security risk and should be considered with caution. -- **[Create, edit, and delete placeholder users](../placeholder-users/)** +- [Create, edit, and delete placeholder users](../placeholder-users/) > **Note**: Users with this global permission cannot automatically see and edit all placeholder user in all projects. It is restricted to the placeholder users in projects in which the user has the respective permission to see or edit project member. diff --git a/docs/system-admin-guide/users-permissions/users/README.md b/docs/system-admin-guide/users-permissions/users/README.md index ff65a5d4cee2..a1bd818edbb0 100644 --- a/docs/system-admin-guide/users-permissions/users/README.md +++ b/docs/system-admin-guide/users-permissions/users/README.md @@ -142,19 +142,19 @@ To create a new password for a user (e.g. if he/she lost it) navigate to the **A In order to see and work in a project, a user has to be a member of a project and needs to be added with a certain role to this project. -On the **Projects** tab, select the new project from the drop-down list, choose the [**roles**](../roles-permissions) for this project and click the blue **Add** button. +On the **Projects** tab, select the new project from the drop-down list, choose the [roles](../roles-permissions) for this project and click the blue **Add** button. -![Sys-admin-add-project](Sys-admin-add-project1.gif) +![Sysadmin add project](Sys-admin-add-project1.gif) ### Add users to groups On the **Groups** tab you can see the groups the user belongs to. If a group is shown, click the group name link. -![open-projet-user-groups](system_guide_user_groups.png) +![User groups](system_guide_user_groups.png) If no groups are shown (i.e. the user does not belong to any group, yet), click the **Manage groups** link to [edit groups](../groups). -![manage-groups](system_guide_manage_groups.png) +![Manage Groups](system_guide_manage_groups.png) **Please note**: The **Groups** tab is only shown if at least one user group exists in OpenProject. @@ -164,7 +164,7 @@ In order to add a global role to a user, at least one global role needs to be [c On the **Global roles** tab, select or de-select the global role(s) for this user. Click the **Add** button. -![Openproject-user-add-global-roles](openproject_system_guide_add_global_roles.png) +![Add global roles](openproject_system_guide_add_global_roles.png) ### Notification settings diff --git a/docs/use-cases/portfolio-management/README.md b/docs/use-cases/portfolio-management/README.md index 1feb2e59f51a..fb76ea586f5a 100644 --- a/docs/use-cases/portfolio-management/README.md +++ b/docs/use-cases/portfolio-management/README.md @@ -24,7 +24,7 @@ Step 2: You will get a list of all the projects that exist in your organization. You can then sort the project list by clicking on a column heading, for example by project status. -![Openproject sort project list by status](sort_by_status.png) +![OpenProject sort project list by status](sort_by_status.png) You can add a visual component to the overview by clicking on the **Open as Gantt view** button. @@ -38,7 +38,7 @@ Step 3: You can also configure this view using the button with the three dots at You will then be led to the **System settings** of the global Administration. If you scroll down the page, you can select which columns are to be displayed in the project list in the section **Settings for project overview list** (you will need to scroll down the page). Please save your changes via the blue **Save** button, at the bottom of the page. -![OpenProject settings for project overview list](openproject_settings_for_project_overview_list.png) +![Settings for project overview list](openproject_settings_for_project_overview_list.png) If you click on **Edit query** you can adjust the project overview when using the Gantt chart option. @@ -47,13 +47,13 @@ If you click on **Edit query** you can adjust the project overview when using th ### Exporting reports For creating custom project reports you can use the export function in the work packages view. -![Openproject reports export](openproject_export.png) +![Reports export](openproject_export.png) You can export the work packages in one of the following formats. -![Openproject export options](export_options.png) +![Export options](export_options.png) To export or print a Gantt chart use the print function (**CTRL+P**) and then save it as PDF. Only information displayed in the main screen area is included. None of the designs or side or top menus are in it. Please see here [how to print a Gantt chart in OpenProject](../../user-guide/gantt-chart/#how-to-print-a-gantt-chart). diff --git a/docs/use-cases/resource-management/README.md b/docs/use-cases/resource-management/README.md index c2bd57f5584f..07d5a12144c0 100644 --- a/docs/use-cases/resource-management/README.md +++ b/docs/use-cases/resource-management/README.md @@ -30,15 +30,15 @@ Step 4: You can add any filters necessary and sort or group the work packages by ![OpenProject sort work packages by assignee](openproject_sort_by_assignee.png) -Step 5: Save your adjusted view by clicking on the **Save** icon on the left (you can name this view before saving or re-name it later). ![Save adjusted openrpoject workpage view](openproject_save_wp_adjusted_view.png) +Step 5: Save your adjusted view by clicking on the **Save** icon on the left (you can name this view before saving or re-name it later). ![Save adjusted openproject work package view](openproject_save_wp_adjusted_view.png) This view will be saved and shown under your private work package filters (you can make it public and share with other team members). -![OpenProjec work package private filter](work_package_private_filter.png) +![OpenProject work package private filter](work_package_private_filter.png) ## Adding sums to the work packages view -You can also use the sum function. Select **[⋮]** -> ***Configure view*** -> ***Display settings*** -> and check the ***Display Sums*** box: +You can also use the sum function. Select **\[⋮\]** -> ***Configure view*** -> ***Display settings*** -> and check the ***Display Sums*** box: ![OpenProject work package configure view](openproject_configure_view.png) diff --git a/docs/use-cases/safe-framework/README.md b/docs/use-cases/safe-framework/README.md index 39750435c7d1..2478003c4bb5 100644 --- a/docs/use-cases/safe-framework/README.md +++ b/docs/use-cases/safe-framework/README.md @@ -9,7 +9,7 @@ keywords: safe, scaled agile, release train, program increment, ART backlog, roa # Implementing Scaled Agile Framework (SAFe) in OpenProject -OpenProject is a powerful project management tool that can adapt to a number of different frameworks and methodologies. Larger organisations who choose to implement the **Scaled Agile Framework (SAFe)** methodology can leverage the wide range of features and customisability that OpenProject offers to define, plan organise to deliver value to their end customers. +OpenProject is a powerful project management tool that can adapt to a number of different frameworks and methodologies. Larger organizations who choose to implement the **Scaled Agile Framework (SAFe)** methodology can leverage the wide range of features and customizability that OpenProject offers to define, plan organize to deliver value to their end customers. This guide contains the following sections: @@ -19,8 +19,8 @@ This guide contains the following sections: | [Setting up Agile Release Trains](#setting-up-agile-release-trains) | Configuring projects and using project templates to create and administer Agile Release Trains | | [Using versions to set Program Increments](#using-versions-to-set-program-increments) | Using versions in OpenProject to define Program Increments (PIs) and Iterations | | [Working with epics, features and stories](#working-with-epics-features-and-stories) | Configuring and using work packages for Epics, Capabilities, Enablers, Features and User Stories | -| [Organising work using table view, Gantt view](#organising-work-using-table-view-gantt-view) | Using table and Gantt views to visualise, sort, filter and group work packages and save custom views at all levels (agile team, Agile Release Train or Solution Train) | -| [Backlogs, Kanban and Team planner](#backlogs-kanban-and-team-planner) | Organising work and facilitating planning using Backlogs, Kanban boards and Team planner | +| [Organizing work using table view, Gantt view](#organizing-work-using-table-view-gantt-view) | Using table and Gantt views to visualize, sort, filter and group work packages and save custom views at all levels (agile team, Agile Release Train or Solution Train) | +| [Backlogs, Kanban and Team planner](#backlogs-kanban-and-team-planner) | Organizing work and facilitating planning using Backlogs, Kanban boards and Team planner | @@ -65,7 +65,7 @@ A project consists of a number of different elements: Different [members groups](../../system-admin-guide/users-permissions/groups/) can also be created at an instance level and entire groups added to projects as members. -To learn how to use the Work packages module to configure epics, features and user stories, see: [Organising work using table view, Gantt view](#organising-work-using-table-view-gantt-view) +To learn how to use the Work packages module to configure epics, features and user stories, see: [Organizing work using table view, Gantt view](#organizing-work-using-table-view-gantt-view) > **Demo:** View an [overview of an ART set up as a project](https://safe.openproject.com/projects/art-2-design/work_packages?query_id=58). @@ -73,17 +73,17 @@ To learn how to use the Work packages module to configure epics, features and us You can also use [project templates](../../user-guide/projects/project-templates/) and to make it easier to create news ARTs with the same structure, set of enabled modules, project structure or work package templates. Once a new ART is created using a template, it can then be modified in any way. -**Agile teams** *within* an Agile Release Train (ART) can either be organised as sub-projects of an ART or simply as saved custom views in a Team planner or Assignee-based Kanban board. To learn more, read [Backlogs, Kanban and Team planner](#backlogs-kanban-and-team-planner) below. +**Agile teams** *within* an Agile Release Train (ART) can either be organized as sub-projects of an ART or simply as saved custom views in a Team planner or Assignee-based Kanban board. To learn more, read [Backlogs, Kanban and Team planner](#backlogs-kanban-and-team-planner) below. ### Solution Trains -Project portfolios allow you to view, organise, sort and filter through all projects and their hierarchies. Since individual projects represent Agile Release trains, project porfolios can be used to access information at a **Solution train**-level. +Project portfolios allow you to view, organize, sort and filter through all projects and their hierarchies. Since individual projects represent Agile Release trains, project portfolios can be used to access information at a **Solution train**-level. ![All Features and User Stories across all teams](all_features_across_all_teams.png) > In a near future release, OpenProject will have dedicated project portfolio features. [View mockups.](https://www.figma.com/file/YCCMdJWkrtP9YSmf49Od0i/Project-lists?type=design&node-id=470%3A13037&mode=design&t=g1EZesuy0Jj0VZFD-1) > -> For the moment, **[global modules](../../user-guide/home/global-modules/)** give you an overview of content from all projects, including the ability to view and filter though a **project list**, and view, sort and filter **work packages at a global level**. +> For the moment, [global modules](../../user-guide/home/global-modules/) give you an overview of content from all projects, including the ability to view and filter though a **project list**, and view, sort and filter **work packages at a global level**. > **Demo:** [Solution train (project list)](https://safe.openproject.com/projects) > @@ -177,7 +177,7 @@ Progress can be viewed at a team label, at an ART-level or at a solution train l > **Demo:** [Progress overview at a PI level](https://safe.openproject.com/projects/safe-demo/work_packages?query_id=78) -## Organising work using table view, Gantt view +## Organizing work using table view, Gantt view OpenProject is a powerful tool that allows you to view work packages in a variety of different ways. @@ -187,17 +187,17 @@ The work package table view lets you view and edit work packages of all types (E ![Work package table view](work_package_table_view.png) -These tables are highly customisable and can be [configured](../../user-guide/work-packages/work-package-table-configuration/) to show precisely the information you need. Tables can also be **sorted** (for example by id, name, start dates, project, assignee, priority), **grouped** and **filtered** to create highly precise views. They can also show nested parent-children relations in **hierarchy view**. +These tables are highly customizable and can be [configured](../../user-guide/work-packages/work-package-table-configuration/) to show precisely the information you need. Tables can also be **sorted** (for example by id, name, start dates, project, assignee, priority), **grouped** and **filtered** to create highly precise views. They can also show nested parent-children relations in **hierarchy view**. > **Demo**: [A table view of all epics, features and stories in an ART](https://safe.openproject.com/projects/art-0-test-release-train/work_packages?query_id=29) Configured tables can be saved as private (for you only) or public views (for all project members) to easily access them later and share them with other team members. -Additionally, the [**Baseline** **comparison**](../../user-guide/work-packages/baseline-comparison/) feature allow lets you visualise changes to a table (in relation to the filter criteria) over a period of time, affording you yet another way to monitor progress and changes within your ART or agile team. +Additionally, the [Baseline comparison](../../user-guide/work-packages/baseline-comparison/) feature allow lets you visualize changes to a table (in relation to the filter criteria) over a period of time, affording you yet another way to monitor progress and changes within your ART or agile team. ### Gantt view -The **[Gantt chart](../../user-guide/gantt-chart/)** module allows you to quickly visualise planning at any level (Solution, ART or agile team) in a calendar view that also displays [work package relations](../../user-guide/work-packages/work-package-relations-hierarchies/). Like table view, it can be filtered to create custom views that can be saved. +The [Gantt chart](../../user-guide/gantt-chart/) module allows you to quickly visualize planning at any level (Solution, ART or agile team) in a calendar view that also displays [work package relations](../../user-guide/work-packages/work-package-relations-hierarchies/). Like table view, it can be filtered to create custom views that can be saved. ![Gantt view of one sprint in one ART](Gantt_view.png) @@ -210,7 +210,7 @@ The **Backlog** and **Kanban** are key tools in a scaled agile environment, not ### Backlog -The [**Backlog module**](../../user-guide/backlogs-scrum/work-with-backlogs/) displays all versions available to a particular project or ART in a two-column format. For each version (representing a Product increment, Iteration or a Feature or Story backlog), the module displays: +The [Backlog module](../../user-guide/backlogs-scrum/work-with-backlogs/) displays all versions available to a particular project or ART in a two-column format. For each version (representing a Product increment, Iteration or a Feature or Story backlog), the module displays: - Version name - Start and end dates @@ -218,17 +218,17 @@ The [**Backlog module**](../../user-guide/backlogs-scrum/work-with-backlogs/) di It also displays the *id*, *name*, *status* and *story points* for each work package contained in a version. -![Backlock view of one ART](Backlogs.png) +![Backlog view of one ART](Backlogs.png) -We recommend organising all relevant sprints on the left column and the backlog on the right column. Any epic, feature, story, enabler or capability can easier be dragged and dropped between versions or to and from the backlog. +We recommend organizing all relevant sprints on the left column and the backlog on the right column. Any epic, feature, story, enabler or capability can easier be dragged and dropped between versions or to and from the backlog. > **Demo**: [Backlog of an ART showing planned Sprints and a feature backlog](https://safe.openproject.com/projects/art-0-test-release-train/backlogs) ### Kanban -[**Kanban boards**](../../user-guide/agile-boards/) allow you to clearly visualise work items in a number of different ways. In OpenProject, dynamic boards can easily be created for a number of different fields. +[Kanban boards](../../user-guide/agile-boards/) allow you to clearly visualize work items in a number of different ways. In OpenProject, dynamic boards can easily be created for a number of different fields. -![Kanban board of one ART organised by status](Kanban_status.png) +![Kanban board of one ART organized by status](Kanban_status.png) For each ART, we recommend creating these dynamic Kanban boards: @@ -242,7 +242,7 @@ OpenProject boards are powerful and can be filtered for more control over what i ### Team planner -The [**Team planner module**](../../user-guide/team-planner/) allows you to visualise work packages assigned to particular team members in a week or two-week calendar view. It is a powerful tool to monitor work at a day-to-day level. +The [Team planner module](../../user-guide/team-planner/) allows you to visualize work packages assigned to particular team members in a week or two-week calendar view. It is a powerful tool to monitor work at a day-to-day level. ![Team planner view configured for one agile team](teamPlanner.png) @@ -254,6 +254,6 @@ At a Solution train level, it also allows you to view the work of members across ## Here for you -OpenProject is a powerful and highly-configurable tool that can be customised to fit the needs of your particular scaled agile implementation. Beyond the basics covered in this guide, OpenProject has many additional features and modules (such as [budgets](https://www.openproject.org/docs/user-guide/budgets/), [time and cost tracking](https://www.openproject.org/docs/user-guide/time-and-costs/), [wiki](https://www.openproject.org/docs/user-guide/wiki/), [meetings](https://www.openproject.org/docs/user-guide/meetings/) and [file storage integrations](https://www.openproject.org/docs/development/file-storage-integration/)) that further enable your agile teams to work efficiently and deliver value. +OpenProject is a powerful and highly-configurable tool that can be customized to fit the needs of your particular scaled agile implementation. Beyond the basics covered in this guide, OpenProject has many additional features and modules (such as [budgets](https://www.openproject.org/docs/user-guide/budgets/), [time and cost tracking](https://www.openproject.org/docs/user-guide/time-and-costs/), [wiki](https://www.openproject.org/docs/user-guide/wiki/), [meetings](https://www.openproject.org/docs/user-guide/meetings/) and [file storage integrations](https://www.openproject.org/docs/development/file-storage-integration/)) that further enable your agile teams to work efficiently and deliver value. If you have questions about how to [use](../../getting-started/) and [configure](../../system-admin-guide/) OpenProject to work for you, please [get in touch](https://www.openproject.org/contact/) or [start a free trial](https://start.openproject.com/) to see for yourself. diff --git a/docs/user-guide/agile-boards/README.md b/docs/user-guide/agile-boards/README.md index 40f248200aa3..b7c4d85110e1 100644 --- a/docs/user-guide/agile-boards/README.md +++ b/docs/user-guide/agile-boards/README.md @@ -68,7 +68,7 @@ Each list represents a status. That means that e.g. all work packages with the s When creating a new Status board a list with all work packages in the default status (usually this is the status "New") will be added automatically, while additional lists need to be added manually. Please note: You can't move work packages from or to every status. Please find out more about the work-flow logics restricting this here: [Allowed transitions between status](../../system-admin-guide/manage-work-packages/work-package-workflows/) -![creat status board](create-status-board.png) +![create status board](create-status-board.png) ### Assignee board Every list represents one assignee. You can choose regular users, [placeholder users](../../system-admin-guide/users-permissions/placeholder-users) and groups as assignees. When you move a card from one list to another, the assigned user is changed to the user that is selected for the list you moved the card to. @@ -158,7 +158,7 @@ A **double click on a card** will open the work package's **fullscreen view.** T ![back-to-boards-view-button](back-to-boards-view-button.png) -Clicking on **Open details view** (the blue "**i**") will open the work package's **[split screen view](../work-packages/work-package-views/#split-screen-view)**. You can close it by clicking on the **"x"** in its upper right corner. +Clicking on **Open details view** (the blue "**i**") will open the work package's [split screen view](../work-packages/work-package-views/#split-screen-view). You can close it by clicking on the **"x"** in its upper right corner. ![Close split screen button](close-split-screen.png) diff --git a/docs/user-guide/calendar/README.md b/docs/user-guide/calendar/README.md index 4a325a889dc0..3489d73ae41a 100644 --- a/docs/user-guide/calendar/README.md +++ b/docs/user-guide/calendar/README.md @@ -30,7 +30,7 @@ Once enabled, clicking on the **Calendars** entry on the left sidebar takes you - Click on an existing (saved) calendar to view it. -- You can change the visibility settings of any calendar by clicking on **[⋮] (more)** -> **Visibility settings.** +- You can change the visibility settings of any calendar by clicking on **\[⋮\] (more)** -> **Visibility settings.** - Any calendar that has the **Favored** option checked will be displayed under the **Favorite** heading in the sidebar to the left. @@ -77,7 +77,7 @@ You can make basic date modifications simply by manipulating the work package st ![Use drag handles to change start and finish dates](Calendar-dragHandle-modifyDate.png) -> **Note**: The calendar will highlight non-working days with a darker background colour. By default, a work package cannot be dragged or resized such that it begins or ends on these days unless the “Working days only” switch is turned off for that work package. To learn how to do this, refer to the documentation on [Working days and duration](../work-packages/set-change-dates/#working-days-and-duration). +> **Note**: The calendar will highlight non-working days with a darker background color. By default, a work package cannot be dragged or resized such that it begins or ends on these days unless the “Working days only” switch is turned off for that work package. To learn how to do this, refer to the documentation on [Working days and duration](../work-packages/set-change-dates/#working-days-and-duration). > > Work packages can also expand and retract in width depending on how many non-working days are spanned. For example, a 3-day task starting on Thursday and ending on Monday will spread across 5 calendar days. Dragging that same work package so that it starts on a Tuesday and ends on a Thursday means that it will spread across 3 calendar days. In both cases, the duration remains 3 days. @@ -115,7 +115,7 @@ This makes it possible for you to keep an eye on your project schedule from any To subscribe to a calendar: -1. Click on the **[⋮]** **(more) button** on the toolbar and select **Subscribe to calendar**. +1. Click on the **\[⋮\] (more) button** on the toolbar and select **Subscribe to calendar**. 2. In the modal that appears, give this calendar a unique name (you can only use it once). We recommend naming it based on where you will be subscribing to this calendar from ("personal phone" or "work tablet" for example). 3. Click on **Copy URL**. This creates the a [calendar token](../../getting-started/my-account/#access-tokens) and copies the calendar URL to your clipboard. 4. Paste this URL in your desired calendar client to subscribe. diff --git a/docs/user-guide/calendar/calendar-faq/README.md b/docs/user-guide/calendar/calendar-faq/README.md index eecce90bd220..810623f8f43f 100644 --- a/docs/user-guide/calendar/calendar-faq/README.md +++ b/docs/user-guide/calendar/calendar-faq/README.md @@ -28,4 +28,4 @@ Since the [12.3 release](https://www.openproject.org/docs/release-notes/12/12-3- ## Is there a limit for the number of work packages displayed in the calendar? -The limit is 100 and can't be changed at the moment. Find the respective feature request [here](https://community.openproject.com/wp/35062). +The limit is 100 and can't be changed at the moment. Find the respective feature request [here](https://community.openproject.org/wp/35062). diff --git a/docs/user-guide/file-management/nextcloud-integration/README.md b/docs/user-guide/file-management/nextcloud-integration/README.md index 41423c16ed86..29c0770f89da 100644 --- a/docs/user-guide/file-management/nextcloud-integration/README.md +++ b/docs/user-guide/file-management/nextcloud-integration/README.md @@ -8,27 +8,37 @@ keywords: integration, apps, Nextcloud, user # Nextcloud integration -You can use [Nextcloud](https://nextcloud.com/) as an integrated file storage in OpenProject. +You can use [Nextcloud](https://nextcloud.com) as an integrated file storage in OpenProject. This integration makes it possible for you to: - Link files and folders stored in Nextcloud with work packages in OpenProject - View, open and download files and folders linked to a work package via the **Files** tab - View all work packages linked to a file +- Create work packages directly in Nextcloud + +Additionally you can: + - View OpenProject notifications via the Nextcloud dashboard +- Pick and preview links to work packages in Nextcloud +- Search for work packages using Nextcloud's search bar + It is also possible to automatically create dedicated [project folders](../../projects/project-settings/file-storages/#project-folders), which makes documentation structure clearer and makes navigation more intuitive. -> **Important note**: To be able to use Nextcloud as a file storage in your project, the administrator of your instance should first have completed the [Nextcloud integration setup](../../../system-admin-guide/integrations/nextcloud). Then a project administrator can activate Nextcloud in the [**File storages**](../../projects/project-settings/file-storages/) for a project. +> **Important note**: To be able to use Nextcloud as a file storage in your project, the administrator of your instance should first have completed the [Nextcloud integration setup](../../../system-admin-guide/integrations/nextcloud). Then a project administrator can activate Nextcloud in the [File storages](../../projects/project-settings/file-storages/) for a project. -| Topic | Description | -| ------------------------------------------------------------ | :----------------------------------------------------------- | +| Topic | Description | +|-----------------------------------------------------------------------------------------------------|:------------------------------------------------------------------------------------------| | [Connect your OpenProject and Nextcloud accounts](#connect-your-openproject-and-nextcloud-accounts) | How to connect your Nextcloud and OpenProject accounts to be able to use this integration | -| [Link files and folders to work packages](#link-files-and-folders-to-work-packages) | How to link files and folders to work packages and view and download linked files | -| [Unlink files and folders](#remove-links) | How to remove the link between a work package and a Nextcloud file or folder | -| [Permissions and access control](#permissions-and-access-control) | Who has access to linked files and who doesn't | -| [Possible errors and troubleshooting](#possible-errors-and-troubleshooting) | Common errors and how to troubleshoot them | +| [Link files and folders to work packages](#link-files-and-folders-to-work-packages) | How to link files and folders to work packages and view and download linked files | +| [Unlink files and folders](#remove-links) | How to remove the link between a work package and a Nextcloud file or folder | +| [Nextcloud dashboard](#nextcloud-dashboard) | How to keep an eye on your OpenProject notifications | +| [Navigation and search in Nextcloud](#navigation-and-search-in-nextcloud) | How to search OpenProject work packages via the universal search bar | +| [Work package link preview in Nextcloud](#work-package-link-preview-in-nextcloud) | How to use the smart picker and see previews of work packages in text fields | +| [Permissions and access control](#permissions-and-access-control) | Who has access to linked files and who doesn't | +| [Possible errors and troubleshooting](#possible-errors-and-troubleshooting) | Common errors and how to troubleshoot them | ## Connect your OpenProject and Nextcloud accounts @@ -123,8 +133,6 @@ Respectively in order to download a file, hover over the **Download** icon in t If you click the **Folder** icon, the Nextcloud folder containing this file will open in a separate tab. - - ### In Nextcloud This video will give you an overview how to link files and folder from Nextcloud to OpenProject (English only). @@ -149,6 +157,24 @@ This linked file will then appear underneath the search bar. Doing so will also ![Show linked work packages in Nextcloud](NC_1_00-FileWPRelation.png) +#### Link multiple files to a work packages + +You can also **link multiple files** to a single OpenProject work package. To do that, select the files you want to link, click the *Actions* menu and select the respective option. +![Select multiple files in Nextcloud to link to a single work package in OpenProject](nc_select_multiple_files.png) + +A dialogue will open, allowing you to search for and then select an OpenProject work package to add all of the files to. The newly added files will become visible under the **Files** tab in the work package. + +![Select an OpenProject work package in Nextcloud](nc_select_wp_to_link.png) + +#### Create a new work package + +You can create a new OpenProject work package directly from Nextcloud file storage. To do this, select the file you want to link, choose the **OpenProject** tab and click on **+ Create and link a work package**. +![Create a new OpenProject work package from Nextcloud](nc_create_new_wp.png) + +A pop-up dialogue will open allowing you to specify the project, work package name and further details. Once you click **Create**, the new work package will be created in the specified project and the file will be linked to it. + +![Specify details of a new OpenProject work package created in Nextcloud](nc-new-work-package-created.png) + #### Remove links Once a work package is linked to a file, you can always unlink it by clicking on the **unlink** icon. @@ -229,7 +255,7 @@ If you see the words "No Nextcloud connection" in the Files tab in OpenProject, In rare occasions, it is possible for the integration to not be able to fetch all the details of all linked files. A simple page refresh should solve the issue. Should the error persist, please contact administrator of your OpenProject and Nextcloud instances. -![OpenProject file fatching error](1_0_03-Fetching_error.png) +![OpenProject file fetching error](1_0_03-Fetching_error.png) ### Project notifications are not displayed in Nextcloud diff --git a/docs/user-guide/file-management/nextcloud-integration/nc-new-work-package-created.png b/docs/user-guide/file-management/nextcloud-integration/nc-new-work-package-created.png new file mode 100644 index 000000000000..062391e426ef Binary files /dev/null and b/docs/user-guide/file-management/nextcloud-integration/nc-new-work-package-created.png differ diff --git a/docs/user-guide/file-management/nextcloud-integration/nc_create_new_wp.png b/docs/user-guide/file-management/nextcloud-integration/nc_create_new_wp.png new file mode 100644 index 000000000000..a189c134f9a2 Binary files /dev/null and b/docs/user-guide/file-management/nextcloud-integration/nc_create_new_wp.png differ diff --git a/docs/user-guide/file-management/nextcloud-integration/nc_select_multiple_files.png b/docs/user-guide/file-management/nextcloud-integration/nc_select_multiple_files.png new file mode 100644 index 000000000000..f17bedc2f6d2 Binary files /dev/null and b/docs/user-guide/file-management/nextcloud-integration/nc_select_multiple_files.png differ diff --git a/docs/user-guide/file-management/nextcloud-integration/nc_select_wp_to_link.png b/docs/user-guide/file-management/nextcloud-integration/nc_select_wp_to_link.png new file mode 100644 index 000000000000..d388e701ee9c Binary files /dev/null and b/docs/user-guide/file-management/nextcloud-integration/nc_select_wp_to_link.png differ diff --git a/docs/user-guide/file-management/one-drive-integration/README.md b/docs/user-guide/file-management/one-drive-integration/README.md index e1d0e7b98e44..cbc9132ca19b 100644 --- a/docs/user-guide/file-management/one-drive-integration/README.md +++ b/docs/user-guide/file-management/one-drive-integration/README.md @@ -17,7 +17,7 @@ This integration makes it possible for you to: - Link files and folders stored in OneDrive/SharePoint with work packages in OpenProject - View, open and download files and folders linked to a work package via the **Files** tab -> **Important note**: To be able to use OneDrive/SharePoint as a file storage in your project, the administrator of your instance should first have completed the [OneDrive/SharePoint integration setup](../../../system-admin-guide/integrations/one-drive). Then a project administrator can activate the integrated storage in the [**File storages**](../../projects/project-settings/file-storages/) for a project. +> **Important note**: To be able to use OneDrive/SharePoint as a file storage in your project, the administrator of your instance should first have completed the [OneDrive/SharePoint integration setup](../../../system-admin-guide/integrations/one-drive). Then a project administrator can activate the integrated storage in the [File storages](../../projects/project-settings/file-storages/) for a project. | Topic | Description | | ------------------------------------------------------------ | :----------------------------------------------------------- | diff --git a/docs/user-guide/gantt-chart/README.md b/docs/user-guide/gantt-chart/README.md index ef1c03b84500..83f8e753c291 100644 --- a/docs/user-guide/gantt-chart/README.md +++ b/docs/user-guide/gantt-chart/README.md @@ -3,7 +3,7 @@ sidebar_navigation: title: Gantt charts priority: 865 description: Create project timelines with Gantt charts in OpenProject -keywords: gantt chart, timeline, project plan, gantchart +keywords: gantt chart, timeline, project plan --- # Gantt charts @@ -41,7 +41,7 @@ Once you have selected the Gantt chart view, you can use the quick context menu. > **Note**: if you use the [work packages view](../work-packages/edit-work-package#update-a-work-package-in-a-work-package-table-view), the options in the quick context menu will differ slightly from the ones in the Gantt chart view. -![Quick context menu in OpenProjedt Gantt chart work packages view](gantt-context-menu.png) +![Quick context menu in OpenProject Gantt chart work packages view](gantt-context-menu.png) You can use any of the following options. @@ -72,7 +72,7 @@ To **change the order of an item** in the Gantt chart, click the **drag and drop To change the duration of a work package in the Gantt chart view, hover over the work package in the Gantt chart and use the little arrows on its ends to adjust the start date or finish date. This will shorten or prolong its duration. To move a work package on the time line just click on it and drag and drop it to the desired point of time. This will change its start and finish date. -> **Note**: The Gantt chart will highlight non-working days with a darker background colour when you are zoomed in to a level that shows individual days. By default, a work package cannot be dragged or resized such that it begins or ends on these days unless the "Working days only" switch is turned off for that work package. To learn how to do this, refer to the documentation on [Working days and duration](../work-packages/set-change-dates/#working-days-and-duration). +> **Note**: The Gantt chart will highlight non-working days with a darker background color when you are zoomed in to a level that shows individual days. By default, a work package cannot be dragged or resized such that it begins or ends on these days unless the "Working days only" switch is turned off for that work package. To learn how to do this, refer to the documentation on [Working days and duration](../work-packages/set-change-dates/#working-days-and-duration). > > Work packages can also expand and retract in width depending on how many non-working days are spanned (for example, a 3-day task starting on Thursday and ending on Monday will spread across 5 calendar days; dragging that same work package so that it starts on a Tuesday and ends on a Thursday means that it will spread across 3 calendar days. In both cases, the duration remains 3 days. @@ -80,14 +80,16 @@ To change the duration of a work package in the Gantt chart view, hover over the You can track dependencies of work packages (e.g. phases, milestones, tasks) in the Gantt chart. This way, you can get an easy overview of what needs to be done in which order, e.g. what tasks need to be completed to achieve a milestone. -To add a dependency, right-click on an element in the Gantt chart. +To add a dependency, right-click on an element in the Gantt chart, which will open a quick context menu. In the menu, choose **Add predecessor** or **Add follower**. Select the item to which you want to create a dependency. The precede and follow relation is marked with a small blue line in the Gantt chart. +The quickest way to remove a relation is to select **Show relations** from the quick context menu and removing the relation in the work package details view. -![dependencies-gantt-chart](dependencies-gantt-chart-1566556144225.gif) + +![dependencies-gantt-chart](gantt-chart.gif) When work packages have a precedes/follows relationship: diff --git a/docs/user-guide/gantt-chart/gantt-chart-faq/README.md b/docs/user-guide/gantt-chart/gantt-chart-faq/README.md index 61df1143e3d8..7383589fc5ba 100644 --- a/docs/user-guide/gantt-chart/gantt-chart-faq/README.md +++ b/docs/user-guide/gantt-chart/gantt-chart-faq/README.md @@ -14,12 +14,12 @@ Make sure that you remove the relations of the milestone to other work packages. ## When I am working in the Gantt chart, every change seems to take quite long. -We understand that the loading time when working in Gantt Chart is too long for you. The reason for this is that every single action is saved. So everything is fine with your installation. We have already taken up the point with us and already have first ideas for a technical solution. The respective feature request can be found [here](https://community.openproject.com/wp/34176). +We understand that the loading time when working in Gantt Chart is too long for you. The reason for this is that every single action is saved. So everything is fine with your installation. We have already taken up the point with us and already have first ideas for a technical solution. The respective feature request can be found [here](https://community.openproject.org/wp/34176). ## Can I export the Gantt? At the moment that's not possible, but you can use the print feature of your browser to print it as PDF (we optimized this for Google Chrome). Please find out more [here](../#how-to-print-a-gantt-chart). -The respective feature request can be found [here](https://community.openproject.com/wp/15444). +The respective feature request can be found [here](https://community.openproject.org/wp/15444). ## How can I build in a "buffer" (e.g. two weeks gap) between two consecutive work packages, so that even if the first one is postponed the second one always starts e.g. two weeks later? diff --git a/docs/user-guide/gantt-chart/gantt-chart.gif b/docs/user-guide/gantt-chart/gantt-chart.gif new file mode 100644 index 000000000000..2d194cbb4867 Binary files /dev/null and b/docs/user-guide/gantt-chart/gantt-chart.gif differ diff --git a/docs/user-guide/gantt-chart/scheduling/README.md b/docs/user-guide/gantt-chart/scheduling/README.md index 8ecbaf4c1d35..c4492753205d 100644 --- a/docs/user-guide/gantt-chart/scheduling/README.md +++ b/docs/user-guide/gantt-chart/scheduling/README.md @@ -11,7 +11,7 @@ keywords: Gantt chart, automatic scheduling, manual scheduling, start date, fini # Automatic and manual scheduling modes-To schedule work packages in the Gantt chart there is an **automatic scheduling mode (default)** and a **manual scheduling mode** (new in [release 11.0](../../../release-notes/11/11-0-0)). To add dependencies between work packages you can set them as predecessor or follower in the Gantt chart. The automatic and manual scheduling modes influence the work packages' behaviour when changing dates of other related work packages. +To schedule work packages in the Gantt chart there is an **automatic scheduling mode (default)** and a **manual scheduling mode** (new in [release 11.0](../../../release-notes/11/11-0-0)). To add dependencies between work packages you can set them as predecessor or follower in the Gantt chart. The automatic and manual scheduling modes influence the work packages' behavior when changing dates of other related work packages.As the scheduling mode only affects individual work packages you can combine manual scheduling mode (top-down planning) and automatic scheduling mode (bottom-up planning) within the same project. diff --git a/docs/user-guide/home/global-modules/README.md b/docs/user-guide/home/global-modules/README.md index 5bca15ca20e2..f433e00e0246 100644 --- a/docs/user-guide/home/global-modules/README.md +++ b/docs/user-guide/home/global-modules/README.md @@ -42,7 +42,7 @@ On the left you will have the following options: **Archived projects** will list all archived projects of which were a member or have the right to see. ->**Note:** You can also access the **Projects** global module by opening the [**Select a project** dropdown menu](https://www.openproject.org/docs/user-guide/projects/#projects-list ) and by clicking the **Projects list** button, or by clicking on the **Modules** button in the header next to the search bar and the selecting **Projects** in the menu that appears. +>**Note:** You can also access the **Projects** global module by opening the [Select a project dropdown menu](https://www.openproject.org/docs/user-guide/projects/#projects-list ) and by clicking the **Projects list** button, or by clicking on the **Modules** button in the header next to the search bar and the selecting **Projects** in the menu that appears. ## Activity @@ -60,13 +60,13 @@ You can adjust the view by using the filters on the left menu and clicking the * ## Work packages -The **Work packages** global module will show a work packages table from the projects of which you are a member or have the right to view, including public projects. You can select your **Favorite** and **Default** work package filters in the left side menu. Please note that if a view is marked as favorite it will be shown in the **Favourite** section, whether it is also saved as public or private or not. +The **Work packages** global module will show a work packages table from the projects of which you are a member or have the right to view, including public projects. You can select your **Favorite** and **Default** work package filters in the left side menu. Please note that if a view is marked as favorite it will be shown in the **Favorite** section, whether it is also saved as public or private or not. ![The Work packages global module](openproject_global_modules_work_packages.png) If you double-click to open one of the work packages in full screen view, the work package will highlight which project it belongs to at the top of the page. -![The project containing the current work package is highligted when opening it from outside the project](openproject_global_modules_work_packages_full_view.png) +![The project containing the current work package is highlighted when opening it from outside the project](openproject_global_modules_work_packages_full_view.png) ## Calendars diff --git a/docs/user-guide/keyboard-shortcuts-access-keys/README.md b/docs/user-guide/keyboard-shortcuts-access-keys/README.md index 0a825819322b..01ef67eec928 100644 --- a/docs/user-guide/keyboard-shortcuts-access-keys/README.md +++ b/docs/user-guide/keyboard-shortcuts-access-keys/README.md @@ -87,6 +87,6 @@ To quickly save changes in a rich text editor (for example a work package descri | Shortcut (Windows / Linux) | Shortcut (Mac) | Action | | -------------------------- | -------------- | ------------------------------------------------------------ | -| CTRL + ENTER | CMD + ENTER | **Save changes.**
For inline-editable fields, save the field and close it.
For pages with a full WYSIWYG (meetings, wiki pages), submit the form. | +| CTRL + ENTER | CMD + ENTER | **Save changes.**
For inline-editable fields, save the field and close it.
For pages with a full WYSIWYG (meetings, wiki pages), submit the form. | -Please also refer to documentation on [working in Rich text editor in OpenProject](../wysiwyg). \ No newline at end of file +Please also refer to documentation on [working in Rich text editor in OpenProject](../wysiwyg). diff --git a/docs/user-guide/meetings/classic-meetings/README.md b/docs/user-guide/meetings/classic-meetings/README.md index f7bd824409b3..f215533a9d0a 100644 --- a/docs/user-guide/meetings/classic-meetings/README.md +++ b/docs/user-guide/meetings/classic-meetings/README.md @@ -89,7 +89,7 @@ After creating a meeting, you can set up a **meeting agenda**. ## Create or edit meeting minutes -The **meeting minutes** are automatically created when closing the agenda in the details view of the meeting and selecting the [**Close**](#create-or-edit-the-meeting-agenda) option. +The **meeting minutes** are automatically created when closing the agenda in the details view of the meeting and selecting the [Close](#create-or-edit-the-meeting-agenda) option. The agenda is closed and copied to the meeting minutes page as a basis. You can start editing the minutes now. The same way as in the [wiki](../../wiki) pages, you can format the text, link minutes to work packages, documents and include [work package lists or other macros](../../wysiwyg/#embedding-of-work-package-attributes-and-project-attributes). diff --git a/docs/user-guide/meetings/dynamic-meetings/README.md b/docs/user-guide/meetings/dynamic-meetings/README.md index ea322a0e656d..81d98583f201 100644 --- a/docs/user-guide/meetings/dynamic-meetings/README.md +++ b/docs/user-guide/meetings/dynamic-meetings/README.md @@ -99,7 +99,7 @@ The durations of each agenda item are automatically summed up. If that sum excee There are two ways to add a work package to a meeting agenda. - **From the Meetings module**: using the **+ Add** button [add a work package agenda item](#create-or-edit-the-meeting-agenda) or -- **From a particular work package**: using the **+ Add to meeting** button on the [**Meetings** tab](../../work-packages/add-work-packages-to-meetings) +- **From a particular work package**: using the **+ Add to meeting** button on the [Meetings tab](../../work-packages/add-work-packages-to-meetings) You can add a work package to both upcoming or past meetings as long as the work package is marked **open**. diff --git a/docs/user-guide/notifications/README.md b/docs/user-guide/notifications/README.md index 51bf0ff59b17..64b295ec1114 100644 --- a/docs/user-guide/notifications/README.md +++ b/docs/user-guide/notifications/README.md @@ -56,7 +56,7 @@ You can filter or group notifications by using the two sets of predefined filter > **Info:** The **Mark all as read** button clears all _visible_ notification rows. If you have a very large number unread notifications, the oldest ones might not be visible on the page. In this case, you might have to click the button multiple times to clear your inbox completely. -(Area 4) If you would like to view your current notification preferences or modify them, click on the [**Notification settings**](./notification-settings) button. You can also access your settings via your Avatar in the top right corner > *My account* > *Notification settings*. +(Area 4) If you would like to view your current notification preferences or modify them, click on the [Notification settings](./notification-settings) button. You can also access your settings via your Avatar in the top right corner > *My account* > *Notification settings*. (Area 5) The split screen view lets you not only view work package activity as previously described, but also lets you access all other work package tabs, including overview, files, relations and watchers. diff --git a/docs/user-guide/notifications/notification-settings/README.md b/docs/user-guide/notifications/notification-settings/README.md index 1d6bbffca37c..1c8ae5964499 100644 --- a/docs/user-guide/notifications/notification-settings/README.md +++ b/docs/user-guide/notifications/notification-settings/README.md @@ -91,4 +91,4 @@ Once you do so, you will see a table with a column for that project and and the ## Email reminders -You can supplement these in-app notifications with email reminders, either at specific times of the day or immediately when someone mentions you. For more information, please read our guide on **[Email reminders](../../../getting-started/my-account#email-reminders)**. +You can supplement these in-app notifications with email reminders, either at specific times of the day or immediately when someone mentions you. For more information, please read our guide on [Email reminders](../../../getting-started/my-account#email-reminders). diff --git a/docs/user-guide/projects/README.md b/docs/user-guide/projects/README.md index 0c47c96851c7..aa50ef73ce8e 100644 --- a/docs/user-guide/projects/README.md +++ b/docs/user-guide/projects/README.md @@ -188,7 +188,7 @@ To change the order of the displayed [custom fields](../../system-admin-guide/cu To **display the work packages** of all your projects **in a Gantt chart** click on the **Open as Gantt view** icon on the upper right. This is a shortcut to quickly get to the report described in the [chapter below](#project-overarching-reports). The Gantt chart view can be configured in the [System settings](../../system-admin-guide/system-settings/project-system-settings) in the Administration. -![display all wprkpackages](display-all-workpackages.png) +![display all work packages](display-all-workpackages.png) ### Overall activity diff --git a/docs/user-guide/projects/project-settings/file-storages/README.md b/docs/user-guide/projects/project-settings/file-storages/README.md index d5e32a55ce4b..2222e7461b8a 100644 --- a/docs/user-guide/projects/project-settings/file-storages/README.md +++ b/docs/user-guide/projects/project-settings/file-storages/README.md @@ -9,12 +9,12 @@ keywords: file storages, project folder, storages > **Info**: Before a storage service can be added to a project, an administrator must first set up [Nextcloud integration](../../../../system-admin-guide/integrations/nextcloud/) or [OneDrive/SharePoint integration](../../../../system-admin-guide/integrations/one-drive/) with OpenProject. -| Topic | Description | -| ------------------------------------------------------------ | :------------------------------------------------ | -| [Activate File Storages module](#activate-file-storages-module) | Activate File Storages module in a project | -| [Add Nextcloud storage](#add-a-nextcloud-storage-to-a-project) | Add your Nextcloud storage to a project | -| [Nextcloud and project folders](#project-folders) | How to manage Nextcloud project folders | -| [Edit and delete Nextcloud storage](#edit-an-existing-nextcloud-storage) | Edit and delete an existing Nextcloud storage | +| Topic | Description | +|------------------------------------------------------------------------------------------------------------------|:--------------------------------------------------| +| [Activate File Storages module](#activate-file-storages-module) | Activate File Storages module in a project | +| [Add Nextcloud storage](#add-a-nextcloud-storage-to-a-project) | Add your Nextcloud storage to a project | +| [Nextcloud and project folders](#project-folders) | How to manage Nextcloud project folders | +| [Edit and delete Nextcloud storage](#edit-an-existing-nextcloud-storage) | Edit and delete an existing Nextcloud storage | | [Add OneDrive/SharePoint storage to a project](#add-a-onedrivesharepoint-storage-to-a-project-enterprise-add-on) | Add your OneDrive/SharePoint storage to a project | ## Activate File Storages module @@ -45,7 +45,7 @@ If you have selected the OneDrive/SharePoint option in the previous step of stor Here you can choose which kind of OneDrive/SharePoint project folder will be the default folder for file uploads for this project when using SharePoint integration. -![Select OndeDrive/SharePoint folder type in OpenProject](onedrive-storage-add-folders.png) +![Select OneDrive/SharePoint folder type in OpenProject](onedrive-storage-add-folders.png) 1. **No specific folder**: By default, each user will start at the drive root when they upload a file or select files for linking. 2. **Existing folder with manually managed permissions**: Once you selected this option, you can designate an existing folder as the project folder for this project using the button **Select folder**. The permissions are however not automatically managed, **instead the folder and its content inherits the permissions as configured in the SharePoint site or drive**. The administrator needs to manually ensure relevant users have access. The selected folder can be used by multiple projects. diff --git a/docs/user-guide/projects/projects-faq/README.md b/docs/user-guide/projects/projects-faq/README.md index cf8b5d939aeb..7476dd7431f2 100644 --- a/docs/user-guide/projects/projects-faq/README.md +++ b/docs/user-guide/projects/projects-faq/README.md @@ -34,7 +34,7 @@ In OpenProject, you can work agilely according to Scrum ([backlogs](../../backlo Versions serve a double function: On the one hand, you can use them to plan your product releases, and on the other hand, you can use them to map the product backlog(s) and sprints required for Scrum. As soon as you have created at least one version in a project, the module "[Roadmap](../../roadmap)" is displayed on the left side in your project, which you can use to get an overview of the versions (intended primarily for releases). The [Backlogs module](../../backlogs-scrum) uses versions to map the product backlog or sprints. By using the backlog, however, some special rules occur: For example, tasks must be assigned to the same version as the associated (parent) work packages. -If you do not work according to Scrum we would recommend to deactivate the Backlogs module and use the [Boards module](../../agile-boards) instead. If you have activated the boards module you can create a version board. You can find an example [here](https://community.openproject.com/projects/openproject/boards/2077). +If you do not work according to Scrum we would recommend to deactivate the Backlogs module and use the [Boards module](../../agile-boards) instead. If you have activated the boards module you can create a version board. You can find an example [here](https://community.openproject.org/projects/openproject/boards/2077). ## Can I assign work packages in subprojects to versions of the parent project? diff --git a/docs/user-guide/repository/README.md b/docs/user-guide/repository/README.md index a7005fae9262..fa91fea23ba7 100644 --- a/docs/user-guide/repository/README.md +++ b/docs/user-guide/repository/README.md @@ -43,7 +43,7 @@ For Git, we recommend the [Pro Git guide](https://git-scm.com/book/en/v2). ## Reference work packages -In the commit message you can reference a workpackage ID (e.g. #1234). In the repository settings (Administration -> System settings -> Repository) you can define keywords that change the status of the referenced work package (e.g. fixes #1234 or closes #1234). +In the commit message you can reference a work package ID (e.g. #1234). In the repository settings (Administration -> System settings -> Repository) you can define keywords that change the status of the referenced work package (e.g. fixes #1234 or closes #1234). In any textile field you can reference revisions by putting an "r" in front of the revision number (e.g. r123). @@ -56,4 +56,4 @@ Please see our system admin guide [how to configure repositories in OpenProject] ## Repository integration -See our Installation and operations guide how to [integrate repositories in Openproject](../../installation-and-operations/configuration/repositories/#repository-integration-in-openproject). +See our Installation and operations guide how to [integrate repositories in OpenProject](../../installation-and-operations/configuration/repositories/#repository-integration-in-openproject). diff --git a/docs/user-guide/roadmap/README.md b/docs/user-guide/roadmap/README.md index 2afe6fe1c332..736eb6fc1edb 100644 --- a/docs/user-guide/roadmap/README.md +++ b/docs/user-guide/roadmap/README.md @@ -28,6 +28,6 @@ Clicking the title of a version allows you to evaluate further information of th The chart displays all work packages listed by a certain attribute. Select the drop-down list to change the attribute: -![roadmap-workpackage-details](1567423371954.png) +![roadmap work package details](1567423371954.png) > **Note**: A roadmap is only displayed in the project menu when at least one [version](../projects/) exists in a project. diff --git a/docs/user-guide/team-planner/README.md b/docs/user-guide/team-planner/README.md index 90fb7380641a..4cbb91a58903 100644 --- a/docs/user-guide/team-planner/README.md +++ b/docs/user-guide/team-planner/README.md @@ -11,7 +11,7 @@ The team planner module helps you get a complete overview of what each member of ![Example team planner showing a two-week view of work packages assigned to team members](TeamPlanner-12.4-twoWeeks.png) -Essentially, the team planner is a calendar view with an assignee column on the left side. Each work package assigned to a team member will appear as a card that spans a certain duration (start date to finish date). These cards can be moved, stretched, shortened or removed to organise the planning of your team. +Essentially, the team planner is a calendar view with an assignee column on the left side. Each work package assigned to a team member will appear as a card that spans a certain duration (start date to finish date). These cards can be moved, stretched, shortened or removed to organize the planning of your team. > **Note**: Team planner is an Enterprise add-on and can only be used with [Enterprise cloud](../../enterprise-guide/enterprise-cloud-guide/) or [Enterprise on-premises](../../enterprise-guide/enterprise-on-premises-guide/). An upgrade from the free community edition is easy and helps support OpenProject. @@ -20,7 +20,7 @@ To use this module, you must have the work packages module enabled. | Topic | Content | |------------------------------------------------------------------------------|:---------------------------------------------------------------------| | [Module overview](#module-overview) | See a list of all existing team planners or create a new one | -| [Team planner basics](#team-planner-basics) | Understanding the basics of how a team planner is organised | +| [Team planner basics](#team-planner-basics) | Understanding the basics of how a team planner is organized | | [Adding team members and work packages](#add-team-members-and-work-packages) | Add team members and schedule, reschedule and reassign work packages | | [Work package detail view](#work-package-details-view) | View or edit a specific work package | | [Removing a work package](#remove-a-work-package) | Removing (unscheduling) visible work packages | @@ -54,7 +54,7 @@ A team planner has a number of features numbered 1 to 8 in the above screenshot: 4. By default, the team planner will only show assigned work packages belonging to the current project. However, it is possible to also add assigned work packages belonging to other projects. You can make these work packages from other projects visible by using **Include projects** feature and selecting additional projects to be included in this view. 5. Use the **Filter** feature (same as in the [work packages](../work-packages/work-package-table-configuration/#filter-work-packages) module) to display only work packages that meet certain filter criteria. You could, for example, filter such that only work packages of certain types, certain status or certain custom field values are visible. 6. The **Fullscreen** button lets you view the team planner in fullscreen mode. -7. The **[⋮]** (more) button gives you additional options, such as saving, renaming and saving a copy (saving as), or deleting the team planner. This is also where you can modify the visibility options. +7. The **\[⋮\]** (more) button gives you additional options, such as saving, renaming and saving a copy (saving as), or deleting the team planner. This is also where you can modify the visibility options. 8. By default the team planner only shows the [work week](../../system-admin-guide/calendars-and-dates/#working-days) (week excluding the weekend and non-working days). Use the drop down to toggle between work week, 1-week and 2-week views. With the arrows you can navigate the weeks back and forth. The Today button brings you to the current week. > **Note**: The team planner will highlight non-working days in the calendar with a darker background color. By default, a work package cannot be dragged or resized such that it begins or ends on these days unless the "Working days only" switch is turned off for that work package. To learn how to do this, refer to the documentation on [Working days and duration](../work-packages/set-change-dates/#working-days-and-duration). diff --git a/docs/user-guide/time-and-costs/time-tracking/README.md b/docs/user-guide/time-and-costs/time-tracking/README.md index 2211d3f6093d..042869a99869 100644 --- a/docs/user-guide/time-and-costs/time-tracking/README.md +++ b/docs/user-guide/time-and-costs/time-tracking/README.md @@ -74,7 +74,7 @@ If you navigate away from the work package in which you have a timer running, yo > > **Enable time logging** option must be [activated under system settings](../../../system-admin-guide/system-settings/repositories/) in order to log time via a commit message. -To log time via commit message **Repository** module must be activated and an SVN or Git repository needs to be configured. Once it is configured you can enter the following syntax into a commit message of your client (for example GitHub desktop client or a command line client) to log time: *refs #work package number @amount of hours*. For example refs #123 @2h will log 2 hours of spent timefor the work package number 123.![openproject_user_guide_log_time_commit_message](openproject_user_guide_log_time_commit_message.png) +To log time via commit message **Repository** module must be activated and an SVN or Git repository needs to be configured. Once it is configured you can enter the following syntax into a commit message of your client (for example GitHub desktop client or a command line client) to log time: *refs #work package number @amount of hours*. For example refs #123 @2h will log 2 hours of spent time for the work package number 123.![openproject_user_guide_log_time_commit_message](openproject_user_guide_log_time_commit_message.png) ## Log time via My Page diff --git a/docs/user-guide/time-and-costs/time-tracking/time-tracker-integration/README.md b/docs/user-guide/time-and-costs/time-tracking/time-tracker-integration/README.md index 44af5547d42e..9bf0a2d39599 100644 --- a/docs/user-guide/time-and-costs/time-tracking/time-tracker-integration/README.md +++ b/docs/user-guide/time-and-costs/time-tracking/time-tracker-integration/README.md @@ -39,4 +39,4 @@ Time Tracker app is available in the Apple [AppStore](https://apps.apple.com/us/ 9. Once you have completed all the fields, press the Create button. 10. After creating the application, copy the Client ID and Base URL values for future reference and keep them secure. Copy Base URL from Auth URL field, it may look like this: `https://example.com` -![openproject_timetracker_configured](openproject_timetracker_configured.png) +![openproject time tracker configured](openproject_timetracker_configured.png) diff --git a/docs/user-guide/time-and-costs/time-tracking/timecamp-integration/README.md b/docs/user-guide/time-and-costs/time-tracking/timecamp-integration/README.md index 6ed499cc01d7..538576ab5a22 100644 --- a/docs/user-guide/time-and-costs/time-tracking/timecamp-integration/README.md +++ b/docs/user-guide/time-and-costs/time-tracking/timecamp-integration/README.md @@ -40,7 +40,7 @@ This integration can be added for Google Chrome as [TimeCamp extension](https:// ![TimeCamp account with a new project which shows 2 tasks](project-with-2-tasks.png) - The time tracked in Openproject will later on appear in TimeCamp on the task that you select. + The time tracked in OpenProject will later on appear in TimeCamp on the task that you select. 3. [Log in to OpenProject](https://www.openproject.org/signin/), open a project and go to a work package. diff --git a/docs/user-guide/time-and-costs/time-tracking/toggl-integration/README.md b/docs/user-guide/time-and-costs/time-tracking/toggl-integration/README.md index ceb658b177e3..5aa3efdd4c6e 100644 --- a/docs/user-guide/time-and-costs/time-tracking/toggl-integration/README.md +++ b/docs/user-guide/time-and-costs/time-tracking/toggl-integration/README.md @@ -22,7 +22,7 @@ This integration can be added for example for Google Chrome as [Toggl Track exte On the cogwheel of the Toggl Track extension you reach the **Settings**, from there chose **Integrations**. -For OpenProject domains that are located on openproject.com, which is the case for most of the Enterprise cloud instances, you are able to chose **Openproject - openproject.com** from the list of default integrations. +For OpenProject domains that are located on openproject.com, which is the case for most of the Enterprise cloud instances, you are able to chose **OpenProject - openproject.com** from the list of default integrations. For any other OpenProject Domains you need to exactly add the **Fully Qualified Domain Name** (including subdomain) to the **Custom URLs for Integration** and chose **OpenProject**. For example: community.openproject.org (wildcards are not supported by Toggl Track at the moment of writing) @@ -34,7 +34,7 @@ For any other OpenProject Domains you need to exactly add the **Fully Qualified If this add-in is installed and the **Integration URL** is configured, a **Start/Stop Timer button** is displayed on the work package details view, which can be used to record times from OpenProject into Toggl: -![toggl-button-openproject-workpackage-detail-view](toggl-button-openproject-workpackage-detail-view.png) +![toggl button openproject work package detail view](toggl-button-openproject-workpackage-detail-view.png) diff --git a/docs/user-guide/wiki/README.md b/docs/user-guide/wiki/README.md index 93c17125febd..119a64a1792b 100644 --- a/docs/user-guide/wiki/README.md +++ b/docs/user-guide/wiki/README.md @@ -35,7 +35,7 @@ Simply type in your text in the input field, highlight a text and select the for ![openproject_user_guide_wiki](openproject_user_guide_wiki.png) -### Linebreaks +### Line breaks Instead of creating a new paragraph with Enter, you can also press SHIFT+Enter to create a line break without creating a new paragraph. diff --git a/docs/user-guide/wiki/more-wiki-functions/README.md b/docs/user-guide/wiki/more-wiki-functions/README.md index 4bb50a1be38b..93b701d436cf 100644 --- a/docs/user-guide/wiki/more-wiki-functions/README.md +++ b/docs/user-guide/wiki/more-wiki-functions/README.md @@ -57,7 +57,7 @@ Please be aware that a deleted wiki page cannot easily be restored within the sy ## Show wiki page history -In some cases, you might want to know the latest change to a wiki page. You can get information on the type of change as well as on the author using the **History** option. To display it, choose **History** in the [**More** functions](#more-wiki-functions) drop-down menu on top of a wiki page. +In some cases, you might want to know the latest change to a wiki page. You can get information on the type of change as well as on the author using the **History** option. To display it, choose **History** in the [More functions](#more-wiki-functions) drop-down menu on top of a wiki page. ![wiki-history](image-20210429102421851.png) @@ -76,4 +76,4 @@ You can choose between **Atom** or **Markdown** export of your wiki page: ![wiki-export-options](1568277748319.png) -Alternatively, you can use your browser's print feature to **print a PDF** from a wiki page. \ No newline at end of file +Alternatively, you can use your browser's print feature to **print a PDF** from a wiki page. diff --git a/docs/user-guide/wiki/wiki-faq/README.md b/docs/user-guide/wiki/wiki-faq/README.md index e0e5b08f2039..6da137fd3325 100644 --- a/docs/user-guide/wiki/wiki-faq/README.md +++ b/docs/user-guide/wiki/wiki-faq/README.md @@ -10,7 +10,7 @@ keywords: wiki faq ### Is it possible to copy a wiki or a wiki page from one project into another project? -Yes, you can do both, you have to export the wiki or the wiki page as a Markdown (or Atom), than copy the Mardown from the text editor. Now you have to create a new wiki in the project you want to copy the old one (or the page). In the section paragraph you have to change into the markdown modus, then paste the text from you have copied. Unforunally pictures cannot be copied this way. You have to add them manually. +Yes, you can do both, you have to export the wiki or the wiki page as a Markdown (or Atom), than copy the Markdown from the text editor. Now you have to create a new wiki in the project you want to copy the old one (or the page). In the section paragraph you have to change into the markdown modus, then paste the text from you have copied. Unfortunately pictures cannot be copied this way. You have to add them manually. ### Which image formats can be used to include them on a wiki page? diff --git a/docs/user-guide/work-packages/set-change-dates/README.md b/docs/user-guide/work-packages/set-change-dates/README.md index d65bd73328d0..e9dd1a114451 100644 --- a/docs/user-guide/work-packages/set-change-dates/README.md +++ b/docs/user-guide/work-packages/set-change-dates/README.md @@ -8,12 +8,12 @@ keywords: date picker start finish dates duration change modify update relations # Set and change dates and duration of work packages -| Feature | Documentation for | -| ------------------------------------------------------------ | ------------------------------------------------------------ | -| [Set start and finish dates](#set-start-and-finish-dates) | How to set start and finish dates, and how to change them | -| [Working days and duration](#working-days-and-duration) | How to set duration, and how it affects start and finish dates | -| [Scheduling mode](#scheduling-mode) | Enabling manual scheduling and what it does | -| [Information and warning ban ners](#information-and-warning-banners) | What the different warning and information banners mean | +| Feature | Documentation for | +|---------------------------------------------------------------------|----------------------------------------------------------------| +| [Set start and finish dates](#set-start-and-finish-dates) | How to set start and finish dates, and how to change them | +| [Working days and duration](#working-days-and-duration) | How to set duration, and how it affects start and finish dates | +| [Scheduling mode](#scheduling-mode) | Enabling manual scheduling and what it does | +| [Information and warning banners](#information-and-warning-banners) | What the different warning and information banners mean | ## Set start and finish dates @@ -46,7 +46,7 @@ You can also click on the **Today** link below the start and finish date fields A more intuitive way to select start and end dates is to simply click on two different dates in the mini calendars below. Two calendar months are displayed for better visibility. -Start by clicking on a start date. This will enter the selected date as the start date, mark it with a dark color on the mini calendar below and move the focus to the finish date field. Hovering on different finish dates will give you a preview of the date range for the work package if you click this second date. Once you have decided on a finish date, click on it. This will enter the finish date in the date field and mark that date with another dark color. The dates in between will be highlighted with a lighter colour. +Start by clicking on a start date. This will enter the selected date as the start date, mark it with a dark color on the mini calendar below and move the focus to the finish date field. Hovering on different finish dates will give you a preview of the date range for the work package if you click this second date. Once you have decided on a finish date, click on it. This will enter the finish date in the date field and mark that date with another dark color. The dates in between will be highlighted with a lighter color. To confirm the selected dates, click on the **Save** button. The green message on top of the work package indicates a successful update. @@ -79,7 +79,7 @@ Work packages with *only* a start date or only a finish date are automatically c Certain work package types (such as Milestones) can only span one day and thus have only one date field: -![Milestones have datpickers with a single date field](milestone-datepicker.png) +![Milestones have datepickers with a single date field](milestone-datepicker.png) @@ -95,7 +95,7 @@ Starting with OpenProject 12.3, it is possible to manually input a duration for ![The "Working days only" switch on the datepicker](working-days-only-switch.png) -The **Working days only** switch is on by default, and the date picker skips over the weekend (or the days defined as non-working days) when scheduling work packages and deriving duration. In this mode, non-working days are marked with a darker colour and are not clickable. Work packages cannot start or finish on non-working days, and these days do not count towards the calculation of duration. +The **Working days only** switch is on by default, and the date picker skips over the weekend (or the days defined as non-working days) when scheduling work packages and deriving duration. In this mode, non-working days are marked with a darker color and are not clickable. Work packages cannot start or finish on non-working days, and these days do not count towards the calculation of duration. Switching **Working days only** off will turn the previously disabled non-working days into regular working days, and make them available for scheduling. The duration will now take these days into account. diff --git a/docs/user-guide/work-packages/share-work-packages/README.md b/docs/user-guide/work-packages/share-work-packages/README.md index 6564994312c0..94f93cc02e94 100644 --- a/docs/user-guide/work-packages/share-work-packages/README.md +++ b/docs/user-guide/work-packages/share-work-packages/README.md @@ -82,7 +82,7 @@ You (with the correct permissions) can always change or remove sharing options. Users with the edit role can update most of the attributes of a shared work package (e.g. 'Subject' and 'Description') and this includes the status. A change in status is governed by the workflows configured for the role the user has. An administrator will therefore have to setup the necessary workflows once. A message at the bottom of the screen will notify administrators of this: -![Message on unconfigured work package editor workflows](openproject_user_guide_sharing_configuration_message.png) +![Message on not configured work package editor workflows](openproject_user_guide_sharing_configuration_message.png) To do so, an administrator can follow the link in the message to get to the form for copying workflows. In that form, select the source type (e.g. 'Task') and source role (e.g. 'Member') to copy the workflow from. Afterwards, select the target (e.g. 'Task') and lastly the role which will be 'Work package editor' to copy the workflow for: diff --git a/docs/user-guide/work-packages/work-package-relations-hierarchies/README.md b/docs/user-guide/work-packages/work-package-relations-hierarchies/README.md index cdb4568f18ca..68960b9f4c3e 100644 --- a/docs/user-guide/work-packages/work-package-relations-hierarchies/README.md +++ b/docs/user-guide/work-packages/work-package-relations-hierarchies/README.md @@ -94,7 +94,7 @@ Open a work package and select the tab *Relations*. Click on *+ Create new child Insert the name of the new work package and save the newly created work package by pressing *Enter*. You can make changes to the work package by clicking on the work package ID. -![create workpackage children](image-20200129144540902.png) +![create work package children](image-20200129144540902.png) For more information on the work package creation take a look at the guideline on [creating a work package](../create-work-package). diff --git a/docs/user-guide/work-packages/work-package-views/README.md b/docs/user-guide/work-packages/work-package-views/README.md index a635dd362767..9639dc4a4a04 100644 --- a/docs/user-guide/work-packages/work-package-views/README.md +++ b/docs/user-guide/work-packages/work-package-views/README.md @@ -2,7 +2,7 @@ sidebar_navigation: title: Work packages views priority: 999 -description: Different ways of organising and viewing work packages, including table, split screen, board and Gantt. +description: Different ways of organizing and viewing work packages, including table, split screen, board and Gantt. keywords: work packages views --- diff --git a/docs/user-guide/work-packages/work-packages-faq/README.md b/docs/user-guide/work-packages/work-packages-faq/README.md index f5038413b41a..88dea8a727cb 100644 --- a/docs/user-guide/work-packages/work-packages-faq/README.md +++ b/docs/user-guide/work-packages/work-packages-faq/README.md @@ -93,9 +93,9 @@ As an inherited change is always commented ("Updated automatically by...") they The "Position" attribute is provided by the Backlogs plugin and shows the position of a work package in the backlog. If you create e.g. a Feature and assign it to a sprint, the position of the feature in the sprint is shown in the "Position" attribute on the work package table. -### Can I restore a deleted workpackage? +### Can I restore a deleted work package? -There is no easy way to restore a deleted workpackage. Generally, you have the option to create and restore your own backups. +There is no easy way to restore a deleted work package. Generally, you have the option to create and restore your own backups. ## Filters and queries @@ -112,7 +112,7 @@ Tick the box next to "Public" when saving the work package view. We suggest tick This is not possible at the moment, but you can configure and save another view. -A [feature request](../../../development/submit-feature-idea/) to change this can be found [here](https://community.openproject.com/wp/31423). +A [feature request](../../../development/submit-feature-idea/) to change this can be found [here](https://community.openproject.org/wp/31423). ### I sorted my work package table and when I get back to my work package table it doesn't look the same way again. Why? @@ -126,7 +126,7 @@ There are two reasons for this: 1. Potentially, a lot of values are displayed in ### I have a parent work package with multiple children. In the work package table I don't see all of the children below the parent. Why? How can I change this? Please increase the number of displayed work packages per page [in the administration](../../../system-admin-guide/system-settings/general-settings/#general-system-settings). Then the probability of this phenomenon happening is lower. -This is a known behavior of OpenProject, but not trivial to solve. There's already a feature request for this [here](https://community.openproject.com/wp/34925). +This is a known behavior of OpenProject, but not trivial to solve. There's already a feature request for this [here](https://community.openproject.org/wp/34925). diff --git a/docs/user-guide/wysiwyg/README.md b/docs/user-guide/wysiwyg/README.md index b42f7ae7b982..61ce3afd6345 100644 --- a/docs/user-guide/wysiwyg/README.md +++ b/docs/user-guide/wysiwyg/README.md @@ -72,7 +72,7 @@ In supported resources of OpenProject where attachments are allowed, you can add The image will be automatically uploaded and stored as an attachment. You can adjust the image size in the editor using your mouse. -![resize-imagesshort](resize-imagesshort.gif) +![Resize Image](resize-imagesshort.gif) @@ -84,7 +84,7 @@ On top of that, OpenProject adds the following shortcut: | Shortcut (Windows / Linux) | Shortcut (Mac) | Action | | -------------------------- | -------------- | ------------------------------------------------------------ | -| CTRL + ENTER | CMD + ENTER | **Save changes.**
For inline-editable fields, save the field and close it.
For pages with a full WYSIWYG (meetings, wiki pages), submit the form. | +| CTRL + ENTER | CMD + ENTER | **Save changes.**
For inline-editable fields, save the field and close it.
For pages with a full WYSIWYG (meetings, wiki pages), submit the form. | ## Macros diff --git a/frontend/src/app/core/datetime/timezone.service.ts b/frontend/src/app/core/datetime/timezone.service.ts index 4b3fcb41a123..1106bce3b145 100644 --- a/frontend/src/app/core/datetime/timezone.service.ts +++ b/frontend/src/app/core/datetime/timezone.service.ts @@ -30,9 +30,7 @@ import { Injectable } from '@angular/core'; import { ConfigurationService } from 'core-app/core/config/configuration.service'; import { I18nService } from 'core-app/core/i18n/i18n.service'; import * as moment from 'moment-timezone'; -import { - Moment, -} from 'moment'; +import { Moment } from 'moment'; @Injectable({ providedIn: 'root' }) export class TimezoneService { @@ -84,9 +82,9 @@ export class TimezoneService { return this.parseDate(date, 'YYYY-MM-DD'); } - public formattedDate(date:string):string { + public formattedDate(date:string, format = this.getDateFormat()):string { const d = this.parseDate(date); - return d.format(this.getDateFormat()); + return d.format(format); } /** diff --git a/frontend/src/app/core/path-helper/apiv3-paths.ts b/frontend/src/app/core/path-helper/apiv3-paths.ts index 14db6aa4c454..8a3bf707569f 100644 --- a/frontend/src/app/core/path-helper/apiv3-paths.ts +++ b/frontend/src/app/core/path-helper/apiv3-paths.ts @@ -1,4 +1,6 @@ import { ApiV3FilterBuilder } from 'core-app/shared/helpers/api-v3/api-v3-filter-builder'; +import { WorkPackageResource } from 'core-app/features/hal/resources/work-package-resource'; +import { HalResource } from 'core-app/features/hal/resources/hal-resource'; export class ApiV3Paths { readonly apiV3Base:string; @@ -35,12 +37,18 @@ export class ApiV3Paths { * https://github.com/opf/commonmark-ckeditor-build/ * */ - public principals(workPackageId:string|number, term:string|null) { + public principals(workPackage:WorkPackageResource, term:string|null) { const filters:ApiV3FilterBuilder = new ApiV3FilterBuilder(); // Only real and activated users: filters.add('status', '!', ['3']); - // that are members of that project: - filters.add('mentionable_on_work_package', '=', [workPackageId.toString()]); + + if (!workPackage.id || workPackage.id === 'new') { + // that are members of that project: + filters.add('member', '=', [(workPackage.project as HalResource).id as string]); + } else { + // that are mentionable on the work package + filters.add('mentionable_on_work_package', '=', [workPackage.id.toString()]); + } // That are users: filters.add('type', '=', ['User', 'Group']); diff --git a/frontend/src/app/core/schemas/schema-cache.service.ts b/frontend/src/app/core/schemas/schema-cache.service.ts index eabbb5471fc9..e9c54acd5346 100644 --- a/frontend/src/app/core/schemas/schema-cache.service.ts +++ b/frontend/src/app/core/schemas/schema-cache.service.ts @@ -28,16 +28,10 @@ import { State } from '@openproject/reactivestates'; import { Injectable } from '@angular/core'; import { StateCacheService } from 'core-app/core/apiv3/cache/state-cache.service'; -import { - firstValueFrom, - Observable, -} from 'rxjs'; +import { firstValueFrom, Observable } from 'rxjs'; import { take } from 'rxjs/operators'; import { States } from 'core-app/core/states/states.service'; -import { - ISchemaProxy, - SchemaProxy, -} from 'core-app/features/hal/schemas/schema-proxy'; +import { ISchemaProxy, SchemaProxy } from 'core-app/features/hal/schemas/schema-proxy'; import { HalResourceService } from 'core-app/features/hal/services/hal-resource.service'; import { WorkPackageSchemaProxy } from 'core-app/features/hal/schemas/work-package-schema-proxy'; import { HalResource } from 'core-app/features/hal/resources/hal-resource'; @@ -71,6 +65,10 @@ export class SchemaCacheService extends StateCacheService{ of(resource:HalResource):ISchemaProxy { const schema = this.state(resource).value as SchemaResource; + return this.proxied(resource, schema); + } + + proxied(resource:HalResource, schema:SchemaResource):ISchemaProxy { if (resource._type === 'WorkPackage') { return WorkPackageSchemaProxy.create(schema, resource); } diff --git a/frontend/src/app/features/backlogs/backlogs-page/styles/taskboard.sass b/frontend/src/app/features/backlogs/backlogs-page/styles/taskboard.sass index 969f504104e5..08d9968e79a1 100644 --- a/frontend/src/app/features/backlogs/backlogs-page/styles/taskboard.sass +++ b/frontend/src/app/features/backlogs/backlogs-page/styles/taskboard.sass @@ -121,8 +121,7 @@ background-color: #F8F6A5 border: none display: block - float: left - min-height: 84px + min-height: 100px margin: 5px padding: 5px position: relative @@ -142,9 +141,8 @@ border: none cursor: move display: block - float: left font-size: 10px - height: 80px + height: 85px padding: 5px margin: 5px 0px position: relative @@ -167,7 +165,7 @@ bottom: -5px color: #FFFFFF font-size: 9px - height: 13px + height: 18px padding-left: 5px padding-right: 5px position: absolute diff --git a/frontend/src/app/features/boards/board/board-partitioned-page/board-list-container.component.ts b/frontend/src/app/features/boards/board/board-partitioned-page/board-list-container.component.ts index 6fff5bda4bc6..b45633cec452 100644 --- a/frontend/src/app/features/boards/board/board-partitioned-page/board-list-container.component.ts +++ b/frontend/src/app/features/boards/board/board-partitioned-page/board-list-container.component.ts @@ -1,5 +1,9 @@ import { Component, ElementRef, Injector, OnInit, QueryList, ViewChild, ViewChildren } from '@angular/core'; -import { Observable, Subscription } from 'rxjs'; +import { + EMPTY, + Observable, + Subscription, +} from 'rxjs'; import { QueryResource } from 'core-app/features/hal/resources/query-resource'; import { BoardListComponent } from 'core-app/features/boards/board/board-list/board-list.component'; import { StateService } from '@uirouter/core'; @@ -19,7 +23,12 @@ import { BoardPartitionedPageComponent } from 'core-app/features/boards/board/bo import { AddListModalComponent } from 'core-app/features/boards/board/add-list-modal/add-list-modal.component'; import { I18nService } from 'core-app/core/i18n/i18n.service'; import { BoardListCrossSelectionService } from 'core-app/features/boards/board/board-list/board-list-cross-selection.service'; -import { filter, tap } from 'rxjs/operators'; +import { + catchError, + filter, + finalize, + tap, +} from 'rxjs/operators'; import { BoardActionsRegistryService } from 'core-app/features/boards/board/board-actions/board-actions-registry.service'; import { ApiV3Service } from 'core-app/core/apiv3/api-v3.service'; import { WorkPackageStatesInitializationService } from 'core-app/features/work-packages/components/wp-list/wp-states-initialization.service'; @@ -159,7 +168,21 @@ export class BoardListContainerComponent extends UntilDestroyedMixin implements } saveBoard(board:Board):void { - this.boardComponent.boardSaver.request(board); + this.Boards + .save(board) + .pipe( + catchError((error) => { + this.halNotification.handleRawError(error); + return EMPTY; + }), + finalize(() => { + this.boardComponent.toolbarDisabled = false; + this.boardComponent.cdRef.detectChanges(); + }), + ).subscribe(() => { + this.toastService.addSuccess(this.text.updateSuccessful); + }, + ); } private setupQueryUpdatedMonitoring(board:Board) { diff --git a/frontend/src/app/features/boards/board/board-partitioned-page/board-partitioned-page.component.ts b/frontend/src/app/features/boards/board/board-partitioned-page/board-partitioned-page.component.ts index 5f942019a800..cc50a353861e 100644 --- a/frontend/src/app/features/boards/board/board-partitioned-page/board-partitioned-page.component.ts +++ b/frontend/src/app/features/boards/board/board-partitioned-page/board-partitioned-page.component.ts @@ -21,7 +21,12 @@ import { ZenModeButtonComponent } from 'core-app/features/work-packages/componen import { BoardsMenuButtonComponent } from 'core-app/features/boards/board/toolbar-menu/boards-menu-button.component'; import { RequestSwitchmap } from 'core-app/shared/helpers/rxjs/request-switchmap'; import { componentDestroyed } from '@w11k/ngx-componentdestroyed'; -import { finalize, take } from 'rxjs/operators'; +import { + catchError, + finalize, + take, + tap, +} from 'rxjs/operators'; import { I18nService } from 'core-app/core/i18n/i18n.service'; import { UntilDestroyedMixin } from 'core-app/shared/helpers/angular/until-destroyed.mixin'; import { QueryResource } from 'core-app/features/hal/resources/query-resource'; @@ -30,6 +35,11 @@ import { BoardFiltersService } from 'core-app/features/boards/board/board-filter import { CardViewHandlerRegistry } from 'core-app/features/work-packages/components/wp-card-view/event-handler/card-view-handler-registry'; import { ApiV3Service } from 'core-app/core/apiv3/api-v3.service'; import { OpTitleService } from 'core-app/core/html/op-title.service'; +import { + EMPTY, + Observable, + of, +} from 'rxjs'; export function boardCardViewHandlerFactory(injector:Injector) { return new CardViewHandlerRegistry(injector); @@ -111,18 +121,6 @@ export class BoardPartitionedPageComponent extends UntilDestroyedMixin { }, }; - // We remember when we want to update the board - boardSaver = new RequestSwitchmap( - (board:Board) => { - this.toolbarDisabled = true; - return this.Boards - .save(board) - .pipe( - finalize(() => (this.toolbarDisabled = false)), - ); - }, - ); - toolbarButtonComponents:ToolbarButtonComponentDefinition[] = [ { component: WorkPackageFilterButtonComponent, @@ -142,7 +140,8 @@ export class BoardPartitionedPageComponent extends UntilDestroyedMixin { }, ]; - constructor(readonly I18n:I18nService, + constructor( + readonly I18n:I18nService, readonly cdRef:ChangeDetectorRef, readonly $transitions:TransitionService, readonly state:StateService, @@ -152,7 +151,8 @@ export class BoardPartitionedPageComponent extends UntilDestroyedMixin { readonly apiV3Service:ApiV3Service, readonly boardFilters:BoardFiltersService, readonly Boards:BoardService, - readonly titleService:OpTitleService) { + readonly titleService:OpTitleService, + ) { super(); } @@ -160,15 +160,6 @@ export class BoardPartitionedPageComponent extends UntilDestroyedMixin { // Ensure board is being loaded this.Boards.loadAllBoards(); - this.boardSaver - .observe(componentDestroyed(this)) - .subscribe( - () => { - this.toastService.addSuccess(this.text.updateSuccessful); - }, - (error:unknown) => this.halNotification.handleRawError(error), - ); - this.removeTransitionSubscription = this.$transitions.onSuccess({}, (transition):any => { const toState = transition.to(); const params = transition.params('to'); @@ -216,7 +207,22 @@ export class BoardPartitionedPageComponent extends UntilDestroyedMixin { const params = { isNew: false, query_props: null }; this.state.go('.', params, { custom: { notify: false } }); - this.boardSaver.request(board); + this.toolbarDisabled = true; + this.Boards + .save(board) + .pipe( + catchError((error) => { + this.halNotification.handleRawError(error); + return EMPTY; + }), + finalize(() => { + this.toolbarDisabled = false; + this.cdRef.detectChanges(); + }), + ).subscribe(() => { + this.toastService.addSuccess(this.text.updateSuccessful); + }, + ); }); } diff --git a/frontend/src/app/features/calendar/op-work-packages-calendar.service.ts b/frontend/src/app/features/calendar/op-work-packages-calendar.service.ts index ffc68def7cd4..67c9b35811c4 100644 --- a/frontend/src/app/features/calendar/op-work-packages-calendar.service.ts +++ b/frontend/src/app/features/calendar/op-work-packages-calendar.service.ts @@ -1,7 +1,4 @@ -import { - Injectable, - Injector, -} from '@angular/core'; +import { Injectable, Injector } from '@angular/core'; import { CalendarOptions, DatesSetArg, @@ -22,11 +19,10 @@ import { splitViewRoute } from 'core-app/features/work-packages/routing/split-vi import { StateService } from '@uirouter/angular'; import { WorkPackageCollectionResource } from 'core-app/features/hal/resources/wp-collection-resource'; import { ToastService } from 'core-app/shared/components/toaster/toast.service'; +import { firstValueFrom, Observable } from 'rxjs'; import { - firstValueFrom, - Observable, -} from 'rxjs'; -import { WorkPackageViewFiltersService } from 'core-app/features/work-packages/routing/wp-view-base/view-services/wp-view-filters.service'; + WorkPackageViewFiltersService, +} from 'core-app/features/work-packages/routing/wp-view-base/view-services/wp-view-filters.service'; import { WorkPackagesListService } from 'core-app/features/work-packages/components/wp-list/wp-list.service'; import { IsolatedQuerySpace } from 'core-app/features/work-packages/directives/query-space/isolated-query-space'; import { UntilDestroyedMixin } from 'core-app/shared/helpers/angular/until-destroyed.mixin'; @@ -40,19 +36,26 @@ import { import { ApiV3Service } from 'core-app/core/apiv3/api-v3.service'; import { UIRouterGlobals } from '@uirouter/core'; import { TimezoneService } from 'core-app/core/datetime/timezone.service'; -import { WorkPackagesListChecksumService } from 'core-app/features/work-packages/components/wp-list/wp-list-checksum.service'; import { - EventReceiveArg, - EventResizeDoneArg, -} from '@fullcalendar/interaction'; -import { HalResourceEditingService } from 'core-app/shared/components/fields/edit/services/hal-resource-editing.service'; + WorkPackagesListChecksumService, +} from 'core-app/features/work-packages/components/wp-list/wp-list-checksum.service'; +import { EventReceiveArg, EventResizeDoneArg } from '@fullcalendar/interaction'; +import { + HalResourceEditingService, +} from 'core-app/shared/components/fields/edit/services/hal-resource-editing.service'; import { ResourceChangeset } from 'core-app/shared/components/fields/changeset/resource-changeset'; import * as moment from 'moment'; -import { WorkPackageViewSelectionService } from 'core-app/features/work-packages/routing/wp-view-base/view-services/wp-view-selection.service'; +import { + WorkPackageViewSelectionService, +} from 'core-app/features/work-packages/routing/wp-view-base/view-services/wp-view-selection.service'; import { isClickedWithModifier } from 'core-app/shared/helpers/link-handling/link-handling'; -import { uiStateLinkClass } from 'core-app/features/work-packages/components/wp-fast-table/builders/ui-state-link-builder'; +import { + uiStateLinkClass, +} from 'core-app/features/work-packages/components/wp-fast-table/builders/ui-state-link-builder'; import { debugLog } from 'core-app/shared/helpers/debug_output'; -import { WorkPackageViewContextMenu } from 'core-app/shared/components/op-context-menu/wp-context-menu/wp-view-context-menu.directive'; +import { + WorkPackageViewContextMenu, +} from 'core-app/shared/components/op-context-menu/wp-context-menu/wp-view-context-menu.directive'; import { OPContextMenuService } from 'core-app/shared/components/op-context-menu/op-context-menu.service'; import { OpCalendarService } from 'core-app/features/calendar/op-calendar.service'; import { WeekdayService } from 'core-app/core/days/weekday.service'; @@ -71,7 +74,7 @@ interface CalendarOptionsWithDayGrid extends CalendarOptions { @Injectable() export class OpWorkPackagesCalendarService extends UntilDestroyedMixin { - static MAX_DISPLAYED = 100; + static MAX_DISPLAYED = 500; tooManyResultsText:string|null; @@ -207,6 +210,8 @@ export class OpWorkPackagesCalendarService extends UntilDestroyedMixin { ...(oldQueryProps.f as QueryPropsFilter[]).filter((filter:QueryPropsFilter) => filter.n !== 'datesInterval'), OpWorkPackagesCalendarService.dateFilter(startDate, endDate), ], + pp: OpWorkPackagesCalendarService.MAX_DISPLAYED, + pa: 1, }; queryProps = JSON.stringify(newQueryProps); diff --git a/frontend/src/app/features/team-planner/team-planner/planner/event-view-lookup.service.ts b/frontend/src/app/features/team-planner/team-planner/planner/event-view-lookup.service.ts deleted file mode 100644 index 94612f914906..000000000000 --- a/frontend/src/app/features/team-planner/team-planner/planner/event-view-lookup.service.ts +++ /dev/null @@ -1,123 +0,0 @@ -import { - EmbeddedViewRef, - Injectable, - OnDestroy, - TemplateRef, - ViewContainerRef, -} from '@angular/core'; -import { debugLog } from 'core-app/shared/helpers/debug_output'; - -/** - * View lookup service for injecting angular templates - * as fullcalendar event content. - * - * Based on the suggestion from Daniel Goldsmith - * in https://github.com/fullcalendar/fullcalendar-angular/issues/204 - * - */ -@Injectable() -export class EventViewLookupService implements OnDestroy { - /** Active templates currently rendered */ - private readonly activeViews = new Map >(); - - /** Remember detached views to be destroyed on destroyAll */ - private readonly detachedViews:EmbeddedViewRef [] = []; - - constructor(private viewContainerRef:ViewContainerRef) { - } - - /** - * Gets the view for the given ID, or creates one if there isn't one - * already. The template's context is set (or updated to, if the - * view has already been created) the given context values. - * @param template The template ref (get this from a @ViewChild of an - * ) - * @param id The unique ID for this instance of the view. Use this so that - * you don't keep around views for the same event. - * @param context The available variables for the . For - * example, if it looks like this: then - * your context should be an object with a `value` key. - */ - getView( - template:TemplateRef diff --git a/frontend/src/assets/fonts/lato/Lato-Bold.woff b/frontend/src/assets/fonts/lato/Lato-Bold.woff deleted file mode 100644 index c6dff51f063c..000000000000 Binary files a/frontend/src/assets/fonts/lato/Lato-Bold.woff and /dev/null differ diff --git a/frontend/src/assets/fonts/lato/Lato-Bold.woff2 b/frontend/src/assets/fonts/lato/Lato-Bold.woff2 deleted file mode 100644 index bb195043cfc0..000000000000 Binary files a/frontend/src/assets/fonts/lato/Lato-Bold.woff2 and /dev/null differ diff --git a/frontend/src/assets/fonts/lato/Lato-BoldItalic.woff b/frontend/src/assets/fonts/lato/Lato-BoldItalic.woff deleted file mode 100644 index 88ad05b9ff41..000000000000 Binary files a/frontend/src/assets/fonts/lato/Lato-BoldItalic.woff and /dev/null differ diff --git a/frontend/src/assets/fonts/lato/Lato-BoldItalic.woff2 b/frontend/src/assets/fonts/lato/Lato-BoldItalic.woff2 deleted file mode 100644 index c4e3d804b57b..000000000000 Binary files a/frontend/src/assets/fonts/lato/Lato-BoldItalic.woff2 and /dev/null differ diff --git a/frontend/src/assets/fonts/lato/Lato-Italic.woff b/frontend/src/assets/fonts/lato/Lato-Italic.woff deleted file mode 100644 index 76114bc03362..000000000000 Binary files a/frontend/src/assets/fonts/lato/Lato-Italic.woff and /dev/null differ diff --git a/frontend/src/assets/fonts/lato/Lato-Italic.woff2 b/frontend/src/assets/fonts/lato/Lato-Italic.woff2 deleted file mode 100644 index 3404f37e2e31..000000000000 Binary files a/frontend/src/assets/fonts/lato/Lato-Italic.woff2 and /dev/null differ diff --git a/frontend/src/assets/fonts/lato/Lato-Light.woff b/frontend/src/assets/fonts/lato/Lato-Light.woff deleted file mode 100644 index 77b4e148f7f4..000000000000 Binary files a/frontend/src/assets/fonts/lato/Lato-Light.woff and /dev/null differ diff --git a/frontend/src/assets/fonts/lato/Lato-Light.woff2 b/frontend/src/assets/fonts/lato/Lato-Light.woff2 deleted file mode 100644 index ce49f82217ea..000000000000 Binary files a/frontend/src/assets/fonts/lato/Lato-Light.woff2 and /dev/null differ diff --git a/frontend/src/assets/fonts/lato/Lato-LightItalic.woff b/frontend/src/assets/fonts/lato/Lato-LightItalic.woff deleted file mode 100644 index da3dfa30a456..000000000000 Binary files a/frontend/src/assets/fonts/lato/Lato-LightItalic.woff and /dev/null differ diff --git a/frontend/src/assets/fonts/lato/Lato-LightItalic.woff2 b/frontend/src/assets/fonts/lato/Lato-LightItalic.woff2 deleted file mode 100644 index 0c897ce40ca1..000000000000 Binary files a/frontend/src/assets/fonts/lato/Lato-LightItalic.woff2 and /dev/null differ diff --git a/frontend/src/assets/fonts/lato/Lato-Regular.woff b/frontend/src/assets/fonts/lato/Lato-Regular.woff deleted file mode 100644 index ae1307ff5f4c..000000000000 Binary files a/frontend/src/assets/fonts/lato/Lato-Regular.woff and /dev/null differ diff --git a/frontend/src/assets/fonts/lato/Lato-Regular.woff2 b/frontend/src/assets/fonts/lato/Lato-Regular.woff2 deleted file mode 100644 index 3bf9843328a6..000000000000 Binary files a/frontend/src/assets/fonts/lato/Lato-Regular.woff2 and /dev/null differ diff --git a/frontend/src/assets/fonts/lato/OFL.txt b/frontend/src/assets/fonts/lato/OFL.txt deleted file mode 100755 index 6d2c4160b08f..000000000000 --- a/frontend/src/assets/fonts/lato/OFL.txt +++ /dev/null @@ -1,94 +0,0 @@ -Copyright (c) 2010-2015, Łukasz Dziedzic (dziedzic@typoland.com), -with Reserved Font Name Lato. - -This Font Software is licensed under the SIL Open Font License, Version 1.1. -This license is copied below, and is also available with a FAQ at: -http://scripts.sil.org/OFL - - ------------------------------------------------------------ -SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 ------------------------------------------------------------ - -PREAMBLE -The goals of the Open Font License (OFL) are to stimulate worldwide -development of collaborative font projects, to support the font creation -efforts of academic and linguistic communities, and to provide a free and -open framework in which fonts may be shared and improved in partnership -with others. - -The OFL allows the licensed fonts to be used, studied, modified and -redistributed freely as long as they are not sold by themselves. The -fonts, including any derivative works, can be bundled, embedded, -redistributed and/or sold with any software provided that any reserved -names are not used by derivative works. The fonts and derivatives, -however, cannot be released under any other type of license. The -requirement for fonts to remain under this license does not apply -to any document created using the fonts or their derivatives. - -DEFINITIONS -"Font Software" refers to the set of files released by the Copyright -Holder(s) under this license and clearly marked as such. This may -include source files, build scripts and documentation. - -"Reserved Font Name" refers to any names specified as such after the -copyright statement(s). - -"Original Version" refers to the collection of Font Software components as -distributed by the Copyright Holder(s). - -"Modified Version" refers to any derivative made by adding to, deleting, -or substituting -- in part or in whole -- any of the components of the -Original Version, by changing formats or by porting the Font Software to a -new environment. - -"Author" refers to any designer, engineer, programmer, technical -writer or other person who contributed to the Font Software. - -PERMISSION & CONDITIONS -Permission is hereby granted, free of charge, to any person obtaining -a copy of the Font Software, to use, study, copy, merge, embed, modify, -redistribute, and sell modified and unmodified copies of the Font -Software, subject to the following conditions: - -1) Neither the Font Software nor any of its individual components, -in Original or Modified Versions, may be sold by itself. - -2) Original or Modified Versions of the Font Software may be bundled, -redistributed and/or sold with any software, provided that each copy -contains the above copyright notice and this license. These can be -included either as stand-alone text files, human-readable headers or -in the appropriate machine-readable metadata fields within text or -binary files as long as those fields can be easily viewed by the user. - -3) No Modified Version of the Font Software may use the Reserved Font -Name(s) unless explicit written permission is granted by the corresponding -Copyright Holder. This restriction only applies to the primary font name as -presented to the users. - -4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font -Software shall not be used to promote, endorse or advertise any -Modified Version, except to acknowledge the contribution(s) of the -Copyright Holder(s) and the Author(s) or with their explicit written -permission. - -5) The Font Software, modified or unmodified, in part or in whole, -must be distributed entirely under this license, and must not be -distributed under any other license. The requirement for fonts to -remain under this license does not apply to any document created -using the Font Software. - -TERMINATION -This license becomes null and void if any of the above conditions are -not met. - -DISCLAIMER -THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT -OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE -COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL -DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM -OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/frontend/src/global_styles/content/_sidemenu.sass b/frontend/src/global_styles/content/_sidemenu.sass index 931ab0adaae9..059ab00bf74a 100644 --- a/frontend/src/global_styles/content/_sidemenu.sass +++ b/frontend/src/global_styles/content/_sidemenu.sass @@ -46,6 +46,7 @@ padding-left: 12px &--item-title + display: flex margin-right: auto overflow: hidden text-overflow: ellipsis diff --git a/frontend/src/global_styles/content/user-content/_list.sass b/frontend/src/global_styles/content/user-content/_list.sass index 10ef43aa6d78..eb2a0f2d48cf 100644 --- a/frontend/src/global_styles/content/user-content/_list.sass +++ b/frontend/src/global_styles/content/user-content/_list.sass @@ -26,19 +26,31 @@ ol.op-uc-list list-style: none list-style-type: decimal ol + &.op-uc-list_task-list + list-style: none list-style-type: lower-latin ol + &.op-uc-list_task-list + list-style: none list-style-type: lower-roman ol + &.op-uc-list_task-list + list-style: none list-style-type: upper-latin ol + &.op-uc-list_task-list + list-style: none list-style-type: upper-roman ul.op-uc-list &_task-list list-style: none list-style-type: disc ul + &.op-uc-list_task-list + list-style: none list-style-type: circle ul, ul ul + &.op-uc-list_task-list + list-style: none list-style-type: square diff --git a/frontend/src/global_styles/fonts/_index.sass b/frontend/src/global_styles/fonts/_index.sass index 3c6ddd074a33..a94a5d588ecd 100644 --- a/frontend/src/global_styles/fonts/_index.sass +++ b/frontend/src/global_styles/fonts/_index.sass @@ -1,3 +1,2 @@ -@import lato @import openproject_icon_font @import openproject_icon_font_face diff --git a/frontend/src/global_styles/fonts/_lato.sass b/frontend/src/global_styles/fonts/_lato.sass deleted file mode 100644 index 77924118ce96..000000000000 --- a/frontend/src/global_styles/fonts/_lato.sass +++ /dev/null @@ -1,63 +0,0 @@ -//-- copyright -// OpenProject is an open source project management software. -// Copyright (C) 2012-2024 the OpenProject GmbH -// -// 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 COPYRIGHT and LICENSE files for more details. -//++ - -@font-face - font-family: LatoLight - src: url('~assets/fonts/lato/Lato-Light.woff') format('woff'), url('~assets/fonts/lato/Lato-Light.woff2') format('woff2') - font-weight: normal - font-style: normal - -@font-face - font-family: LatoLight - src: url('~assets/fonts/lato/Lato-LightItalic.woff') format('woff'), url('~assets/fonts/lato/Lato-LightItalic.woff2') format('woff2') - font-weight: normal - font-style: italic - -@font-face - font-family: Lato - src: url('~assets/fonts/lato/Lato-Regular.woff') format('woff'), url('~assets/fonts/lato/Lato-Regular.woff2') format('woff2') - font-weight: normal - font-style: normal - -@font-face - font-family: Lato - src: url('~assets/fonts/lato/Lato-Italic.woff') format('woff'), url('~assets/fonts/lato/Lato-Italic.woff2') format('woff2') - font-weight: normal - font-style: italic - -@font-face - font-family: Lato - src: url('~assets/fonts/lato/Lato-Bold.woff') format('woff'), url('~assets/fonts/lato/Lato-Bold.woff2') format('woff2') - font-weight: var(--base-text-weight-bold) - font-style: normal - -@font-face - font-family: Lato - src: url('~assets/fonts/lato/Lato-BoldItalic.woff') format('woff'), url('~assets/fonts/lato/Lato-BoldItalic.woff2') format('woff2') - font-weight: var(--base-text-weight-bold) - font-style: italic diff --git a/frontend/src/stimulus/controllers/dynamic/backlogs/model.js b/frontend/src/stimulus/controllers/dynamic/backlogs/model.js index b9ecb9c81566..359a37e44a6d 100644 --- a/frontend/src/stimulus/controllers/dynamic/backlogs/model.js +++ b/frontend/src/stimulus/controllers/dynamic/backlogs/model.js @@ -304,14 +304,16 @@ RB.Model = (function ($) { }, handleClick: function (e) { - var field, model, j, editor; - - field = $(this); - model = field.parents('.model').first().data('this'); - j = model.$; - - if (!j.hasClass('editing') && !j.hasClass('dragging') && !j.hasClass('prevent_edit') && !$(e.target).hasClass('prevent_edit')) { - editor = model.edit(); + const field = $(this); + const model = field.parents('.model').first().data('this'); + const j = model.$; + + if (!j.hasClass('editing') + && !j.hasClass('dragging') + && !j.hasClass('prevent_edit') + && !$(e.target).hasClass('prevent_edit') + && e.target.closest('.editable').getAttribute('fieldeditable') !== 'false' ) { + const editor = model.edit(); var input = editor.find('.' + $(e.currentTarget).attr('fieldname') + '.editor'); input.focus(); diff --git a/frontend/src/vendor/ckeditor/ckeditor.js b/frontend/src/vendor/ckeditor/ckeditor.js index 8325f7b8206d..924341b9c23b 100644 --- a/frontend/src/vendor/ckeditor/ckeditor.js +++ b/frontend/src/vendor/ckeditor/ckeditor.js @@ -1,142327 +1,7 @@ -(function(d){ const l = d['en'] = d['en'] || {}; l.dictionary=Object.assign( l.dictionary||{}, {"%0 of %1":"%0 of %1","Align cell text to the bottom":"Align cell text to the bottom","Align cell text to the center":"Align cell text to the center","Align cell text to the left":"Align cell text to the left","Align cell text to the middle":"Align cell text to the middle","Align cell text to the right":"Align cell text to the right","Align cell text to the top":"Align cell text to the top","Align table to the left":"Align table to the left","Align table to the right":"Align table to the right",Alignment:"Alignment",Aquamarine:"Aquamarine",Background:"Background",Black:"Black","Block quote":"Block quote",Blue:"Blue",Bold:"Bold",Border:"Border","Break text":"Break text","Bulleted List":"Bulleted List","Bulleted list styles toolbar":"Bulleted list styles toolbar",Cancel:"Cancel","Cannot upload file:":"Cannot upload file:","Caption for image: %0":"Caption for image: %0","Caption for the image":"Caption for the image","Cell properties":"Cell properties","Center table":"Center table","Centered image":"Centered image","Change image text alternative":"Change image text alternative","Choose heading":"Choose heading",Circle:"Circle",Code:"Code",Color:"Color","Color picker":"Color picker",Column:"Column",Dashed:"Dashed",Decimal:"Decimal","Decimal with leading zero":"Decimal with leading zero","Delete column":"Delete column","Delete row":"Delete row","Dim grey":"Dim grey",Dimensions:"Dimensions",Disc:"Disc",Dotted:"Dotted",Double:"Double",Downloadable:"Downloadable","Dropdown toolbar":"Dropdown toolbar","Edit block":"Edit block","Edit link":"Edit link","Editor block content toolbar":"Editor block content toolbar","Editor contextual toolbar":"Editor contextual toolbar","Editor editing area: %0":"Editor editing area: %0","Editor toolbar":"Editor toolbar","Enter image caption":"Enter image caption","Enter table caption":"Enter table caption","Full size image":"Full size image",Green:"Green",Grey:"Grey",Groove:"Groove","Header column":"Header column","Header row":"Header row",Heading:"Heading","Heading 1":"Heading 1","Heading 2":"Heading 2","Heading 3":"Heading 3","Heading 4":"Heading 4","Heading 5":"Heading 5","Heading 6":"Heading 6",Height:"Height",HEX:"HEX","Horizontal text alignment toolbar":"Horizontal text alignment toolbar","Image resize list":"Image resize list","Image toolbar":"Image toolbar","image widget":"image widget","In line":"In line",Insert:"Insert","Insert column left":"Insert column left","Insert column right":"Insert column right","Insert image":"Insert image","Insert image via URL":"Insert image via URL","Insert paragraph after block":"Insert paragraph after block","Insert paragraph before block":"Insert paragraph before block","Insert row above":"Insert row above","Insert row below":"Insert row below","Insert table":"Insert table",Inset:"Inset",Italic:"Italic","Justify cell text":"Justify cell text","Left aligned image":"Left aligned image","Light blue":"Light blue","Light green":"Light green","Light grey":"Light grey",Link:"Link","Link image":"Link image","Link URL":"Link URL","List properties":"List properties","Lower-latin":"Lower-latin","Lower–roman":"Lower–roman","Merge cell down":"Merge cell down","Merge cell left":"Merge cell left","Merge cell right":"Merge cell right","Merge cell up":"Merge cell up","Merge cells":"Merge cells",Next:"Next",None:"None","Numbered List":"Numbered List","Numbered list styles toolbar":"Numbered list styles toolbar","Open in a new tab":"Open in a new tab","Open link in new tab":"Open link in new tab",Orange:"Orange",Original:"Original",Outset:"Outset",Padding:"Padding",Paragraph:"Paragraph","Press Enter to type after or press Shift + Enter to type before the widget":"Press Enter to type after or press Shift + Enter to type before the widget",Previous:"Previous",Purple:"Purple",Red:"Red",Redo:"Redo","Remove color":"Remove color","Resize image":"Resize image","Resize image to %0":"Resize image to %0","Resize image to the original size":"Resize image to the original size","Restore default":"Restore default","Reversed order":"Reversed order","Rich Text Editor":"Rich Text Editor","Rich Text Editor. Editing area: %0":"Rich Text Editor. Editing area: %0",Ridge:"Ridge","Right aligned image":"Right aligned image",Row:"Row",Save:"Save","Select all":"Select all","Select column":"Select column","Select row":"Select row","Show more items":"Show more items","Side image":"Side image",Solid:"Solid","Split cell horizontally":"Split cell horizontally","Split cell vertically":"Split cell vertically",Square:"Square","Start at":"Start at","Start index must be greater than 0.":"Start index must be greater than 0.",Strikethrough:"Strikethrough",Style:"Style",Subscript:"Subscript",Superscript:"Superscript","Table alignment toolbar":"Table alignment toolbar","Table cell text alignment":"Table cell text alignment","Table properties":"Table properties","Table toolbar":"Table toolbar","Text alternative":"Text alternative","The color is invalid. Try \"#FF0000\" or \"rgb(255,0,0)\" or \"red\".":"The color is invalid. Try \"#FF0000\" or \"rgb(255,0,0)\" or \"red\".","The value is invalid. Try \"10px\" or \"2em\" or simply \"2\".":"The value is invalid. Try \"10px\" or \"2em\" or simply \"2\".","This link has no URL":"This link has no URL","To-do List":"To-do List","Toggle caption off":"Toggle caption off","Toggle caption on":"Toggle caption on","Toggle the circle list style":"Toggle the circle list style","Toggle the decimal list style":"Toggle the decimal list style","Toggle the decimal with leading zero list style":"Toggle the decimal with leading zero list style","Toggle the disc list style":"Toggle the disc list style","Toggle the lower–latin list style":"Toggle the lower–latin list style","Toggle the lower–roman list style":"Toggle the lower–roman list style","Toggle the square list style":"Toggle the square list style","Toggle the upper–latin list style":"Toggle the upper–latin list style","Toggle the upper–roman list style":"Toggle the upper–roman list style",Turquoise:"Turquoise","Type or paste your content here.":"Type or paste your content here.","Type your title":"Type your title",Underline:"Underline",Undo:"Undo",Unlink:"Unlink",Update:"Update","Update image URL":"Update image URL","Upload failed":"Upload failed","Upload in progress":"Upload in progress","Upper-latin":"Upper-latin","Upper-roman":"Upper-roman","Vertical text alignment toolbar":"Vertical text alignment toolbar",White:"White","Widget toolbar":"Widget toolbar",Width:"Width","Wrap text":"Wrap text",Yellow:"Yellow"} );})(window.CKEDITOR_TRANSLATIONS||(window.CKEDITOR_TRANSLATIONS={})); +!function(e){const t=e.en=e.en||{};t.dictionary=Object.assign(t.dictionary||{},{"%0 of %1":"%0 of %1","Align cell text to the bottom":"Align cell text to the bottom","Align cell text to the center":"Align cell text to the center","Align cell text to the left":"Align cell text to the left","Align cell text to the middle":"Align cell text to the middle","Align cell text to the right":"Align cell text to the right","Align cell text to the top":"Align cell text to the top","Align table to the left":"Align table to the left","Align table to the right":"Align table to the right",Alignment:"Alignment",Aquamarine:"Aquamarine",Background:"Background",Black:"Black","Block quote":"Block quote",Blue:"Blue",Bold:"Bold",Border:"Border","Break text":"Break text","Bulleted List":"Bulleted List","Bulleted list styles toolbar":"Bulleted list styles toolbar",Cancel:"Cancel","Cannot upload file:":"Cannot upload file:","Caption for image: %0":"Caption for image: %0","Caption for the image":"Caption for the image","Cell properties":"Cell properties","Center table":"Center table","Centered image":"Centered image","Change image text alternative":"Change image text alternative","Choose heading":"Choose heading",Circle:"Circle",Code:"Code",Color:"Color","Color picker":"Color picker",Column:"Column",Dashed:"Dashed",Decimal:"Decimal","Decimal with leading zero":"Decimal with leading zero","Delete column":"Delete column","Delete row":"Delete row","Dim grey":"Dim grey",Dimensions:"Dimensions",Disc:"Disc",Dotted:"Dotted",Double:"Double",Downloadable:"Downloadable","Dropdown toolbar":"Dropdown toolbar","Edit block":"Edit block","Edit link":"Edit link","Editor block content toolbar":"Editor block content toolbar","Editor contextual toolbar":"Editor contextual toolbar","Editor editing area: %0":"Editor editing area: %0","Editor toolbar":"Editor toolbar","Enter image caption":"Enter image caption","Enter table caption":"Enter table caption","Full size image":"Full size image",Green:"Green",Grey:"Grey",Groove:"Groove","Header column":"Header column","Header row":"Header row",Heading:"Heading","Heading 1":"Heading 1","Heading 2":"Heading 2","Heading 3":"Heading 3","Heading 4":"Heading 4","Heading 5":"Heading 5","Heading 6":"Heading 6",Height:"Height",HEX:"HEX","Horizontal text alignment toolbar":"Horizontal text alignment toolbar","Image resize list":"Image resize list","Image toolbar":"Image toolbar","image widget":"image widget","In line":"In line",Insert:"Insert","Insert column left":"Insert column left","Insert column right":"Insert column right","Insert image":"Insert image","Insert image via URL":"Insert image via URL","Insert paragraph after block":"Insert paragraph after block","Insert paragraph before block":"Insert paragraph before block","Insert row above":"Insert row above","Insert row below":"Insert row below","Insert table":"Insert table",Inset:"Inset",Italic:"Italic","Justify cell text":"Justify cell text","Left aligned image":"Left aligned image","Light blue":"Light blue","Light green":"Light green","Light grey":"Light grey",Link:"Link","Link image":"Link image","Link URL":"Link URL","List properties":"List properties","Lower-latin":"Lower-latin","Lower–roman":"Lower–roman","Merge cell down":"Merge cell down","Merge cell left":"Merge cell left","Merge cell right":"Merge cell right","Merge cell up":"Merge cell up","Merge cells":"Merge cells",Next:"Next",None:"None","Numbered List":"Numbered List","Numbered list styles toolbar":"Numbered list styles toolbar","Open in a new tab":"Open in a new tab","Open link in new tab":"Open link in new tab",Orange:"Orange",Original:"Original",Outset:"Outset",Padding:"Padding",Paragraph:"Paragraph","Press Enter to type after or press Shift + Enter to type before the widget":"Press Enter to type after or press Shift + Enter to type before the widget",Previous:"Previous",Purple:"Purple",Red:"Red",Redo:"Redo","Remove color":"Remove color","Resize image":"Resize image","Resize image to %0":"Resize image to %0","Resize image to the original size":"Resize image to the original size","Restore default":"Restore default","Reversed order":"Reversed order","Rich Text Editor":"Rich Text Editor","Rich Text Editor. Editing area: %0":"Rich Text Editor. Editing area: %0",Ridge:"Ridge","Right aligned image":"Right aligned image",Row:"Row",Save:"Save","Select all":"Select all","Select column":"Select column","Select row":"Select row","Show more items":"Show more items","Side image":"Side image",Solid:"Solid","Split cell horizontally":"Split cell horizontally","Split cell vertically":"Split cell vertically",Square:"Square","Start at":"Start at","Start index must be greater than 0.":"Start index must be greater than 0.",Strikethrough:"Strikethrough",Style:"Style",Subscript:"Subscript",Superscript:"Superscript","Table alignment toolbar":"Table alignment toolbar","Table cell text alignment":"Table cell text alignment","Table properties":"Table properties","Table toolbar":"Table toolbar","Text alternative":"Text alternative",'The color is invalid. Try "#FF0000" or "rgb(255,0,0)" or "red".':'The color is invalid. Try "#FF0000" or "rgb(255,0,0)" or "red".','The value is invalid. Try "10px" or "2em" or simply "2".':'The value is invalid. Try "10px" or "2em" or simply "2".',"This link has no URL":"This link has no URL","To-do List":"To-do List","Toggle caption off":"Toggle caption off","Toggle caption on":"Toggle caption on","Toggle the circle list style":"Toggle the circle list style","Toggle the decimal list style":"Toggle the decimal list style","Toggle the decimal with leading zero list style":"Toggle the decimal with leading zero list style","Toggle the disc list style":"Toggle the disc list style","Toggle the lower–latin list style":"Toggle the lower–latin list style","Toggle the lower–roman list style":"Toggle the lower–roman list style","Toggle the square list style":"Toggle the square list style","Toggle the upper–latin list style":"Toggle the upper–latin list style","Toggle the upper–roman list style":"Toggle the upper–roman list style",Turquoise:"Turquoise","Type or paste your content here.":"Type or paste your content here.","Type your title":"Type your title",Underline:"Underline",Undo:"Undo",Unlink:"Unlink",Update:"Update","Update image URL":"Update image URL","Upload failed":"Upload failed","Upload in progress":"Upload in progress","Upper-latin":"Upper-latin","Upper-roman":"Upper-roman","Vertical text alignment toolbar":"Vertical text alignment toolbar",White:"White","Widget toolbar":"Widget toolbar",Width:"Width","Wrap text":"Wrap text",Yellow:"Yellow"})}(window.CKEDITOR_TRANSLATIONS||(window.CKEDITOR_TRANSLATIONS={})), /*! - * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved. + * @license Copyright (c) 2003-2024, CKSource Holding sp. z o.o. All rights reserved. * For licensing, see LICENSE.md. */ -(function webpackUniversalModuleDefinition(root, factory) { - if(typeof exports === 'object' && typeof module === 'object') - module.exports = factory(); - else if(typeof define === 'function' && define.amd) - define([], factory); - else if(typeof exports === 'object') - exports["OPEditor"] = factory(); - else - root["OPEditor"] = factory(); -})(self, () => { -return /******/ (() => { // webpackBootstrap -/******/ var __webpack_modules__ = ({ - -/***/ "./node_modules/@ckeditor/ckeditor5-adapter-ckfinder/src/augmentation.js": -/*!*******************************************************************************!*\ - !*** ./node_modules/@ckeditor/ckeditor5-adapter-ckfinder/src/augmentation.js ***! - \*******************************************************************************/ -/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { - -"use strict"; -__webpack_require__.r(__webpack_exports__); -/** - * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved. - * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license - */ - - - -/***/ }), - -/***/ "./node_modules/@ckeditor/ckeditor5-adapter-ckfinder/src/index.js": -/*!************************************************************************!*\ - !*** ./node_modules/@ckeditor/ckeditor5-adapter-ckfinder/src/index.js ***! - \************************************************************************/ -/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { - -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export */ __webpack_require__.d(__webpack_exports__, { -/* harmony export */ UploadAdapter: () => (/* reexport safe */ _uploadadapter__WEBPACK_IMPORTED_MODULE_0__["default"]) -/* harmony export */ }); -/* harmony import */ var _uploadadapter__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./uploadadapter */ "./node_modules/@ckeditor/ckeditor5-adapter-ckfinder/src/uploadadapter.js"); -/* harmony import */ var _augmentation__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./augmentation */ "./node_modules/@ckeditor/ckeditor5-adapter-ckfinder/src/augmentation.js"); -/** - * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved. - * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license - */ -/** - * @module adapter-ckfinder - */ - - - - -/***/ }), - -/***/ "./node_modules/@ckeditor/ckeditor5-adapter-ckfinder/src/uploadadapter.js": -/*!********************************************************************************!*\ - !*** ./node_modules/@ckeditor/ckeditor5-adapter-ckfinder/src/uploadadapter.js ***! - \********************************************************************************/ -/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { - -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export */ __webpack_require__.d(__webpack_exports__, { -/* harmony export */ "default": () => (/* binding */ CKFinderUploadAdapter) -/* harmony export */ }); -/* harmony import */ var ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ckeditor5/src/core */ "./node_modules/ckeditor5/src/core.js"); -/* harmony import */ var ckeditor5_src_upload__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ckeditor5/src/upload */ "./node_modules/ckeditor5/src/upload.js"); -/* harmony import */ var _utils__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./utils */ "./node_modules/@ckeditor/ckeditor5-adapter-ckfinder/src/utils.js"); -/** - * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved. - * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license - */ -/* globals XMLHttpRequest, FormData */ -/** - * @module adapter-ckfinder/uploadadapter - */ - - - -/** - * A plugin that enables file uploads in CKEditor 5 using the CKFinder server–side connector. - * - * See the {@glink features/file-management/ckfinder "CKFinder file manager integration"} guide to learn how to configure - * and use this feature as well as find out more about the full integration with the file manager - * provided by the {@link module:ckfinder/ckfinder~CKFinder} plugin. - * - * Check out the {@glink features/images/image-upload/image-upload comprehensive "Image upload overview"} guide to learn - * about other ways to upload images into CKEditor 5. - */ -class CKFinderUploadAdapter extends ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__.Plugin { - /** - * @inheritDoc - */ - static get requires() { - return [ckeditor5_src_upload__WEBPACK_IMPORTED_MODULE_1__.FileRepository]; - } - /** - * @inheritDoc - */ - static get pluginName() { - return 'CKFinderUploadAdapter'; - } - /** - * @inheritDoc - */ - init() { - const url = this.editor.config.get('ckfinder.uploadUrl'); - if (!url) { - return; - } - // Register CKFinderAdapter - this.editor.plugins.get(ckeditor5_src_upload__WEBPACK_IMPORTED_MODULE_1__.FileRepository).createUploadAdapter = loader => new UploadAdapter(loader, url, this.editor.t); - } -} -/** - * Upload adapter for CKFinder. - */ -class UploadAdapter { - /** - * Creates a new adapter instance. - */ - constructor(loader, url, t) { - this.loader = loader; - this.url = url; - this.t = t; - } - /** - * Starts the upload process. - * - * @see module:upload/filerepository~UploadAdapter#upload - */ - upload() { - return this.loader.file.then(file => { - return new Promise((resolve, reject) => { - this._initRequest(); - this._initListeners(resolve, reject, file); - this._sendRequest(file); - }); - }); - } - /** - * Aborts the upload process. - * - * @see module:upload/filerepository~UploadAdapter#abort - */ - abort() { - if (this.xhr) { - this.xhr.abort(); - } - } - /** - * Initializes the XMLHttpRequest object. - */ - _initRequest() { - const xhr = this.xhr = new XMLHttpRequest(); - xhr.open('POST', this.url, true); - xhr.responseType = 'json'; - } - /** - * Initializes XMLHttpRequest listeners. - * - * @param resolve Callback function to be called when the request is successful. - * @param reject Callback function to be called when the request cannot be completed. - * @param file File instance to be uploaded. - */ - _initListeners(resolve, reject, file) { - const xhr = this.xhr; - const loader = this.loader; - const t = this.t; - const genericError = t('Cannot upload file:') + ` ${file.name}.`; - xhr.addEventListener('error', () => reject(genericError)); - xhr.addEventListener('abort', () => reject()); - xhr.addEventListener('load', () => { - const response = xhr.response; - if (!response || !response.uploaded) { - return reject(response && response.error && response.error.message ? response.error.message : genericError); - } - resolve({ - default: response.url - }); - }); - // Upload progress when it's supported. - /* istanbul ignore else -- @preserve */ - if (xhr.upload) { - xhr.upload.addEventListener('progress', evt => { - if (evt.lengthComputable) { - loader.uploadTotal = evt.total; - loader.uploaded = evt.loaded; - } - }); - } - } - /** - * Prepares the data and sends the request. - * - * @param file File instance to be uploaded. - */ - _sendRequest(file) { - // Prepare form data. - const data = new FormData(); - data.append('upload', file); - data.append('ckCsrfToken', (0,_utils__WEBPACK_IMPORTED_MODULE_2__.getCsrfToken)()); - // Send request. - this.xhr.send(data); - } -} - - -/***/ }), - -/***/ "./node_modules/@ckeditor/ckeditor5-adapter-ckfinder/src/utils.js": -/*!************************************************************************!*\ - !*** ./node_modules/@ckeditor/ckeditor5-adapter-ckfinder/src/utils.js ***! - \************************************************************************/ -/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { - -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export */ __webpack_require__.d(__webpack_exports__, { -/* harmony export */ getCookie: () => (/* binding */ getCookie), -/* harmony export */ getCsrfToken: () => (/* binding */ getCsrfToken), -/* harmony export */ setCookie: () => (/* binding */ setCookie) -/* harmony export */ }); -/** - * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved. - * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license - */ -/* globals window, document */ -/** - * @module adapter-ckfinder/utils - */ -const TOKEN_COOKIE_NAME = 'ckCsrfToken'; -const TOKEN_LENGTH = 40; -const tokenCharset = 'abcdefghijklmnopqrstuvwxyz0123456789'; -/** - * Returns the CSRF token value. The value is a hash stored in `document.cookie` - * under the `ckCsrfToken` key. The CSRF token can be used to secure the communication - * between the web browser and the CKFinder server. - */ -function getCsrfToken() { - let token = getCookie(TOKEN_COOKIE_NAME); - if (!token || token.length != TOKEN_LENGTH) { - token = generateToken(TOKEN_LENGTH); - setCookie(TOKEN_COOKIE_NAME, token); - } - return token; -} -/** - * Returns the value of the cookie with a given name or `null` if the cookie is not found. - */ -function getCookie(name) { - name = name.toLowerCase(); - const parts = document.cookie.split(';'); - for (const part of parts) { - const pair = part.split('='); - const key = decodeURIComponent(pair[0].trim().toLowerCase()); - if (key === name) { - return decodeURIComponent(pair[1]); - } - } - return null; -} -/** - * Sets the value of the cookie with a given name. - */ -function setCookie(name, value) { - document.cookie = encodeURIComponent(name) + '=' + encodeURIComponent(value) + ';path=/'; -} -/** - * Generates the CSRF token with the given length. - */ -function generateToken(length) { - let result = ''; - const randValues = new Uint8Array(length); - window.crypto.getRandomValues(randValues); - for (let j = 0; j < randValues.length; j++) { - const character = tokenCharset.charAt(randValues[j] % tokenCharset.length); - result += Math.random() > 0.5 ? character.toUpperCase() : character; - } - return result; -} - - -/***/ }), - -/***/ "./node_modules/@ckeditor/ckeditor5-autoformat/src/augmentation.js": -/*!*************************************************************************!*\ - !*** ./node_modules/@ckeditor/ckeditor5-autoformat/src/augmentation.js ***! - \*************************************************************************/ -/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { - -"use strict"; -__webpack_require__.r(__webpack_exports__); -/** - * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved. - * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license - */ - - - -/***/ }), - -/***/ "./node_modules/@ckeditor/ckeditor5-autoformat/src/autoformat.js": -/*!***********************************************************************!*\ - !*** ./node_modules/@ckeditor/ckeditor5-autoformat/src/autoformat.js ***! - \***********************************************************************/ -/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { - -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export */ __webpack_require__.d(__webpack_exports__, { -/* harmony export */ "default": () => (/* binding */ Autoformat) -/* harmony export */ }); -/* harmony import */ var ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ckeditor5/src/core */ "./node_modules/ckeditor5/src/core.js"); -/* harmony import */ var ckeditor5_src_typing__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ckeditor5/src/typing */ "./node_modules/ckeditor5/src/typing.js"); -/* harmony import */ var _blockautoformatediting__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./blockautoformatediting */ "./node_modules/@ckeditor/ckeditor5-autoformat/src/blockautoformatediting.js"); -/* harmony import */ var _inlineautoformatediting__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./inlineautoformatediting */ "./node_modules/@ckeditor/ckeditor5-autoformat/src/inlineautoformatediting.js"); -/** - * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved. - * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license - */ - - - - -/** - * Enables a set of predefined autoformatting actions. - * - * For a detailed overview, check the {@glink features/autoformat Autoformatting} feature guide - * and the {@glink api/autoformat package page}. - */ -class Autoformat extends ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__.Plugin { - /** - * @inheritDoc - */ - static get requires() { - return [ckeditor5_src_typing__WEBPACK_IMPORTED_MODULE_1__.Delete]; - } - /** - * @inheritDoc - */ - static get pluginName() { - return 'Autoformat'; - } - /** - * @inheritDoc - */ - afterInit() { - this._addListAutoformats(); - this._addBasicStylesAutoformats(); - this._addHeadingAutoformats(); - this._addBlockQuoteAutoformats(); - this._addCodeBlockAutoformats(); - this._addHorizontalLineAutoformats(); - } - /** - * Adds autoformatting related to the {@link module:list/list~List}. - * - * When typed: - * - `* ` or `- ` – A paragraph will be changed into a bulleted list. - * - `1. ` or `1) ` – A paragraph will be changed into a numbered list ("1" can be any digit or a list of digits). - * - `[] ` or `[ ] ` – A paragraph will be changed into a to-do list. - * - `[x] ` or `[ x ] ` – A paragraph will be changed into a checked to-do list. - */ - _addListAutoformats() { - const commands = this.editor.commands; - if (commands.get('bulletedList')) { - (0,_blockautoformatediting__WEBPACK_IMPORTED_MODULE_2__["default"])(this.editor, this, /^[*-]\s$/, 'bulletedList'); - } - if (commands.get('numberedList')) { - (0,_blockautoformatediting__WEBPACK_IMPORTED_MODULE_2__["default"])(this.editor, this, /^1[.|)]\s$/, 'numberedList'); - } - if (commands.get('todoList')) { - (0,_blockautoformatediting__WEBPACK_IMPORTED_MODULE_2__["default"])(this.editor, this, /^\[\s?\]\s$/, 'todoList'); - } - if (commands.get('checkTodoList')) { - (0,_blockautoformatediting__WEBPACK_IMPORTED_MODULE_2__["default"])(this.editor, this, /^\[\s?x\s?\]\s$/, () => { - this.editor.execute('todoList'); - this.editor.execute('checkTodoList'); - }); - } - } - /** - * Adds autoformatting related to the {@link module:basic-styles/bold~Bold}, - * {@link module:basic-styles/italic~Italic}, {@link module:basic-styles/code~Code} - * and {@link module:basic-styles/strikethrough~Strikethrough} - * - * When typed: - * - `**foobar**` – `**` characters are removed and `foobar` is set to bold, - * - `__foobar__` – `__` characters are removed and `foobar` is set to bold, - * - `*foobar*` – `*` characters are removed and `foobar` is set to italic, - * - `_foobar_` – `_` characters are removed and `foobar` is set to italic, - * - ``` `foobar` – ``` ` ``` characters are removed and `foobar` is set to code, - * - `~~foobar~~` – `~~` characters are removed and `foobar` is set to strikethrough. - */ - _addBasicStylesAutoformats() { - const commands = this.editor.commands; - if (commands.get('bold')) { - const boldCallback = getCallbackFunctionForInlineAutoformat(this.editor, 'bold'); - (0,_inlineautoformatediting__WEBPACK_IMPORTED_MODULE_3__["default"])(this.editor, this, /(?:^|\s)(\*\*)([^*]+)(\*\*)$/g, boldCallback); - (0,_inlineautoformatediting__WEBPACK_IMPORTED_MODULE_3__["default"])(this.editor, this, /(?:^|\s)(__)([^_]+)(__)$/g, boldCallback); - } - if (commands.get('italic')) { - const italicCallback = getCallbackFunctionForInlineAutoformat(this.editor, 'italic'); - // The italic autoformatter cannot be triggered by the bold markers, so we need to check the - // text before the pattern (e.g. `(?:^|[^\*])`). - (0,_inlineautoformatediting__WEBPACK_IMPORTED_MODULE_3__["default"])(this.editor, this, /(?:^|\s)(\*)([^*_]+)(\*)$/g, italicCallback); - (0,_inlineautoformatediting__WEBPACK_IMPORTED_MODULE_3__["default"])(this.editor, this, /(?:^|\s)(_)([^_]+)(_)$/g, italicCallback); - } - if (commands.get('code')) { - const codeCallback = getCallbackFunctionForInlineAutoformat(this.editor, 'code'); - (0,_inlineautoformatediting__WEBPACK_IMPORTED_MODULE_3__["default"])(this.editor, this, /(`)([^`]+)(`)$/g, codeCallback); - } - if (commands.get('strikethrough')) { - const strikethroughCallback = getCallbackFunctionForInlineAutoformat(this.editor, 'strikethrough'); - (0,_inlineautoformatediting__WEBPACK_IMPORTED_MODULE_3__["default"])(this.editor, this, /(~~)([^~]+)(~~)$/g, strikethroughCallback); - } - } - /** - * Adds autoformatting related to {@link module:heading/heading~Heading}. - * - * It is using a number at the end of the command name to associate it with the proper trigger: - * - * * `heading` with a `heading1` value will be executed when typing `#`, - * * `heading` with a `heading2` value will be executed when typing `##`, - * * ... up to `heading6` for `######`. - */ - _addHeadingAutoformats() { - const command = this.editor.commands.get('heading'); - if (command) { - command.modelElements - .filter(name => name.match(/^heading[1-6]$/)) - .forEach(modelName => { - const level = modelName[7]; - const pattern = new RegExp(`^(#{${level}})\\s$`); - (0,_blockautoformatediting__WEBPACK_IMPORTED_MODULE_2__["default"])(this.editor, this, pattern, () => { - // Should only be active if command is enabled and heading style associated with pattern is inactive. - if (!command.isEnabled || command.value === modelName) { - return false; - } - this.editor.execute('heading', { value: modelName }); - }); - }); - } - } - /** - * Adds autoformatting related to {@link module:block-quote/blockquote~BlockQuote}. - * - * When typed: - * * `> ` – A paragraph will be changed to a block quote. - */ - _addBlockQuoteAutoformats() { - if (this.editor.commands.get('blockQuote')) { - (0,_blockautoformatediting__WEBPACK_IMPORTED_MODULE_2__["default"])(this.editor, this, /^>\s$/, 'blockQuote'); - } - } - /** - * Adds autoformatting related to {@link module:code-block/codeblock~CodeBlock}. - * - * When typed: - * - `` ``` `` – A paragraph will be changed to a code block. - */ - _addCodeBlockAutoformats() { - const editor = this.editor; - const selection = editor.model.document.selection; - if (editor.commands.get('codeBlock')) { - (0,_blockautoformatediting__WEBPACK_IMPORTED_MODULE_2__["default"])(editor, this, /^```$/, () => { - if (selection.getFirstPosition().parent.is('element', 'listItem')) { - return false; - } - this.editor.execute('codeBlock', { - usePreviousLanguageChoice: true - }); - }); - } - } - /** - * Adds autoformatting related to {@link module:horizontal-line/horizontalline~HorizontalLine}. - * - * When typed: - * - `` --- `` – Will be replaced with a horizontal line. - */ - _addHorizontalLineAutoformats() { - if (this.editor.commands.get('horizontalLine')) { - (0,_blockautoformatediting__WEBPACK_IMPORTED_MODULE_2__["default"])(this.editor, this, /^---$/, 'horizontalLine'); - } - } -} -/** - * Helper function for getting `inlineAutoformatEditing` callbacks that checks if command is enabled. - */ -function getCallbackFunctionForInlineAutoformat(editor, attributeKey) { - return (writer, rangesToFormat) => { - const command = editor.commands.get(attributeKey); - if (!command.isEnabled) { - return false; - } - const validRanges = editor.model.schema.getValidRanges(rangesToFormat, attributeKey); - for (const range of validRanges) { - writer.setAttribute(attributeKey, true, range); - } - // After applying attribute to the text, remove given attribute from the selection. - // This way user is able to type a text without attribute used by auto formatter. - writer.removeSelectionAttribute(attributeKey); - }; -} - - -/***/ }), - -/***/ "./node_modules/@ckeditor/ckeditor5-autoformat/src/blockautoformatediting.js": -/*!***********************************************************************************!*\ - !*** ./node_modules/@ckeditor/ckeditor5-autoformat/src/blockautoformatediting.js ***! - \***********************************************************************************/ -/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { - -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export */ __webpack_require__.d(__webpack_exports__, { -/* harmony export */ "default": () => (/* binding */ blockAutoformatEditing) -/* harmony export */ }); -/* harmony import */ var ckeditor5_src_engine__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ckeditor5/src/engine */ "./node_modules/ckeditor5/src/engine.js"); -/* harmony import */ var ckeditor5_src_utils__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ckeditor5/src/utils */ "./node_modules/ckeditor5/src/utils.js"); -/** - * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved. - * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license - */ - - -/** - * The block autoformatting engine. It allows to format various block patterns. For example, - * it can be configured to turn a paragraph starting with `*` and followed by a space into a list item. - * - * The autoformatting operation is integrated with the undo manager, - * so the autoformatting step can be undone if the user's intention was not to format the text. - * - * See the {@link module:autoformat/blockautoformatediting~blockAutoformatEditing `blockAutoformatEditing`} documentation - * to learn how to create custom block autoformatters. You can also use - * the {@link module:autoformat/autoformat~Autoformat} feature which enables a set of default autoformatters - * (lists, headings, bold and italic). - * - * @module autoformat/blockautoformatediting - */ -/** - * Creates a listener triggered on {@link module:engine/model/document~Document#event:change:data `change:data`} event in the document. - * Calls the callback when inserted text matches the regular expression or the command name - * if provided instead of the callback. - * - * Examples of usage: - * - * To convert a paragraph into heading 1 when `- ` is typed, using just the command name: - * - * ```ts - * blockAutoformatEditing( editor, plugin, /^\- $/, 'heading1' ); - * ``` - * - * To convert a paragraph into heading 1 when `- ` is typed, using just the callback: - * - * ```ts - * blockAutoformatEditing( editor, plugin, /^\- $/, ( context ) => { - * const { match } = context; - * const headingLevel = match[ 1 ].length; - * - * editor.execute( 'heading', { - * formatId: `heading${ headingLevel }` - * } ); - * } ); - * ``` - * - * @param editor The editor instance. - * @param plugin The autoformat plugin instance. - * @param pattern The regular expression to execute on just inserted text. The regular expression is tested against the text - * from the beginning until the caret position. - * @param callbackOrCommand The callback to execute or the command to run when the text is matched. - * In case of providing the callback, it receives the following parameter: - * * match RegExp.exec() result of matching the pattern to inserted text. - */ -function blockAutoformatEditing(editor, plugin, pattern, callbackOrCommand) { - let callback; - let command = null; - if (typeof callbackOrCommand == 'function') { - callback = callbackOrCommand; - } - else { - // We assume that the actual command name was provided. - command = editor.commands.get(callbackOrCommand); - callback = () => { - editor.execute(callbackOrCommand); - }; - } - editor.model.document.on('change:data', (evt, batch) => { - if (command && !command.isEnabled || !plugin.isEnabled) { - return; - } - const range = (0,ckeditor5_src_utils__WEBPACK_IMPORTED_MODULE_1__.first)(editor.model.document.selection.getRanges()); - if (!range.isCollapsed) { - return; - } - if (batch.isUndo || !batch.isLocal) { - return; - } - const changes = Array.from(editor.model.document.differ.getChanges()); - const entry = changes[0]; - // Typing is represented by only a single change. - if (changes.length != 1 || entry.type !== 'insert' || entry.name != '$text' || entry.length != 1) { - return; - } - const blockToFormat = entry.position.parent; - // Block formatting should be disabled in codeBlocks (#5800). - if (blockToFormat.is('element', 'codeBlock')) { - return; - } - // Only list commands and custom callbacks can be applied inside a list. - if (blockToFormat.is('element', 'listItem') && - typeof callbackOrCommand !== 'function' && - !['numberedList', 'bulletedList', 'todoList'].includes(callbackOrCommand)) { - return; - } - // In case a command is bound, do not re-execute it over an existing block style which would result in a style removal. - // Instead, just drop processing so that autoformat trigger text is not lost. E.g. writing "# " in a level 1 heading. - if (command && command.value === true) { - return; - } - const firstNode = blockToFormat.getChild(0); - const firstNodeRange = editor.model.createRangeOn(firstNode); - // Range is only expected to be within or at the very end of the first text node. - if (!firstNodeRange.containsRange(range) && !range.end.isEqual(firstNodeRange.end)) { - return; - } - const match = pattern.exec(firstNode.data.substr(0, range.end.offset)); - // ...and this text node's data match the pattern. - if (!match) { - return; - } - // Use enqueueChange to create new batch to separate typing batch from the auto-format changes. - editor.model.enqueueChange(writer => { - // Matched range. - const start = writer.createPositionAt(blockToFormat, 0); - const end = writer.createPositionAt(blockToFormat, match[0].length); - const range = new ckeditor5_src_engine__WEBPACK_IMPORTED_MODULE_0__.LiveRange(start, end); - const wasChanged = callback({ match }); - // Remove matched text. - if (wasChanged !== false) { - writer.remove(range); - const selectionRange = editor.model.document.selection.getFirstRange(); - const blockRange = writer.createRangeIn(blockToFormat); - // If the block is empty and the document selection has been moved when - // applying formatting (e.g. is now in newly created block). - if (blockToFormat.isEmpty && !blockRange.isEqual(selectionRange) && !blockRange.containsRange(selectionRange, true)) { - writer.remove(blockToFormat); - } - } - range.detach(); - editor.model.enqueueChange(() => { - const deletePlugin = editor.plugins.get('Delete'); - deletePlugin.requestUndoOnBackspace(); - }); - }); - }); -} - - -/***/ }), - -/***/ "./node_modules/@ckeditor/ckeditor5-autoformat/src/index.js": -/*!******************************************************************!*\ - !*** ./node_modules/@ckeditor/ckeditor5-autoformat/src/index.js ***! - \******************************************************************/ -/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { - -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export */ __webpack_require__.d(__webpack_exports__, { -/* harmony export */ Autoformat: () => (/* reexport safe */ _autoformat__WEBPACK_IMPORTED_MODULE_0__["default"]) -/* harmony export */ }); -/* harmony import */ var _autoformat__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./autoformat */ "./node_modules/@ckeditor/ckeditor5-autoformat/src/autoformat.js"); -/* harmony import */ var _augmentation__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./augmentation */ "./node_modules/@ckeditor/ckeditor5-autoformat/src/augmentation.js"); -/** - * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved. - * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license - */ -/** - * @module autoformat - */ - - - - -/***/ }), - -/***/ "./node_modules/@ckeditor/ckeditor5-autoformat/src/inlineautoformatediting.js": -/*!************************************************************************************!*\ - !*** ./node_modules/@ckeditor/ckeditor5-autoformat/src/inlineautoformatediting.js ***! - \************************************************************************************/ -/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { - -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export */ __webpack_require__.d(__webpack_exports__, { -/* harmony export */ "default": () => (/* binding */ inlineAutoformatEditing) -/* harmony export */ }); -/** - * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved. - * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license - */ -/** - * Enables autoformatting mechanism for a given {@link module:core/editor/editor~Editor}. - * - * It formats the matched text by applying the given model attribute or by running the provided formatting callback. - * On every {@link module:engine/model/document~Document#event:change:data data change} in the model document - * the autoformatting engine checks the text on the left of the selection - * and executes the provided action if the text matches given criteria (regular expression or callback). - * - * @param editor The editor instance. - * @param plugin The autoformat plugin instance. - * @param testRegexpOrCallback The regular expression or callback to execute on text. - * Provided regular expression *must* have three capture groups. The first and the third capture group - * should match opening and closing delimiters. The second capture group should match the text to format. - * - * ```ts - * // Matches the `**bold text**` pattern. - * // There are three capturing groups: - * // - The first to match the starting `**` delimiter. - * // - The second to match the text to format. - * // - The third to match the ending `**` delimiter. - * inlineAutoformatEditing( editor, plugin, /(\*\*)([^\*]+?)(\*\*)$/g, formatCallback ); - * ``` - * - * When a function is provided instead of the regular expression, it will be executed with the text to match as a parameter. - * The function should return proper "ranges" to delete and format. - * - * ```ts - * { - * remove: [ - * [ 0, 1 ], // Remove the first letter from the given text. - * [ 5, 6 ] // Remove the 6th letter from the given text. - * ], - * format: [ - * [ 1, 5 ] // Format all letters from 2nd to 5th. - * ] - * } - * ``` - * - * @param formatCallback A callback to apply actual formatting. - * It should return `false` if changes should not be applied (e.g. if a command is disabled). - * - * ```ts - * inlineAutoformatEditing( editor, plugin, /(\*\*)([^\*]+?)(\*\*)$/g, ( writer, rangesToFormat ) => { - * const command = editor.commands.get( 'bold' ); - * - * if ( !command.isEnabled ) { - * return false; - * } - * - * const validRanges = editor.model.schema.getValidRanges( rangesToFormat, 'bold' ); - * - * for ( let range of validRanges ) { - * writer.setAttribute( 'bold', true, range ); - * } - * } ); - * ``` - */ -function inlineAutoformatEditing(editor, plugin, testRegexpOrCallback, formatCallback) { - let regExp; - let testCallback; - if (testRegexpOrCallback instanceof RegExp) { - regExp = testRegexpOrCallback; - } - else { - testCallback = testRegexpOrCallback; - } - // A test callback run on changed text. - testCallback = testCallback || (text => { - let result; - const remove = []; - const format = []; - while ((result = regExp.exec(text)) !== null) { - // There should be full match and 3 capture groups. - if (result && result.length < 4) { - break; - } - let { index, '1': leftDel, '2': content, '3': rightDel } = result; - // Real matched string - there might be some non-capturing groups so we need to recalculate starting index. - const found = leftDel + content + rightDel; - index += result[0].length - found.length; - // Start and End offsets of delimiters to remove. - const delStart = [ - index, - index + leftDel.length - ]; - const delEnd = [ - index + leftDel.length + content.length, - index + leftDel.length + content.length + rightDel.length - ]; - remove.push(delStart); - remove.push(delEnd); - format.push([index + leftDel.length, index + leftDel.length + content.length]); - } - return { - remove, - format - }; - }); - editor.model.document.on('change:data', (evt, batch) => { - if (batch.isUndo || !batch.isLocal || !plugin.isEnabled) { - return; - } - const model = editor.model; - const selection = model.document.selection; - // Do nothing if selection is not collapsed. - if (!selection.isCollapsed) { - return; - } - const changes = Array.from(model.document.differ.getChanges()); - const entry = changes[0]; - // Typing is represented by only a single change. - if (changes.length != 1 || entry.type !== 'insert' || entry.name != '$text' || entry.length != 1) { - return; - } - const focus = selection.focus; - const block = focus.parent; - const { text, range } = getTextAfterCode(model.createRange(model.createPositionAt(block, 0), focus), model); - const testOutput = testCallback(text); - const rangesToFormat = testOutputToRanges(range.start, testOutput.format, model); - const rangesToRemove = testOutputToRanges(range.start, testOutput.remove, model); - if (!(rangesToFormat.length && rangesToRemove.length)) { - return; - } - // Use enqueueChange to create new batch to separate typing batch from the auto-format changes. - model.enqueueChange(writer => { - // Apply format. - const hasChanged = formatCallback(writer, rangesToFormat); - // Strict check on `false` to have backward compatibility (when callbacks were returning `undefined`). - if (hasChanged === false) { - return; - } - // Remove delimiters - use reversed order to not mix the offsets while removing. - for (const range of rangesToRemove.reverse()) { - writer.remove(range); - } - model.enqueueChange(() => { - const deletePlugin = editor.plugins.get('Delete'); - deletePlugin.requestUndoOnBackspace(); - }); - }); - }); -} -/** - * Converts output of the test function provided to the inlineAutoformatEditing and converts it to the model ranges - * inside provided block. - */ -function testOutputToRanges(start, arrays, model) { - return arrays - .filter(array => (array[0] !== undefined && array[1] !== undefined)) - .map(array => { - return model.createRange(start.getShiftedBy(array[0]), start.getShiftedBy(array[1])); - }); -} -/** - * Returns the last text line after the last code element from the given range. - * It is similar to {@link module:typing/utils/getlasttextline.getLastTextLine `getLastTextLine()`}, - * but it ignores any text before the last `code`. - */ -function getTextAfterCode(range, model) { - let start = range.start; - const text = Array.from(range.getItems()).reduce((rangeText, node) => { - // Trim text to a last occurrence of an inline element and update range start. - if (!(node.is('$text') || node.is('$textProxy')) || node.getAttribute('code')) { - start = model.createPositionAfter(node); - return ''; - } - return rangeText + node.data; - }, ''); - return { text, range: model.createRange(start, range.end) }; -} - - -/***/ }), - -/***/ "./node_modules/@ckeditor/ckeditor5-basic-styles/src/attributecommand.js": -/*!*******************************************************************************!*\ - !*** ./node_modules/@ckeditor/ckeditor5-basic-styles/src/attributecommand.js ***! - \*******************************************************************************/ -/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { - -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export */ __webpack_require__.d(__webpack_exports__, { -/* harmony export */ "default": () => (/* binding */ AttributeCommand) -/* harmony export */ }); -/* harmony import */ var ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ckeditor5/src/core */ "./node_modules/ckeditor5/src/core.js"); -/** - * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved. - * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license - */ -/** - * @module basic-styles/attributecommand - */ - -/** - * An extension of the base {@link module:core/command~Command} class, which provides utilities for a command - * that toggles a single attribute on a text or an element. - * - * `AttributeCommand` uses {@link module:engine/model/document~Document#selection} - * to decide which nodes (if any) should be changed, and applies or removes the attribute from them. - * - * The command checks the {@link module:engine/model/model~Model#schema} to decide if it can be enabled - * for the current selection and to which nodes the attribute can be applied. - */ -class AttributeCommand extends ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__.Command { - /** - * @param attributeKey Attribute that will be set by the command. - */ - constructor(editor, attributeKey) { - super(editor); - this.attributeKey = attributeKey; - } - /** - * Updates the command's {@link #value} and {@link #isEnabled} based on the current selection. - */ - refresh() { - const model = this.editor.model; - const doc = model.document; - this.value = this._getValueFromFirstAllowedNode(); - this.isEnabled = model.schema.checkAttributeInSelection(doc.selection, this.attributeKey); - } - /** - * Executes the command — applies the attribute to the selection or removes it from the selection. - * - * If the command is active (`value == true`), it will remove attributes. Otherwise, it will set attributes. - * - * The execution result differs, depending on the {@link module:engine/model/document~Document#selection}: - * - * * If the selection is on a range, the command applies the attribute to all nodes in that range - * (if they are allowed to have this attribute by the {@link module:engine/model/schema~Schema schema}). - * * If the selection is collapsed in a non-empty node, the command applies the attribute to the - * {@link module:engine/model/document~Document#selection} itself (note that typed characters copy attributes from the selection). - * * If the selection is collapsed in an empty node, the command applies the attribute to the parent node of the selection (note - * that the selection inherits all attributes from a node if it is in an empty node). - * - * @fires execute - * @param options Command options. - * @param options.forceValue If set, it will force the command behavior. If `true`, - * the command will apply the attribute, otherwise the command will remove the attribute. - * If not set, the command will look for its current value to decide what it should do. - */ - execute(options = {}) { - const model = this.editor.model; - const doc = model.document; - const selection = doc.selection; - const value = (options.forceValue === undefined) ? !this.value : options.forceValue; - model.change(writer => { - if (selection.isCollapsed) { - if (value) { - writer.setSelectionAttribute(this.attributeKey, true); - } - else { - writer.removeSelectionAttribute(this.attributeKey); - } - } - else { - const ranges = model.schema.getValidRanges(selection.getRanges(), this.attributeKey); - for (const range of ranges) { - if (value) { - writer.setAttribute(this.attributeKey, value, range); - } - else { - writer.removeAttribute(this.attributeKey, range); - } - } - } - }); - } - /** - * Checks the attribute value of the first node in the selection that allows the attribute. - * For the collapsed selection returns the selection attribute. - * - * @returns The attribute value. - */ - _getValueFromFirstAllowedNode() { - const model = this.editor.model; - const schema = model.schema; - const selection = model.document.selection; - if (selection.isCollapsed) { - return selection.hasAttribute(this.attributeKey); - } - for (const range of selection.getRanges()) { - for (const item of range.getItems()) { - if (schema.checkAttribute(item, this.attributeKey)) { - return item.hasAttribute(this.attributeKey); - } - } - } - return false; - } -} - - -/***/ }), - -/***/ "./node_modules/@ckeditor/ckeditor5-basic-styles/src/augmentation.js": -/*!***************************************************************************!*\ - !*** ./node_modules/@ckeditor/ckeditor5-basic-styles/src/augmentation.js ***! - \***************************************************************************/ -/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { - -"use strict"; -__webpack_require__.r(__webpack_exports__); -/** - * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved. - * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license - */ - - - -/***/ }), - -/***/ "./node_modules/@ckeditor/ckeditor5-basic-styles/src/bold.js": -/*!*******************************************************************!*\ - !*** ./node_modules/@ckeditor/ckeditor5-basic-styles/src/bold.js ***! - \*******************************************************************/ -/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { - -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export */ __webpack_require__.d(__webpack_exports__, { -/* harmony export */ "default": () => (/* binding */ Bold) -/* harmony export */ }); -/* harmony import */ var ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ckeditor5/src/core */ "./node_modules/ckeditor5/src/core.js"); -/* harmony import */ var _bold_boldediting__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./bold/boldediting */ "./node_modules/@ckeditor/ckeditor5-basic-styles/src/bold/boldediting.js"); -/* harmony import */ var _bold_boldui__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./bold/boldui */ "./node_modules/@ckeditor/ckeditor5-basic-styles/src/bold/boldui.js"); -/** - * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved. - * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license - */ -/** - * @module basic-styles/bold - */ - - - -/** - * The bold feature. - * - * For a detailed overview check the {@glink features/basic-styles Basic styles feature} guide - * and the {@glink api/basic-styles package page}. - * - * This is a "glue" plugin which loads the {@link module:basic-styles/bold/boldediting~BoldEditing bold editing feature} - * and {@link module:basic-styles/bold/boldui~BoldUI bold UI feature}. - */ -class Bold extends ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__.Plugin { - /** - * @inheritDoc - */ - static get requires() { - return [_bold_boldediting__WEBPACK_IMPORTED_MODULE_1__["default"], _bold_boldui__WEBPACK_IMPORTED_MODULE_2__["default"]]; - } - /** - * @inheritDoc - */ - static get pluginName() { - return 'Bold'; - } -} - - -/***/ }), - -/***/ "./node_modules/@ckeditor/ckeditor5-basic-styles/src/bold/boldediting.js": -/*!*******************************************************************************!*\ - !*** ./node_modules/@ckeditor/ckeditor5-basic-styles/src/bold/boldediting.js ***! - \*******************************************************************************/ -/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { - -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export */ __webpack_require__.d(__webpack_exports__, { -/* harmony export */ "default": () => (/* binding */ BoldEditing) -/* harmony export */ }); -/* harmony import */ var ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ckeditor5/src/core */ "./node_modules/ckeditor5/src/core.js"); -/* harmony import */ var _attributecommand__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../attributecommand */ "./node_modules/@ckeditor/ckeditor5-basic-styles/src/attributecommand.js"); -/** - * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved. - * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license - */ -/** - * @module basic-styles/bold/boldediting - */ - - -const BOLD = 'bold'; -/** - * The bold editing feature. - * - * It registers the `'bold'` command and introduces the `bold` attribute in the model which renders to the view - * as a `` element. - */ -class BoldEditing extends ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__.Plugin { - /** - * @inheritDoc - */ - static get pluginName() { - return 'BoldEditing'; - } - /** - * @inheritDoc - */ - init() { - const editor = this.editor; - // Allow bold attribute on text nodes. - editor.model.schema.extend('$text', { allowAttributes: BOLD }); - editor.model.schema.setAttributeProperties(BOLD, { - isFormatting: true, - copyOnEnter: true - }); - // Build converter from model to view for data and editing pipelines. - editor.conversion.attributeToElement({ - model: BOLD, - view: 'strong', - upcastAlso: [ - 'b', - viewElement => { - const fontWeight = viewElement.getStyle('font-weight'); - if (!fontWeight) { - return null; - } - // Value of the `font-weight` attribute can be defined as a string or a number. - if (fontWeight == 'bold' || Number(fontWeight) >= 600) { - return { - name: true, - styles: ['font-weight'] - }; - } - return null; - } - ] - }); - // Create bold command. - editor.commands.add(BOLD, new _attributecommand__WEBPACK_IMPORTED_MODULE_1__["default"](editor, BOLD)); - // Set the Ctrl+B keystroke. - editor.keystrokes.set('CTRL+B', BOLD); - } -} - - -/***/ }), - -/***/ "./node_modules/@ckeditor/ckeditor5-basic-styles/src/bold/boldui.js": -/*!**************************************************************************!*\ - !*** ./node_modules/@ckeditor/ckeditor5-basic-styles/src/bold/boldui.js ***! - \**************************************************************************/ -/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { - -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export */ __webpack_require__.d(__webpack_exports__, { -/* harmony export */ "default": () => (/* binding */ BoldUI) -/* harmony export */ }); -/* harmony import */ var ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ckeditor5/src/core */ "./node_modules/ckeditor5/src/core.js"); -/* harmony import */ var ckeditor5_src_ui__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ckeditor5/src/ui */ "./node_modules/ckeditor5/src/ui.js"); -/** - * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved. - * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license - */ -/** - * @module basic-styles/bold/boldui - */ - - -const BOLD = 'bold'; -/** - * The bold UI feature. It introduces the Bold button. - */ -class BoldUI extends ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__.Plugin { - /** - * @inheritDoc - */ - static get pluginName() { - return 'BoldUI'; - } - /** - * @inheritDoc - */ - init() { - const editor = this.editor; - const t = editor.t; - // Add bold button to feature components. - editor.ui.componentFactory.add(BOLD, locale => { - const command = editor.commands.get(BOLD); - const view = new ckeditor5_src_ui__WEBPACK_IMPORTED_MODULE_1__.ButtonView(locale); - view.set({ - label: t('Bold'), - icon: ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__.icons.bold, - keystroke: 'CTRL+B', - tooltip: true, - isToggleable: true - }); - view.bind('isOn', 'isEnabled').to(command, 'value', 'isEnabled'); - // Execute command. - this.listenTo(view, 'execute', () => { - editor.execute(BOLD); - editor.editing.view.focus(); - }); - return view; - }); - } -} - - -/***/ }), - -/***/ "./node_modules/@ckeditor/ckeditor5-basic-styles/src/code.js": -/*!*******************************************************************!*\ - !*** ./node_modules/@ckeditor/ckeditor5-basic-styles/src/code.js ***! - \*******************************************************************/ -/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { - -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export */ __webpack_require__.d(__webpack_exports__, { -/* harmony export */ "default": () => (/* binding */ Code) -/* harmony export */ }); -/* harmony import */ var ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ckeditor5/src/core */ "./node_modules/ckeditor5/src/core.js"); -/* harmony import */ var _code_codeediting__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./code/codeediting */ "./node_modules/@ckeditor/ckeditor5-basic-styles/src/code/codeediting.js"); -/* harmony import */ var _code_codeui__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./code/codeui */ "./node_modules/@ckeditor/ckeditor5-basic-styles/src/code/codeui.js"); -/* harmony import */ var _theme_code_css__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../theme/code.css */ "./node_modules/@ckeditor/ckeditor5-basic-styles/theme/code.css"); -/** - * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved. - * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license - */ -/** - * @module basic-styles/code - */ - - - - -/** - * The code feature. - * - * For a detailed overview check the {@glink features/basic-styles Basic styles feature} guide - * and the {@glink api/basic-styles package page}. - * - * This is a "glue" plugin which loads the {@link module:basic-styles/code/codeediting~CodeEditing code editing feature} - * and {@link module:basic-styles/code/codeui~CodeUI code UI feature}. - */ -class Code extends ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__.Plugin { - /** - * @inheritDoc - */ - static get requires() { - return [_code_codeediting__WEBPACK_IMPORTED_MODULE_1__["default"], _code_codeui__WEBPACK_IMPORTED_MODULE_2__["default"]]; - } - /** - * @inheritDoc - */ - static get pluginName() { - return 'Code'; - } -} - - -/***/ }), - -/***/ "./node_modules/@ckeditor/ckeditor5-basic-styles/src/code/codeediting.js": -/*!*******************************************************************************!*\ - !*** ./node_modules/@ckeditor/ckeditor5-basic-styles/src/code/codeediting.js ***! - \*******************************************************************************/ -/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { - -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export */ __webpack_require__.d(__webpack_exports__, { -/* harmony export */ "default": () => (/* binding */ CodeEditing) -/* harmony export */ }); -/* harmony import */ var ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ckeditor5/src/core */ "./node_modules/ckeditor5/src/core.js"); -/* harmony import */ var ckeditor5_src_typing__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ckeditor5/src/typing */ "./node_modules/ckeditor5/src/typing.js"); -/* harmony import */ var _attributecommand__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../attributecommand */ "./node_modules/@ckeditor/ckeditor5-basic-styles/src/attributecommand.js"); -/** - * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved. - * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license - */ -/** - * @module basic-styles/code/codeediting - */ - - - -const CODE = 'code'; -const HIGHLIGHT_CLASS = 'ck-code_selected'; -/** - * The code editing feature. - * - * It registers the `'code'` command and introduces the `code` attribute in the model which renders to the view - * as a `, id:string, context:unknown, - ):EmbeddedViewRef { - let view = this.activeViews.get(id); - if (view) { - debugLog('Returning active view %O', id); - view.detectChanges(); - return view; - } - - // Create a new view and move to active - debugLog('CREATING new view %O', id); - view = this.viewContainerRef.createEmbeddedView(template, context); - this.activeViews.set(id, view); - view.detectChanges(); - - return view; - } - - ngOnDestroy():void { - this.destroyAll(); - } - - /** - * Call this method if all views need to be cleaned up. This will happen - * when your parent component is destroyed (e.g., in ngOnDestroy), - * but it may also be needed if you are clearing just the area where the - * views have been placed. - */ - public destroyAll():void { - debugLog('Destroying all views'); - - Array - .from(this.activeViews.values()) - .forEach(this.destroyView.bind(this)); - - debugLog('Destroying %O active views', this.activeViews.size); - this.activeViews.clear(); - - this.destroyDetached(); - } - - /** - * Call this method if you want to clean detached views. - * This is safe to call outside of drag & drop operations. - * - */ - public destroyDetached():void { - debugLog('Destroying %O detached views', this.detachedViews.length); - - while (this.detachedViews.length) { - this.destroyView(this.detachedViews.pop() as EmbeddedViewRef ); - } - } - - /** - * Mark a view to be destroyed. - * It will only be destroyed once +destroyAll+ is called. - * - * Ensure that destroyAll is called when, e.g., refreshing the calendar. - * - * @param id View ID - */ - public markForDestruction(id:string):void { - const view = this.activeViews.get(id); - if (!view) { - return; - } - - debugLog('Marking view %O to be destroyed', id); - this.activeViews.delete(id); - this.detachedViews.push(view); - } - - private destroyView(view:EmbeddedViewRef ) { - const index = this.viewContainerRef.indexOf(view); - if (index !== -1) { - this.viewContainerRef.remove(index); - } - - view.destroy(); - } -} diff --git a/frontend/src/app/features/team-planner/team-planner/planner/team-planner.component.ts b/frontend/src/app/features/team-planner/team-planner/planner/team-planner.component.ts index 108e5ea5cf19..2755041a09eb 100644 --- a/frontend/src/app/features/team-planner/team-planner/planner/team-planner.component.ts +++ b/frontend/src/app/features/team-planner/team-planner/planner/team-planner.component.ts @@ -37,18 +37,8 @@ import { TemplateRef, ViewChild, } from '@angular/core'; -import { - CalendarOptions, - DateSelectArg, - EventApi, - EventDropArg, - EventInput, -} from '@fullcalendar/core'; -import { - BehaviorSubject, - combineLatest, - Subject, -} from 'rxjs'; +import { CalendarOptions, DateSelectArg, EventApi, EventDropArg, EventInput } from '@fullcalendar/core'; +import { BehaviorSubject, combineLatest, Subject } from 'rxjs'; import { debounceTime, distinctUntilChanged, @@ -73,29 +63,31 @@ import interactionPlugin, { import { FullCalendarComponent } from '@fullcalendar/angular'; import { I18nService } from 'core-app/core/i18n/i18n.service'; import { ConfigurationService } from 'core-app/core/config/configuration.service'; -import { EventViewLookupService } from 'core-app/features/team-planner/team-planner/planner/event-view-lookup.service'; -import { WorkPackageViewFiltersService } from 'core-app/features/work-packages/routing/wp-view-base/view-services/wp-view-filters.service'; +import { + WorkPackageViewFiltersService, +} from 'core-app/features/work-packages/routing/wp-view-base/view-services/wp-view-filters.service'; import { IsolatedQuerySpace } from 'core-app/features/work-packages/directives/query-space/isolated-query-space'; import { CurrentProjectService } from 'core-app/core/current-project/current-project.service'; import { splitViewRoute } from 'core-app/features/work-packages/routing/split-view-routes.helper'; import { QueryFilterInstanceResource } from 'core-app/features/hal/resources/query-filter-instance-resource'; import { PrincipalsResourceService } from 'core-app/core/state/principals/principals.service'; -import { - ApiV3ListFilter, - ApiV3ListParameters, -} from 'core-app/core/apiv3/paths/apiv3-list-resource.interface'; +import { ApiV3ListFilter, ApiV3ListParameters } from 'core-app/core/apiv3/paths/apiv3-list-resource.interface'; import { WorkPackageResource } from 'core-app/features/hal/resources/work-package-resource'; import { HalResource } from 'core-app/features/hal/resources/hal-resource'; import { UntilDestroyedMixin } from 'core-app/shared/helpers/angular/until-destroyed.mixin'; import { OpCalendarService } from 'core-app/features/calendar/op-calendar.service'; -import { HalResourceEditingService } from 'core-app/shared/components/fields/edit/services/hal-resource-editing.service'; +import { + HalResourceEditingService, +} from 'core-app/shared/components/fields/edit/services/hal-resource-editing.service'; import { HalResourceNotificationService } from 'core-app/features/hal/services/hal-resource-notification.service'; import { SchemaCacheService } from 'core-app/core/schemas/schema-cache.service'; import { ApiV3Service } from 'core-app/core/apiv3/api-v3.service'; import { CalendarDragDropService } from 'core-app/features/team-planner/team-planner/calendar-drag-drop.service'; import { StatusResource } from 'core-app/features/hal/resources/status-resource'; import { ResourceChangeset } from 'core-app/shared/components/fields/changeset/resource-changeset'; -import { KeepTabService } from 'core-app/features/work-packages/components/wp-single-view-tabs/keep-tab/keep-tab.service'; +import { + KeepTabService, +} from 'core-app/features/work-packages/components/wp-single-view-tabs/keep-tab/keep-tab.service'; import { HalError } from 'core-app/features/hal/services/hal-error'; import { ActionsService } from 'core-app/core/state/actions/actions.service'; import { @@ -104,10 +96,7 @@ import { teamPlannerPageRefresh, } from 'core-app/features/team-planner/team-planner/planner/team-planner.actions'; import { imagePath } from 'core-app/shared/helpers/images/path-helper'; -import { - skeletonEvents, - skeletonResources, -} from './loading-skeleton-data'; +import { skeletonEvents, skeletonResources } from './loading-skeleton-data'; import { CapabilitiesResourceService } from 'core-app/core/state/capabilities/capabilities.service'; import { ICapability } from 'core-app/core/state/capabilities/capability.model'; import { ToastService } from 'core-app/shared/components/toaster/toast.service'; @@ -118,10 +107,7 @@ import { RawOptionsFromRefiners } from '@fullcalendar/core/internal'; import { ViewOptionRefiners } from '@fullcalendar/common'; import { ResourceApi } from '@fullcalendar/resource'; import { DeviceService } from 'core-app/core/browser/device.service'; -import { - EffectCallback, - registerEffectCallbacks, -} from 'core-app/core/state/effects/effect-handler.decorator'; +import { EffectCallback, registerEffectCallbacks } from 'core-app/core/state/effects/effect-handler.decorator'; import { addBackgroundEvents, removeBackgroundEvents, @@ -136,9 +122,6 @@ export type TeamPlannerViewOptions = { [K in TeamPlannerViewOptionKey]:RawOption templateUrl: './team-planner.component.html', styleUrls: ['./team-planner.component.sass'], changeDetection: ChangeDetectionStrategy.OnPush, - providers: [ - EventViewLookupService, - ], }) export class TeamPlannerComponent extends UntilDestroyedMixin implements OnInit, OnDestroy { @ViewChild(FullCalendarComponent) ucCalendar:FullCalendarComponent; @@ -377,7 +360,6 @@ export class TeamPlannerComponent extends UntilDestroyedMixin implements OnInit, private wpTableFilters:WorkPackageViewFiltersService, private querySpace:IsolatedQuerySpace, private currentProject:CurrentProjectService, - private viewLookup:EventViewLookupService, private I18n:I18nService, readonly injector:Injector, readonly calendar:OpCalendarService, @@ -602,7 +584,7 @@ export class TeamPlannerComponent extends UntilDestroyedMixin implements OnInit, ([workPackages, projectAssignables]) => { const events = this.mapToCalendarEvents(workPackages.elements, projectAssignables); - this.viewLookup.destroyDetached(); + this.workPackagesCalendar.warnOnTooManyResults(workPackages); this.removeExternalEvents(); diff --git a/frontend/src/app/features/work-packages/components/wp-card-view/wp-single-card/wp-single-card.component.html b/frontend/src/app/features/work-packages/components/wp-card-view/wp-single-card/wp-single-card.component.html index 805f68ea95b7..57a000ef47b6 100644 --- a/frontend/src/app/features/work-packages/components/wp-card-view/wp-single-card/wp-single-card.component.html +++ b/frontend/src/app/features/work-packages/components/wp-card-view/wp-single-card/wp-single-card.component.html @@ -52,20 +52,20 @@ *ngIf="isNewResource(workPackage)"> + [wrapperClasses]="'work-packages--type-selector'" + [fieldName]="'type'" + class="op-wp-single-card-content--type"> + fieldName="subject" + class="op-wp-single-card-content--subject -bold"> - + - {{startDate(workPackage)}} - +diff --git a/frontend/src/app/features/work-packages/components/wp-card-view/wp-single-card/wp-single-card.component.ts b/frontend/src/app/features/work-packages/components/wp-card-view/wp-single-card/wp-single-card.component.ts index 7b6195bef3ad..d204c5f31b41 100644 --- a/frontend/src/app/features/work-packages/components/wp-card-view/wp-single-card/wp-single-card.component.ts +++ b/frontend/src/app/features/work-packages/components/wp-card-view/wp-single-card/wp-single-card.component.ts @@ -7,20 +7,29 @@ import { OnInit, Output, } from '@angular/core'; -import { uiStateLinkClass } from 'core-app/features/work-packages/components/wp-fast-table/builders/ui-state-link-builder'; +import { + uiStateLinkClass, +} from 'core-app/features/work-packages/components/wp-fast-table/builders/ui-state-link-builder'; import { PathHelperService } from 'core-app/core/path-helper/path-helper.service'; -import { Highlighting } from 'core-app/features/work-packages/components/wp-fast-table/builders/highlighting/highlighting.functions'; import { - StateService, - UIRouterGlobals, -} from '@uirouter/core'; -import { WorkPackageViewSelectionService } from 'core-app/features/work-packages/routing/wp-view-base/view-services/wp-view-selection.service'; -import { WorkPackageCardViewService } from 'core-app/features/work-packages/components/wp-card-view/services/wp-card-view.service'; + Highlighting, +} from 'core-app/features/work-packages/components/wp-fast-table/builders/highlighting/highlighting.functions'; +import { StateService, UIRouterGlobals } from '@uirouter/core'; +import { + WorkPackageViewSelectionService, +} from 'core-app/features/work-packages/routing/wp-view-base/view-services/wp-view-selection.service'; +import { + WorkPackageCardViewService, +} from 'core-app/features/work-packages/components/wp-card-view/services/wp-card-view.service'; import { I18nService } from 'core-app/core/i18n/i18n.service'; -import { CardHighlightingMode } from 'core-app/features/work-packages/components/wp-fast-table/builders/highlighting/highlighting-mode.const'; +import { + CardHighlightingMode, +} from 'core-app/features/work-packages/components/wp-fast-table/builders/highlighting/highlighting-mode.const'; import { CardViewOrientation } from 'core-app/features/work-packages/components/wp-card-view/wp-card-view.component'; import { UntilDestroyedMixin } from 'core-app/shared/helpers/angular/until-destroyed.mixin'; -import { WorkPackageViewFocusService } from 'core-app/features/work-packages/routing/wp-view-base/view-services/wp-view-focus.service'; +import { + WorkPackageViewFocusService, +} from 'core-app/features/work-packages/routing/wp-view-base/view-services/wp-view-focus.service'; import { WorkPackageResource } from 'core-app/features/hal/resources/work-package-resource'; import { isClickedWithModifier } from 'core-app/shared/helpers/link-handling/link-handling'; import isNewResource from 'core-app/features/hal/helpers/is-new-resource'; @@ -30,9 +39,10 @@ import { combineLatest } from 'rxjs'; import { map } from 'rxjs/operators'; import { SchemaCacheService } from 'core-app/core/schemas/schema-cache.service'; import SpotDropAlignmentOption from 'core-app/spot/drop-alignment-options'; +import { getBaselineState } from 'core-app/features/work-packages/components/wp-baseline/baseline-helpers'; import { - getBaselineState, -} from 'core-app/features/work-packages/components/wp-baseline/baseline-helpers'; + CombinedDateDisplayField, +} from 'core-app/shared/components/fields/display/field-types/combined-date-display.field'; @Component({ selector: 'wp-single-card', @@ -99,16 +109,7 @@ export class WorkPackageSingleCardComponent extends UntilDestroyedMixin implemen public tooltipPosition = SpotDropAlignmentOption.BottomLeft; - private dateTimeFormatYear = new Intl.DateTimeFormat(this.I18n.locale, { - year: 'numeric', - month: 'short', - day: 'numeric', - }); - - private dateTimeFormat = new Intl.DateTimeFormat(this.I18n.locale, { - month: 'short', - day: 'numeric', - }); + combinedDateDisplayField = CombinedDateDisplayField; constructor( readonly pathHelper:PathHelperService, @@ -206,50 +207,6 @@ export class WorkPackageSingleCardComponent extends UntilDestroyedMixin implemen return wp.project?.name; } - public wpDates(wp:WorkPackageResource):string { - const { startDate, dueDate } = wp; - - if (startDate && dueDate) { - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore see https://github.com/microsoft/TypeScript/issues/46905 - // eslint-disable-next-line @typescript-eslint/no-unsafe-call - return String(this.dateTimeFormatYear.formatRange(new Date(startDate), new Date(dueDate))); - } - - if (!startDate && dueDate) { - return `– ${this.dateTimeFormatYear.format(new Date(dueDate))}`; - } - - if (startDate && !dueDate) { - return `${this.dateTimeFormatYear.format(new Date(startDate))} –`; - } - - return ''; - } - - startDate(wp:WorkPackageResource):string { - const { startDate } = wp; - if (!startDate) { - return ''; - } - - return this.dateTimeFormat.format(new Date(startDate)); - } - - endDate(wp:WorkPackageResource):string { - const { dueDate } = wp; - if (!dueDate) { - return ''; - } - - return this.dateTimeFormat.format(new Date(dueDate)); - } - - wpOverDueHighlighting(wp:WorkPackageResource):string { - const diff = this.timezoneService.daysFromToday(wp.dueDate); - return Highlighting.overdueDate(diff); - } - public fullWorkPackageLink(wp:WorkPackageResource):string { return this.$state.href('work-packages.show', { workPackageId: wp.id }); } diff --git a/frontend/src/app/features/work-packages/components/wp-custom-actions/wp-custom-actions/wp-custom-action.component.ts b/frontend/src/app/features/work-packages/components/wp-custom-actions/wp-custom-actions/wp-custom-action.component.ts index fb9cd88bfb47..a126f6360cb4 100644 --- a/frontend/src/app/features/work-packages/components/wp-custom-actions/wp-custom-actions/wp-custom-action.component.ts +++ b/frontend/src/app/features/work-packages/components/wp-custom-actions/wp-custom-actions/wp-custom-action.component.ts @@ -26,26 +26,30 @@ // See COPYRIGHT and LICENSE files for more details. //++ -import { - ChangeDetectionStrategy, Component, HostListener, Input, -} from '@angular/core'; +import { ChangeDetectionStrategy, ChangeDetectorRef, Component, HostListener, Input, OnInit } from '@angular/core'; import { ApiV3Service } from 'core-app/core/apiv3/api-v3.service'; import { CustomActionResource } from 'core-app/features/hal/resources/custom-action-resource'; import { HalEventsService } from 'core-app/features/hal/services/hal-events.service'; -import { HalResourceEditingService } from 'core-app/shared/components/fields/edit/services/hal-resource-editing.service'; +import { + HalResourceEditingService, +} from 'core-app/shared/components/fields/edit/services/hal-resource-editing.service'; import { HalResourceService } from 'core-app/features/hal/services/hal-resource.service'; import { ResourceChangeset } from 'core-app/shared/components/fields/changeset/resource-changeset'; -import { SchemaCacheService } from 'core-app/core/schemas/schema-cache.service'; -import { WorkPackageNotificationService } from 'core-app/features/work-packages/services/notifications/work-package-notification.service'; +import { + WorkPackageNotificationService, +} from 'core-app/features/work-packages/services/notifications/work-package-notification.service'; import { WorkPackageResource } from 'core-app/features/hal/resources/work-package-resource'; -import { WorkPackagesActivityService } from 'core-app/features/work-packages/components/wp-single-view-tabs/activity-panel/wp-activity.service'; +import { + WorkPackagesActivityService, +} from 'core-app/features/work-packages/components/wp-single-view-tabs/activity-panel/wp-activity.service'; +import { UntilDestroyedMixin } from 'core-app/shared/helpers/angular/until-destroyed.mixin'; @Component({ selector: 'wp-custom-action', templateUrl: './wp-custom-action.component.html', changeDetection: ChangeDetectionStrategy.OnPush, }) -export class WpCustomActionComponent { +export class WpCustomActionComponent extends UntilDestroyedMixin implements OnInit { @Input() workPackage:WorkPackageResource; @Input() action:CustomActionResource; @@ -53,12 +57,23 @@ export class WpCustomActionComponent { constructor( private halResourceService:HalResourceService, private apiV3Service:ApiV3Service, - private wpSchemaCacheService:SchemaCacheService, private wpActivity:WorkPackagesActivityService, private notificationService:WorkPackageNotificationService, private halEditing:HalResourceEditingService, private halEvents:HalEventsService, + private cdRef:ChangeDetectorRef, ) { + super(); + } + + ngOnInit() { + this + .halEvents + .events$ + .pipe( + this.untilDestroyed(), + ) + .subscribe(() => this.cdRef.detectChanges()); } private fetchAction() { @@ -103,11 +118,13 @@ export class WpCustomActionComponent { this.halEditing.stopEditing(savedWp); this.halEvents.push(savedWp, { eventType: 'updated' }); this.change.inFlight = false; + this.cdRef.detectChanges(); }); }, (errorResource) => { this.notificationService.handleRawError(errorResource, this.workPackage); this.change.inFlight = false; + this.cdRef.detectChanges(); }, ); } diff --git a/frontend/src/app/features/work-packages/routing/partitioned-query-space-page/partitioned-query-space-page.component.ts b/frontend/src/app/features/work-packages/routing/partitioned-query-space-page/partitioned-query-space-page.component.ts index 4448c227d72e..604f03ad9a27 100644 --- a/frontend/src/app/features/work-packages/routing/partitioned-query-space-page/partitioned-query-space-page.component.ts +++ b/frontend/src/app/features/work-packages/routing/partitioned-query-space-page/partitioned-query-space-page.component.ts @@ -218,7 +218,10 @@ export class PartitionedQuerySpacePageComponent extends WorkPackagesViewBase imp this.currentQuery!.name = val; this.wpListService .save(this.currentQuery) - .finally(() => { this.toolbarDisabled = false; }); + .finally(() => { + this.toolbarDisabled = false; + this.cdRef.detectChanges(); + }); } updateTitle(query?:QueryResource):void { diff --git a/frontend/src/app/shared/components/fields/display/display-field.component.ts b/frontend/src/app/shared/components/fields/display/display-field.component.ts index 4994cbdeb1ee..d6509e3ba8e3 100644 --- a/frontend/src/app/shared/components/fields/display/display-field.component.ts +++ b/frontend/src/app/shared/components/fields/display/display-field.component.ts @@ -1,18 +1,11 @@ -import { - ChangeDetectionStrategy, - Component, - ElementRef, - Injector, - Input, - OnInit, - ViewChild, -} from '@angular/core'; +import { ChangeDetectionStrategy, Component, ElementRef, Injector, Input, OnInit, ViewChild } from '@angular/core'; import { IFieldSchema } from 'core-app/shared/components/fields/field.base'; import { DisplayFieldService } from 'core-app/shared/components/fields/display/display-field.service'; import { HalResource } from 'core-app/features/hal/resources/hal-resource'; import { SchemaCacheService } from 'core-app/core/schemas/schema-cache.service'; import { Constructor } from '@angular/cdk/table'; import { DisplayField } from 'core-app/shared/components/fields/display/display-field.module'; +import { SchemaResource } from 'core-app/features/hal/resources/schema-resource'; @Component({ selector: 'display-field', @@ -32,16 +25,20 @@ export class DisplayFieldComponent implements OnInit { @ViewChild('displayFieldContainer') container:ElementRef+ + - - - {{endDate(workPackage)}} + - ++ @@ -118,7 +130,7 @@ [workPackage]="workPackage" [small]="true" class="op-wp-single-card--content-status" - > + > - - + containerType="single-view"> +; - constructor(private injector:Injector, + constructor( + private injector:Injector, private displayFieldService:DisplayFieldService, - private schemaCache:SchemaCacheService) { + private schemaCache:SchemaCacheService, + ) { } ngOnInit():void { void this.schemaCache .ensureLoaded(this.resource) .then((schema) => { - this.render(schema[this.fieldName]); + const proxied = this.schemaCache.proxied(this.resource, schema); + this.fieldName = this.attributeName(this.fieldName, proxied); + this.render(proxied[this.fieldName] as IFieldSchema); }); } @@ -76,6 +73,15 @@ export class DisplayFieldComponent implements OnInit { ); } + private attributeName(attribute:string, schema:SchemaResource):string { + if (schema.mappedName) { + // eslint-disable-next-line @typescript-eslint/no-unsafe-call + return schema.mappedName(attribute) as string; + } + + return attribute; + } + private get displayFieldContext() { return { injector: this.injector, container: this.containerType, options: this.displayFieldOptions }; } diff --git a/frontend/src/app/shared/components/fields/display/field-types/combined-date-display.field.ts b/frontend/src/app/shared/components/fields/display/field-types/combined-date-display.field.ts index d169a99fc2d3..da2d111e9eb2 100644 --- a/frontend/src/app/shared/components/fields/display/field-types/combined-date-display.field.ts +++ b/frontend/src/app/shared/components/fields/display/field-types/combined-date-display.field.ts @@ -33,10 +33,60 @@ export class CombinedDateDisplayField extends DateDisplayField { placeholder: { startDate: this.I18n.t('js.label_no_start_date'), dueDate: this.I18n.t('js.label_no_due_date'), + date: this.I18n.t('js.label_no_date'), }, }; - public render(element:HTMLElement, displayText:string):void { + public render(element:HTMLElement):void { + if (this.name === 'date') { + this.renderSingleDate('date', element); + return; + } + + if (this.startDate && (this.startDate === this.dueDate)) { + this.renderSingleDate('dueDate', element); + return; + } + + if (!this.startDate && !this.dueDate) { + element.innerHTML = this.customPlaceholder(`${this.text.placeholder.startDate} - ${this.text.placeholder.dueDate}`); + return; + } + + this.renderDates(element); + } + + isEmpty():boolean { + return false; + } + + customPlaceholder(fallback:string):string { + if (typeof this.context.options.placeholder === 'string') { + return this.context.options.placeholder; + } + + return fallback; + } + + private get startDate():string|null { + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access,@typescript-eslint/no-unsafe-return + return this.resource.startDate; + } + + private get dueDate():string|null { + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access,@typescript-eslint/no-unsafe-return + return this.resource.dueDate; + } + + private renderSingleDate(field:'date'|'startDate'|'dueDate', element:HTMLElement):void { + element.innerHTML = ''; + + const dateElement = this.createDateDisplayField(field); + + element.appendChild(dateElement); + } + + private renderDates(element:HTMLElement):void { element.innerHTML = ''; const startDateElement = this.createDateDisplayField('startDate'); @@ -50,14 +100,15 @@ export class CombinedDateDisplayField extends DateDisplayField { element.appendChild(dueDateElement); } - private createDateDisplayField(date:'dueDate'|'startDate'):HTMLElement { + private createDateDisplayField(date:'dueDate'|'startDate'|'date'):HTMLElement { const dateElement = document.createElement('span'); const dateDisplayField = new DateDisplayField(date, this.context); - const text = this.resource[date] - ? this.timezoneService.formattedDate(this.resource[date]) - : this.text.placeholder[date]; - dateDisplayField.apply(this.resource, this.schema); + + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + const text = this.resource[date] + ? dateDisplayField.valueString + : this.customPlaceholder(this.text.placeholder[date]); dateDisplayField.render(dateElement, text); return dateElement; diff --git a/frontend/src/app/shared/components/fields/display/field-types/date-display-field.module.ts b/frontend/src/app/shared/components/fields/display/field-types/date-display-field.module.ts index cbe798e1a3f9..01640ccb2fcf 100644 --- a/frontend/src/app/shared/components/fields/display/field-types/date-display-field.module.ts +++ b/frontend/src/app/shared/components/fields/display/field-types/date-display-field.module.ts @@ -26,8 +26,12 @@ // See COPYRIGHT and LICENSE files for more details. //++ -import { Highlighting } from 'core-app/features/work-packages/components/wp-fast-table/builders/highlighting/highlighting.functions'; -import { HighlightableDisplayField } from 'core-app/shared/components/fields/display/field-types/highlightable-display-field.module'; +import { + Highlighting, +} from 'core-app/features/work-packages/components/wp-fast-table/builders/highlighting/highlighting.functions'; +import { + HighlightableDisplayField, +} from 'core-app/shared/components/fields/display/field-types/highlightable-display-field.module'; import { InjectField } from 'core-app/shared/helpers/angular/inject-field.decorator'; import { ApiV3Service } from 'core-app/core/apiv3/api-v3.service'; import { TimezoneService } from 'core-app/core/datetime/timezone.service'; @@ -75,7 +79,8 @@ export class DateDisplayField extends HighlightableDisplayField { public get valueString() { if (this.value) { - return this.timezoneService.formattedDate(this.value); + // eslint-disable-next-line @typescript-eslint/no-unsafe-argument + return this.timezoneService.formattedDate(this.value, this.context.options.dateFormat); } return ''; } diff --git a/frontend/src/app/shared/components/fields/openproject-fields.module.ts b/frontend/src/app/shared/components/fields/openproject-fields.module.ts index 093e3e21cc1e..bbb87b76de54 100644 --- a/frontend/src/app/shared/components/fields/openproject-fields.module.ts +++ b/frontend/src/app/shared/components/fields/openproject-fields.module.ts @@ -131,6 +131,7 @@ import { FormsModule } from '@angular/forms'; EditFormPortalComponent, EditFormComponent, EditableAttributeFieldComponent, + DisplayFieldComponent, ], providers: [ { diff --git a/frontend/src/app/shared/components/op-context-menu/handlers/op-types-context-menu.directive.ts b/frontend/src/app/shared/components/op-context-menu/handlers/op-types-context-menu.directive.ts index 70645e47e6d6..fd3bcc55392a 100644 --- a/frontend/src/app/shared/components/op-context-menu/handlers/op-types-context-menu.directive.ts +++ b/frontend/src/app/shared/components/op-context-menu/handlers/op-types-context-menu.directive.ts @@ -31,10 +31,14 @@ import { StateService } from '@uirouter/core'; import { OPContextMenuService } from 'core-app/shared/components/op-context-menu/op-context-menu.service'; import { Directive, ElementRef, Input } from '@angular/core'; import { isClickedWithModifier } from 'core-app/shared/helpers/link-handling/link-handling'; -import { OpContextMenuTrigger } from 'core-app/shared/components/op-context-menu/handlers/op-context-menu-trigger.directive'; +import { + OpContextMenuTrigger, +} from 'core-app/shared/components/op-context-menu/handlers/op-context-menu-trigger.directive'; import { BrowserDetector } from 'core-app/core/browser/browser-detector.service'; import { WorkPackageCreateService } from 'core-app/features/work-packages/components/wp-new/wp-create.service'; -import { Highlighting } from 'core-app/features/work-packages/components/wp-fast-table/builders/highlighting/highlighting.functions'; +import { + Highlighting, +} from 'core-app/features/work-packages/components/wp-fast-table/builders/highlighting/highlighting.functions'; import { TypeResource } from 'core-app/features/hal/resources/type-resource'; @Directive({ @@ -88,6 +92,11 @@ export class OpTypesContextMenuDirective extends OpContextMenuTrigger { } } + onClose(focus:boolean = false) { + this.isOpen = false; + super.onClose(focus); + } + public get locals():{ showAnchorRight?:boolean, contextMenuId?:string, items:OpContextMenuItem[] } { return { items: this.items, diff --git a/frontend/src/app/shared/components/sidemenu/sidemenu.component.html b/frontend/src/app/shared/components/sidemenu/sidemenu.component.html index 6885c55128cf..b7d527fc23c2 100644 --- a/frontend/src/app/shared/components/sidemenu/sidemenu.component.html +++ b/frontend/src/app/shared/components/sidemenu/sidemenu.component.html @@ -73,7 +73,7 @@ {{ item.count }} ` element. - */ -class CodeEditing extends ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__.Plugin { - /** - * @inheritDoc - */ - static get pluginName() { - return 'CodeEditing'; - } - /** - * @inheritDoc - */ - static get requires() { - return [ckeditor5_src_typing__WEBPACK_IMPORTED_MODULE_1__.TwoStepCaretMovement]; - } - /** - * @inheritDoc - */ - init() { - const editor = this.editor; - // Allow code attribute on text nodes. - editor.model.schema.extend('$text', { allowAttributes: CODE }); - editor.model.schema.setAttributeProperties(CODE, { - isFormatting: true, - copyOnEnter: false - }); - editor.conversion.attributeToElement({ - model: CODE, - view: 'code', - upcastAlso: { - styles: { - 'word-wrap': 'break-word' - } - } - }); - // Create code command. - editor.commands.add(CODE, new _attributecommand__WEBPACK_IMPORTED_MODULE_2__["default"](editor, CODE)); - // Enable two-step caret movement for `code` attribute. - editor.plugins.get(ckeditor5_src_typing__WEBPACK_IMPORTED_MODULE_1__.TwoStepCaretMovement).registerAttribute(CODE); - // Setup highlight over selected element. - (0,ckeditor5_src_typing__WEBPACK_IMPORTED_MODULE_1__.inlineHighlight)(editor, CODE, 'code', HIGHLIGHT_CLASS); - } -} - - -/***/ }), - -/***/ "./node_modules/@ckeditor/ckeditor5-basic-styles/src/code/codeui.js": -/*!**************************************************************************!*\ - !*** ./node_modules/@ckeditor/ckeditor5-basic-styles/src/code/codeui.js ***! - \**************************************************************************/ -/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { - -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export */ __webpack_require__.d(__webpack_exports__, { -/* harmony export */ "default": () => (/* binding */ CodeUI) -/* harmony export */ }); -/* harmony import */ var ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ckeditor5/src/core */ "./node_modules/ckeditor5/src/core.js"); -/* harmony import */ var ckeditor5_src_ui__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ckeditor5/src/ui */ "./node_modules/ckeditor5/src/ui.js"); -/* harmony import */ var _theme_icons_code_svg__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../../theme/icons/code.svg */ "./node_modules/@ckeditor/ckeditor5-basic-styles/theme/icons/code.svg"); -/* harmony import */ var _theme_code_css__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../../theme/code.css */ "./node_modules/@ckeditor/ckeditor5-basic-styles/theme/code.css"); -/** - * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved. - * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license - */ -/** - * @module basic-styles/code/codeui - */ - - - - -const CODE = 'code'; -/** - * The code UI feature. It introduces the Code button. - */ -class CodeUI extends ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__.Plugin { - /** - * @inheritDoc - */ - static get pluginName() { - return 'CodeUI'; - } - /** - * @inheritDoc - */ - init() { - const editor = this.editor; - const t = editor.t; - // Add code button to feature components. - editor.ui.componentFactory.add(CODE, locale => { - const command = editor.commands.get(CODE); - const view = new ckeditor5_src_ui__WEBPACK_IMPORTED_MODULE_1__.ButtonView(locale); - view.set({ - label: t('Code'), - icon: _theme_icons_code_svg__WEBPACK_IMPORTED_MODULE_2__["default"], - tooltip: true, - isToggleable: true - }); - view.bind('isOn', 'isEnabled').to(command, 'value', 'isEnabled'); - // Execute command. - this.listenTo(view, 'execute', () => { - editor.execute(CODE); - editor.editing.view.focus(); - }); - return view; - }); - } -} - - -/***/ }), - -/***/ "./node_modules/@ckeditor/ckeditor5-basic-styles/src/index.js": -/*!********************************************************************!*\ - !*** ./node_modules/@ckeditor/ckeditor5-basic-styles/src/index.js ***! - \********************************************************************/ -/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { - -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export */ __webpack_require__.d(__webpack_exports__, { -/* harmony export */ Bold: () => (/* reexport safe */ _bold__WEBPACK_IMPORTED_MODULE_0__["default"]), -/* harmony export */ BoldEditing: () => (/* reexport safe */ _bold_boldediting__WEBPACK_IMPORTED_MODULE_1__["default"]), -/* harmony export */ BoldUI: () => (/* reexport safe */ _bold_boldui__WEBPACK_IMPORTED_MODULE_2__["default"]), -/* harmony export */ Code: () => (/* reexport safe */ _code__WEBPACK_IMPORTED_MODULE_3__["default"]), -/* harmony export */ CodeEditing: () => (/* reexport safe */ _code_codeediting__WEBPACK_IMPORTED_MODULE_4__["default"]), -/* harmony export */ CodeUI: () => (/* reexport safe */ _code_codeui__WEBPACK_IMPORTED_MODULE_5__["default"]), -/* harmony export */ Italic: () => (/* reexport safe */ _italic__WEBPACK_IMPORTED_MODULE_6__["default"]), -/* harmony export */ ItalicEditing: () => (/* reexport safe */ _italic_italicediting__WEBPACK_IMPORTED_MODULE_7__["default"]), -/* harmony export */ ItalicUI: () => (/* reexport safe */ _italic_italicui__WEBPACK_IMPORTED_MODULE_8__["default"]), -/* harmony export */ Strikethrough: () => (/* reexport safe */ _strikethrough__WEBPACK_IMPORTED_MODULE_9__["default"]), -/* harmony export */ StrikethroughEditing: () => (/* reexport safe */ _strikethrough_strikethroughediting__WEBPACK_IMPORTED_MODULE_10__["default"]), -/* harmony export */ StrikethroughUI: () => (/* reexport safe */ _strikethrough_strikethroughui__WEBPACK_IMPORTED_MODULE_11__["default"]), -/* harmony export */ Subscript: () => (/* reexport safe */ _subscript__WEBPACK_IMPORTED_MODULE_12__["default"]), -/* harmony export */ SubscriptEditing: () => (/* reexport safe */ _subscript_subscriptediting__WEBPACK_IMPORTED_MODULE_13__["default"]), -/* harmony export */ SubscriptUI: () => (/* reexport safe */ _subscript_subscriptui__WEBPACK_IMPORTED_MODULE_14__["default"]), -/* harmony export */ Superscript: () => (/* reexport safe */ _superscript__WEBPACK_IMPORTED_MODULE_15__["default"]), -/* harmony export */ SuperscriptEditing: () => (/* reexport safe */ _superscript_superscriptediting__WEBPACK_IMPORTED_MODULE_16__["default"]), -/* harmony export */ SuperscriptUI: () => (/* reexport safe */ _superscript_superscriptui__WEBPACK_IMPORTED_MODULE_17__["default"]), -/* harmony export */ Underline: () => (/* reexport safe */ _underline__WEBPACK_IMPORTED_MODULE_18__["default"]), -/* harmony export */ UnderlineEditing: () => (/* reexport safe */ _underline_underlineediting__WEBPACK_IMPORTED_MODULE_19__["default"]), -/* harmony export */ UnderlineUI: () => (/* reexport safe */ _underline_underlineui__WEBPACK_IMPORTED_MODULE_20__["default"]) -/* harmony export */ }); -/* harmony import */ var _bold__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./bold */ "./node_modules/@ckeditor/ckeditor5-basic-styles/src/bold.js"); -/* harmony import */ var _bold_boldediting__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./bold/boldediting */ "./node_modules/@ckeditor/ckeditor5-basic-styles/src/bold/boldediting.js"); -/* harmony import */ var _bold_boldui__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./bold/boldui */ "./node_modules/@ckeditor/ckeditor5-basic-styles/src/bold/boldui.js"); -/* harmony import */ var _code__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./code */ "./node_modules/@ckeditor/ckeditor5-basic-styles/src/code.js"); -/* harmony import */ var _code_codeediting__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./code/codeediting */ "./node_modules/@ckeditor/ckeditor5-basic-styles/src/code/codeediting.js"); -/* harmony import */ var _code_codeui__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./code/codeui */ "./node_modules/@ckeditor/ckeditor5-basic-styles/src/code/codeui.js"); -/* harmony import */ var _italic__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./italic */ "./node_modules/@ckeditor/ckeditor5-basic-styles/src/italic.js"); -/* harmony import */ var _italic_italicediting__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./italic/italicediting */ "./node_modules/@ckeditor/ckeditor5-basic-styles/src/italic/italicediting.js"); -/* harmony import */ var _italic_italicui__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./italic/italicui */ "./node_modules/@ckeditor/ckeditor5-basic-styles/src/italic/italicui.js"); -/* harmony import */ var _strikethrough__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ./strikethrough */ "./node_modules/@ckeditor/ckeditor5-basic-styles/src/strikethrough.js"); -/* harmony import */ var _strikethrough_strikethroughediting__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ./strikethrough/strikethroughediting */ "./node_modules/@ckeditor/ckeditor5-basic-styles/src/strikethrough/strikethroughediting.js"); -/* harmony import */ var _strikethrough_strikethroughui__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ./strikethrough/strikethroughui */ "./node_modules/@ckeditor/ckeditor5-basic-styles/src/strikethrough/strikethroughui.js"); -/* harmony import */ var _subscript__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ./subscript */ "./node_modules/@ckeditor/ckeditor5-basic-styles/src/subscript.js"); -/* harmony import */ var _subscript_subscriptediting__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! ./subscript/subscriptediting */ "./node_modules/@ckeditor/ckeditor5-basic-styles/src/subscript/subscriptediting.js"); -/* harmony import */ var _subscript_subscriptui__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! ./subscript/subscriptui */ "./node_modules/@ckeditor/ckeditor5-basic-styles/src/subscript/subscriptui.js"); -/* harmony import */ var _superscript__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! ./superscript */ "./node_modules/@ckeditor/ckeditor5-basic-styles/src/superscript.js"); -/* harmony import */ var _superscript_superscriptediting__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(/*! ./superscript/superscriptediting */ "./node_modules/@ckeditor/ckeditor5-basic-styles/src/superscript/superscriptediting.js"); -/* harmony import */ var _superscript_superscriptui__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(/*! ./superscript/superscriptui */ "./node_modules/@ckeditor/ckeditor5-basic-styles/src/superscript/superscriptui.js"); -/* harmony import */ var _underline__WEBPACK_IMPORTED_MODULE_18__ = __webpack_require__(/*! ./underline */ "./node_modules/@ckeditor/ckeditor5-basic-styles/src/underline.js"); -/* harmony import */ var _underline_underlineediting__WEBPACK_IMPORTED_MODULE_19__ = __webpack_require__(/*! ./underline/underlineediting */ "./node_modules/@ckeditor/ckeditor5-basic-styles/src/underline/underlineediting.js"); -/* harmony import */ var _underline_underlineui__WEBPACK_IMPORTED_MODULE_20__ = __webpack_require__(/*! ./underline/underlineui */ "./node_modules/@ckeditor/ckeditor5-basic-styles/src/underline/underlineui.js"); -/* harmony import */ var _augmentation__WEBPACK_IMPORTED_MODULE_21__ = __webpack_require__(/*! ./augmentation */ "./node_modules/@ckeditor/ckeditor5-basic-styles/src/augmentation.js"); -/** - * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved. - * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license - */ -/** - * @module basic-styles - */ - - - - - - - - - - - - - - - - - - - - - - - - -/***/ }), - -/***/ "./node_modules/@ckeditor/ckeditor5-basic-styles/src/italic.js": -/*!*********************************************************************!*\ - !*** ./node_modules/@ckeditor/ckeditor5-basic-styles/src/italic.js ***! - \*********************************************************************/ -/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { - -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export */ __webpack_require__.d(__webpack_exports__, { -/* harmony export */ "default": () => (/* binding */ Italic) -/* harmony export */ }); -/* harmony import */ var ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ckeditor5/src/core */ "./node_modules/ckeditor5/src/core.js"); -/* harmony import */ var _italic_italicediting__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./italic/italicediting */ "./node_modules/@ckeditor/ckeditor5-basic-styles/src/italic/italicediting.js"); -/* harmony import */ var _italic_italicui__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./italic/italicui */ "./node_modules/@ckeditor/ckeditor5-basic-styles/src/italic/italicui.js"); -/** - * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved. - * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license - */ -/** - * @module basic-styles/italic - */ - - - -/** - * The italic feature. - * - * For a detailed overview check the {@glink features/basic-styles Basic styles feature} guide - * and the {@glink api/basic-styles package page}. - * - * This is a "glue" plugin which loads the {@link module:basic-styles/italic/italicediting~ItalicEditing} and - * {@link module:basic-styles/italic/italicui~ItalicUI} plugins. - */ -class Italic extends ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__.Plugin { - /** - * @inheritDoc - */ - static get requires() { - return [_italic_italicediting__WEBPACK_IMPORTED_MODULE_1__["default"], _italic_italicui__WEBPACK_IMPORTED_MODULE_2__["default"]]; - } - /** - * @inheritDoc - */ - static get pluginName() { - return 'Italic'; - } -} - - -/***/ }), - -/***/ "./node_modules/@ckeditor/ckeditor5-basic-styles/src/italic/italicediting.js": -/*!***********************************************************************************!*\ - !*** ./node_modules/@ckeditor/ckeditor5-basic-styles/src/italic/italicediting.js ***! - \***********************************************************************************/ -/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { - -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export */ __webpack_require__.d(__webpack_exports__, { -/* harmony export */ "default": () => (/* binding */ ItalicEditing) -/* harmony export */ }); -/* harmony import */ var ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ckeditor5/src/core */ "./node_modules/ckeditor5/src/core.js"); -/* harmony import */ var _attributecommand__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../attributecommand */ "./node_modules/@ckeditor/ckeditor5-basic-styles/src/attributecommand.js"); -/** - * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved. - * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license - */ -/** - * @module basic-styles/italic/italicediting - */ - - -const ITALIC = 'italic'; -/** - * The italic editing feature. - * - * It registers the `'italic'` command, the Ctrl+I keystroke and introduces the `italic` attribute in the model - * which renders to the view as an `` element. - */ -class ItalicEditing extends ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__.Plugin { - /** - * @inheritDoc - */ - static get pluginName() { - return 'ItalicEditing'; - } - /** - * @inheritDoc - */ - init() { - const editor = this.editor; - // Allow italic attribute on text nodes. - editor.model.schema.extend('$text', { allowAttributes: ITALIC }); - editor.model.schema.setAttributeProperties(ITALIC, { - isFormatting: true, - copyOnEnter: true - }); - editor.conversion.attributeToElement({ - model: ITALIC, - view: 'i', - upcastAlso: [ - 'em', - { - styles: { - 'font-style': 'italic' - } - } - ] - }); - // Create italic command. - editor.commands.add(ITALIC, new _attributecommand__WEBPACK_IMPORTED_MODULE_1__["default"](editor, ITALIC)); - // Set the Ctrl+I keystroke. - editor.keystrokes.set('CTRL+I', ITALIC); - } -} - - -/***/ }), - -/***/ "./node_modules/@ckeditor/ckeditor5-basic-styles/src/italic/italicui.js": -/*!******************************************************************************!*\ - !*** ./node_modules/@ckeditor/ckeditor5-basic-styles/src/italic/italicui.js ***! - \******************************************************************************/ -/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { - -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export */ __webpack_require__.d(__webpack_exports__, { -/* harmony export */ "default": () => (/* binding */ ItalicUI) -/* harmony export */ }); -/* harmony import */ var ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ckeditor5/src/core */ "./node_modules/ckeditor5/src/core.js"); -/* harmony import */ var ckeditor5_src_ui__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ckeditor5/src/ui */ "./node_modules/ckeditor5/src/ui.js"); -/* harmony import */ var _theme_icons_italic_svg__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../../theme/icons/italic.svg */ "./node_modules/@ckeditor/ckeditor5-basic-styles/theme/icons/italic.svg"); -/** - * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved. - * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license - */ -/** - * @module basic-styles/italic/italicui - */ - - - -const ITALIC = 'italic'; -/** - * The italic UI feature. It introduces the Italic button. - */ -class ItalicUI extends ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__.Plugin { - /** - * @inheritDoc - */ - static get pluginName() { - return 'ItalicUI'; - } - /** - * @inheritDoc - */ - init() { - const editor = this.editor; - const t = editor.t; - // Add bold button to feature components. - editor.ui.componentFactory.add(ITALIC, locale => { - const command = editor.commands.get(ITALIC); - const view = new ckeditor5_src_ui__WEBPACK_IMPORTED_MODULE_1__.ButtonView(locale); - view.set({ - label: t('Italic'), - icon: _theme_icons_italic_svg__WEBPACK_IMPORTED_MODULE_2__["default"], - keystroke: 'CTRL+I', - tooltip: true, - isToggleable: true - }); - view.bind('isOn', 'isEnabled').to(command, 'value', 'isEnabled'); - // Execute command. - this.listenTo(view, 'execute', () => { - editor.execute(ITALIC); - editor.editing.view.focus(); - }); - return view; - }); - } -} - - -/***/ }), - -/***/ "./node_modules/@ckeditor/ckeditor5-basic-styles/src/strikethrough.js": -/*!****************************************************************************!*\ - !*** ./node_modules/@ckeditor/ckeditor5-basic-styles/src/strikethrough.js ***! - \****************************************************************************/ -/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { - -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export */ __webpack_require__.d(__webpack_exports__, { -/* harmony export */ "default": () => (/* binding */ Strikethrough) -/* harmony export */ }); -/* harmony import */ var ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ckeditor5/src/core */ "./node_modules/ckeditor5/src/core.js"); -/* harmony import */ var _strikethrough_strikethroughediting__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./strikethrough/strikethroughediting */ "./node_modules/@ckeditor/ckeditor5-basic-styles/src/strikethrough/strikethroughediting.js"); -/* harmony import */ var _strikethrough_strikethroughui__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./strikethrough/strikethroughui */ "./node_modules/@ckeditor/ckeditor5-basic-styles/src/strikethrough/strikethroughui.js"); -/** - * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved. - * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license - */ -/** - * @module basic-styles/strikethrough - */ - - - -/** - * The strikethrough feature. - * - * For a detailed overview check the {@glink features/basic-styles Basic styles feature} guide - * and the {@glink api/basic-styles package page}. - * - * This is a "glue" plugin which loads the {@link module:basic-styles/strikethrough/strikethroughediting~StrikethroughEditing} and - * {@link module:basic-styles/strikethrough/strikethroughui~StrikethroughUI} plugins. - */ -class Strikethrough extends ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__.Plugin { - /** - * @inheritDoc - */ - static get requires() { - return [_strikethrough_strikethroughediting__WEBPACK_IMPORTED_MODULE_1__["default"], _strikethrough_strikethroughui__WEBPACK_IMPORTED_MODULE_2__["default"]]; - } - /** - * @inheritDoc - */ - static get pluginName() { - return 'Strikethrough'; - } -} - - -/***/ }), - -/***/ "./node_modules/@ckeditor/ckeditor5-basic-styles/src/strikethrough/strikethroughediting.js": -/*!*************************************************************************************************!*\ - !*** ./node_modules/@ckeditor/ckeditor5-basic-styles/src/strikethrough/strikethroughediting.js ***! - \*************************************************************************************************/ -/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { - -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export */ __webpack_require__.d(__webpack_exports__, { -/* harmony export */ "default": () => (/* binding */ StrikethroughEditing) -/* harmony export */ }); -/* harmony import */ var ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ckeditor5/src/core */ "./node_modules/ckeditor5/src/core.js"); -/* harmony import */ var _attributecommand__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../attributecommand */ "./node_modules/@ckeditor/ckeditor5-basic-styles/src/attributecommand.js"); -/** - * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved. - * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license - */ -/** - * @module basic-styles/strikethrough/strikethroughediting - */ - - -const STRIKETHROUGH = 'strikethrough'; -/** - * The strikethrough editing feature. - * - * It registers the `'strikethrough'` command, the Ctrl+Shift+X keystroke and introduces the - * `strikethroughsthrough` attribute in the model which renders to the view - * as a `
` element. - */ -class StrikethroughEditing extends ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__.Plugin { - /** - * @inheritDoc - */ - static get pluginName() { - return 'StrikethroughEditing'; - } - /** - * @inheritDoc - */ - init() { - const editor = this.editor; - // Allow strikethrough attribute on text nodes. - editor.model.schema.extend('$text', { allowAttributes: STRIKETHROUGH }); - editor.model.schema.setAttributeProperties(STRIKETHROUGH, { - isFormatting: true, - copyOnEnter: true - }); - editor.conversion.attributeToElement({ - model: STRIKETHROUGH, - view: 's', - upcastAlso: [ - 'del', - 'strike', - { - styles: { - 'text-decoration': 'line-through' - } - } - ] - }); - // Create strikethrough command. - editor.commands.add(STRIKETHROUGH, new _attributecommand__WEBPACK_IMPORTED_MODULE_1__["default"](editor, STRIKETHROUGH)); - // Set the Ctrl+Shift+X keystroke. - editor.keystrokes.set('CTRL+SHIFT+X', 'strikethrough'); - } -} - - -/***/ }), - -/***/ "./node_modules/@ckeditor/ckeditor5-basic-styles/src/strikethrough/strikethroughui.js": -/*!********************************************************************************************!*\ - !*** ./node_modules/@ckeditor/ckeditor5-basic-styles/src/strikethrough/strikethroughui.js ***! - \********************************************************************************************/ -/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { - -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export */ __webpack_require__.d(__webpack_exports__, { -/* harmony export */ "default": () => (/* binding */ StrikethroughUI) -/* harmony export */ }); -/* harmony import */ var ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ckeditor5/src/core */ "./node_modules/ckeditor5/src/core.js"); -/* harmony import */ var ckeditor5_src_ui__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ckeditor5/src/ui */ "./node_modules/ckeditor5/src/ui.js"); -/* harmony import */ var _theme_icons_strikethrough_svg__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../../theme/icons/strikethrough.svg */ "./node_modules/@ckeditor/ckeditor5-basic-styles/theme/icons/strikethrough.svg"); -/** - * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved. - * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license - */ -/** - * @module basic-styles/strikethrough/strikethroughui - */ - - - -const STRIKETHROUGH = 'strikethrough'; -/** - * The strikethrough UI feature. It introduces the Strikethrough button. - */ -class StrikethroughUI extends ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__.Plugin { - /** - * @inheritDoc - */ - static get pluginName() { - return 'StrikethroughUI'; - } - /** - * @inheritDoc - */ - init() { - const editor = this.editor; - const t = editor.t; - // Add strikethrough button to feature components. - editor.ui.componentFactory.add(STRIKETHROUGH, locale => { - const command = editor.commands.get(STRIKETHROUGH); - const view = new ckeditor5_src_ui__WEBPACK_IMPORTED_MODULE_1__.ButtonView(locale); - view.set({ - label: t('Strikethrough'), - icon: _theme_icons_strikethrough_svg__WEBPACK_IMPORTED_MODULE_2__["default"], - keystroke: 'CTRL+SHIFT+X', - tooltip: true, - isToggleable: true - }); - view.bind('isOn', 'isEnabled').to(command, 'value', 'isEnabled'); - // Execute command. - this.listenTo(view, 'execute', () => { - editor.execute(STRIKETHROUGH); - editor.editing.view.focus(); - }); - return view; - }); - } -} - - -/***/ }), - -/***/ "./node_modules/@ckeditor/ckeditor5-basic-styles/src/subscript.js": -/*!************************************************************************!*\ - !*** ./node_modules/@ckeditor/ckeditor5-basic-styles/src/subscript.js ***! - \************************************************************************/ -/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { - -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export */ __webpack_require__.d(__webpack_exports__, { -/* harmony export */ "default": () => (/* binding */ Subscript) -/* harmony export */ }); -/* harmony import */ var ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ckeditor5/src/core */ "./node_modules/ckeditor5/src/core.js"); -/* harmony import */ var _subscript_subscriptediting__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./subscript/subscriptediting */ "./node_modules/@ckeditor/ckeditor5-basic-styles/src/subscript/subscriptediting.js"); -/* harmony import */ var _subscript_subscriptui__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./subscript/subscriptui */ "./node_modules/@ckeditor/ckeditor5-basic-styles/src/subscript/subscriptui.js"); -/** - * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved. - * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license - */ -/** - * @module basic-styles/subscript - */ - - - -/** - * The subscript feature. - * - * It loads the {@link module:basic-styles/subscript/subscriptediting~SubscriptEditing} and - * {@link module:basic-styles/subscript/subscriptui~SubscriptUI} plugins. - */ -class Subscript extends ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__.Plugin { - /** - * @inheritDoc - */ - static get requires() { - return [_subscript_subscriptediting__WEBPACK_IMPORTED_MODULE_1__["default"], _subscript_subscriptui__WEBPACK_IMPORTED_MODULE_2__["default"]]; - } - /** - * @inheritDoc - */ - static get pluginName() { - return 'Subscript'; - } -} - - -/***/ }), - -/***/ "./node_modules/@ckeditor/ckeditor5-basic-styles/src/subscript/subscriptediting.js": -/*!*****************************************************************************************!*\ - !*** ./node_modules/@ckeditor/ckeditor5-basic-styles/src/subscript/subscriptediting.js ***! - \*****************************************************************************************/ -/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { - -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export */ __webpack_require__.d(__webpack_exports__, { -/* harmony export */ "default": () => (/* binding */ SubscriptEditing) -/* harmony export */ }); -/* harmony import */ var ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ckeditor5/src/core */ "./node_modules/ckeditor5/src/core.js"); -/* harmony import */ var _attributecommand__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../attributecommand */ "./node_modules/@ckeditor/ckeditor5-basic-styles/src/attributecommand.js"); -/** - * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved. - * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license - */ -/** - * @module basic-styles/subscript/subscriptediting - */ - - -const SUBSCRIPT = 'subscript'; -/** - * The subscript editing feature. - * - * It registers the `sub` command and introduces the `sub` attribute in the model which renders to the view - * as a `` element. - */ -class SubscriptEditing extends ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__.Plugin { - /** - * @inheritDoc - */ - static get pluginName() { - return 'SubscriptEditing'; - } - /** - * @inheritDoc - */ - init() { - const editor = this.editor; - // Allow sub attribute on text nodes. - editor.model.schema.extend('$text', { allowAttributes: SUBSCRIPT }); - editor.model.schema.setAttributeProperties(SUBSCRIPT, { - isFormatting: true, - copyOnEnter: true - }); - // Build converter from model to view for data and editing pipelines. - editor.conversion.attributeToElement({ - model: SUBSCRIPT, - view: 'sub', - upcastAlso: [ - { - styles: { - 'vertical-align': 'sub' - } - } - ] - }); - // Create sub command. - editor.commands.add(SUBSCRIPT, new _attributecommand__WEBPACK_IMPORTED_MODULE_1__["default"](editor, SUBSCRIPT)); - } -} - - -/***/ }), - -/***/ "./node_modules/@ckeditor/ckeditor5-basic-styles/src/subscript/subscriptui.js": -/*!************************************************************************************!*\ - !*** ./node_modules/@ckeditor/ckeditor5-basic-styles/src/subscript/subscriptui.js ***! - \************************************************************************************/ -/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { - -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export */ __webpack_require__.d(__webpack_exports__, { -/* harmony export */ "default": () => (/* binding */ SubscriptUI) -/* harmony export */ }); -/* harmony import */ var ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ckeditor5/src/core */ "./node_modules/ckeditor5/src/core.js"); -/* harmony import */ var ckeditor5_src_ui__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ckeditor5/src/ui */ "./node_modules/ckeditor5/src/ui.js"); -/* harmony import */ var _theme_icons_subscript_svg__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../../theme/icons/subscript.svg */ "./node_modules/@ckeditor/ckeditor5-basic-styles/theme/icons/subscript.svg"); -/** - * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved. - * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license - */ -/** - * @module basic-styles/subscript/subscriptui - */ - - - -const SUBSCRIPT = 'subscript'; -/** - * The subscript UI feature. It introduces the Subscript button. - */ -class SubscriptUI extends ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__.Plugin { - /** - * @inheritDoc - */ - static get pluginName() { - return 'SubscriptUI'; - } - /** - * @inheritDoc - */ - init() { - const editor = this.editor; - const t = editor.t; - // Add subscript button to feature components. - editor.ui.componentFactory.add(SUBSCRIPT, locale => { - const command = editor.commands.get(SUBSCRIPT); - const view = new ckeditor5_src_ui__WEBPACK_IMPORTED_MODULE_1__.ButtonView(locale); - view.set({ - label: t('Subscript'), - icon: _theme_icons_subscript_svg__WEBPACK_IMPORTED_MODULE_2__["default"], - tooltip: true, - isToggleable: true - }); - view.bind('isOn', 'isEnabled').to(command, 'value', 'isEnabled'); - // Execute command. - this.listenTo(view, 'execute', () => { - editor.execute(SUBSCRIPT); - editor.editing.view.focus(); - }); - return view; - }); - } -} - - -/***/ }), - -/***/ "./node_modules/@ckeditor/ckeditor5-basic-styles/src/superscript.js": -/*!**************************************************************************!*\ - !*** ./node_modules/@ckeditor/ckeditor5-basic-styles/src/superscript.js ***! - \**************************************************************************/ -/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { - -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export */ __webpack_require__.d(__webpack_exports__, { -/* harmony export */ "default": () => (/* binding */ Superscript) -/* harmony export */ }); -/* harmony import */ var ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ckeditor5/src/core */ "./node_modules/ckeditor5/src/core.js"); -/* harmony import */ var _superscript_superscriptediting__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./superscript/superscriptediting */ "./node_modules/@ckeditor/ckeditor5-basic-styles/src/superscript/superscriptediting.js"); -/* harmony import */ var _superscript_superscriptui__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./superscript/superscriptui */ "./node_modules/@ckeditor/ckeditor5-basic-styles/src/superscript/superscriptui.js"); -/** - * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved. - * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license - */ -/** - * @module basic-styles/superscript - */ - - - -/** - * The superscript feature. - * - * It loads the {@link module:basic-styles/superscript/superscriptediting~SuperscriptEditing} and - * {@link module:basic-styles/superscript/superscriptui~SuperscriptUI} plugins. - */ -class Superscript extends ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__.Plugin { - /** - * @inheritDoc - */ - static get requires() { - return [_superscript_superscriptediting__WEBPACK_IMPORTED_MODULE_1__["default"], _superscript_superscriptui__WEBPACK_IMPORTED_MODULE_2__["default"]]; - } - /** - * @inheritDoc - */ - static get pluginName() { - return 'Superscript'; - } -} - - -/***/ }), - -/***/ "./node_modules/@ckeditor/ckeditor5-basic-styles/src/superscript/superscriptediting.js": -/*!*********************************************************************************************!*\ - !*** ./node_modules/@ckeditor/ckeditor5-basic-styles/src/superscript/superscriptediting.js ***! - \*********************************************************************************************/ -/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { - -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export */ __webpack_require__.d(__webpack_exports__, { -/* harmony export */ "default": () => (/* binding */ SuperscriptEditing) -/* harmony export */ }); -/* harmony import */ var ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ckeditor5/src/core */ "./node_modules/ckeditor5/src/core.js"); -/* harmony import */ var _attributecommand__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../attributecommand */ "./node_modules/@ckeditor/ckeditor5-basic-styles/src/attributecommand.js"); -/** - * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved. - * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license - */ -/** - * @module basic-styles/superscript/superscriptediting - */ - - -const SUPERSCRIPT = 'superscript'; -/** - * The superscript editing feature. - * - * It registers the `super` command and introduces the `super` attribute in the model which renders to the view - * as a `` element. - */ -class SuperscriptEditing extends ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__.Plugin { - /** - * @inheritDoc - */ - static get pluginName() { - return 'SuperscriptEditing'; - } - /** - * @inheritDoc - */ - init() { - const editor = this.editor; - // Allow super attribute on text nodes. - editor.model.schema.extend('$text', { allowAttributes: SUPERSCRIPT }); - editor.model.schema.setAttributeProperties(SUPERSCRIPT, { - isFormatting: true, - copyOnEnter: true - }); - // Build converter from model to view for data and editing pipelines. - editor.conversion.attributeToElement({ - model: SUPERSCRIPT, - view: 'sup', - upcastAlso: [ - { - styles: { - 'vertical-align': 'super' - } - } - ] - }); - // Create super command. - editor.commands.add(SUPERSCRIPT, new _attributecommand__WEBPACK_IMPORTED_MODULE_1__["default"](editor, SUPERSCRIPT)); - } -} - - -/***/ }), - -/***/ "./node_modules/@ckeditor/ckeditor5-basic-styles/src/superscript/superscriptui.js": -/*!****************************************************************************************!*\ - !*** ./node_modules/@ckeditor/ckeditor5-basic-styles/src/superscript/superscriptui.js ***! - \****************************************************************************************/ -/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { - -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export */ __webpack_require__.d(__webpack_exports__, { -/* harmony export */ "default": () => (/* binding */ SuperscriptUI) -/* harmony export */ }); -/* harmony import */ var ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ckeditor5/src/core */ "./node_modules/ckeditor5/src/core.js"); -/* harmony import */ var ckeditor5_src_ui__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ckeditor5/src/ui */ "./node_modules/ckeditor5/src/ui.js"); -/* harmony import */ var _theme_icons_superscript_svg__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../../theme/icons/superscript.svg */ "./node_modules/@ckeditor/ckeditor5-basic-styles/theme/icons/superscript.svg"); -/** - * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved. - * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license - */ -/** - * @module basic-styles/superscript/superscriptui - */ - - - -const SUPERSCRIPT = 'superscript'; -/** - * The superscript UI feature. It introduces the Superscript button. - */ -class SuperscriptUI extends ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__.Plugin { - /** - * @inheritDoc - */ - static get pluginName() { - return 'SuperscriptUI'; - } - /** - * @inheritDoc - */ - init() { - const editor = this.editor; - const t = editor.t; - // Add superscript button to feature components. - editor.ui.componentFactory.add(SUPERSCRIPT, locale => { - const command = editor.commands.get(SUPERSCRIPT); - const view = new ckeditor5_src_ui__WEBPACK_IMPORTED_MODULE_1__.ButtonView(locale); - view.set({ - label: t('Superscript'), - icon: _theme_icons_superscript_svg__WEBPACK_IMPORTED_MODULE_2__["default"], - tooltip: true, - isToggleable: true - }); - view.bind('isOn', 'isEnabled').to(command, 'value', 'isEnabled'); - // Execute command. - this.listenTo(view, 'execute', () => { - editor.execute(SUPERSCRIPT); - editor.editing.view.focus(); - }); - return view; - }); - } -} - - -/***/ }), - -/***/ "./node_modules/@ckeditor/ckeditor5-basic-styles/src/underline.js": -/*!************************************************************************!*\ - !*** ./node_modules/@ckeditor/ckeditor5-basic-styles/src/underline.js ***! - \************************************************************************/ -/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { - -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export */ __webpack_require__.d(__webpack_exports__, { -/* harmony export */ "default": () => (/* binding */ Underline) -/* harmony export */ }); -/* harmony import */ var ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ckeditor5/src/core */ "./node_modules/ckeditor5/src/core.js"); -/* harmony import */ var _underline_underlineediting__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./underline/underlineediting */ "./node_modules/@ckeditor/ckeditor5-basic-styles/src/underline/underlineediting.js"); -/* harmony import */ var _underline_underlineui__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./underline/underlineui */ "./node_modules/@ckeditor/ckeditor5-basic-styles/src/underline/underlineui.js"); -/** - * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved. - * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license - */ -/** - * @module basic-styles/underline - */ - - - -/** - * The underline feature. - * - * For a detailed overview check the {@glink features/basic-styles Basic styles feature} guide - * and the {@glink api/basic-styles package page}. - * - * This is a "glue" plugin which loads the {@link module:basic-styles/underline/underlineediting~UnderlineEditing} and - * {@link module:basic-styles/underline/underlineui~UnderlineUI} plugins. - */ -class Underline extends ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__.Plugin { - /** - * @inheritDoc - */ - static get requires() { - return [_underline_underlineediting__WEBPACK_IMPORTED_MODULE_1__["default"], _underline_underlineui__WEBPACK_IMPORTED_MODULE_2__["default"]]; - } - /** - * @inheritDoc - */ - static get pluginName() { - return 'Underline'; - } -} - - -/***/ }), - -/***/ "./node_modules/@ckeditor/ckeditor5-basic-styles/src/underline/underlineediting.js": -/*!*****************************************************************************************!*\ - !*** ./node_modules/@ckeditor/ckeditor5-basic-styles/src/underline/underlineediting.js ***! - \*****************************************************************************************/ -/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { - -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export */ __webpack_require__.d(__webpack_exports__, { -/* harmony export */ "default": () => (/* binding */ UnderlineEditing) -/* harmony export */ }); -/* harmony import */ var ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ckeditor5/src/core */ "./node_modules/ckeditor5/src/core.js"); -/* harmony import */ var _attributecommand__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../attributecommand */ "./node_modules/@ckeditor/ckeditor5-basic-styles/src/attributecommand.js"); -/** - * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved. - * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license - */ -/** - * @module basic-styles/underline/underlineediting - */ - - -const UNDERLINE = 'underline'; -/** - * The underline editing feature. - * - * It registers the `'underline'` command, the Ctrl+U keystroke - * and introduces the `underline` attribute in the model which renders to the view as an `` element. - */ -class UnderlineEditing extends ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__.Plugin { - /** - * @inheritDoc - */ - static get pluginName() { - return 'UnderlineEditing'; - } - /** - * @inheritDoc - */ - init() { - const editor = this.editor; - // Allow strikethrough attribute on text nodes. - editor.model.schema.extend('$text', { allowAttributes: UNDERLINE }); - editor.model.schema.setAttributeProperties(UNDERLINE, { - isFormatting: true, - copyOnEnter: true - }); - editor.conversion.attributeToElement({ - model: UNDERLINE, - view: 'u', - upcastAlso: { - styles: { - 'text-decoration': 'underline' - } - } - }); - // Create underline command. - editor.commands.add(UNDERLINE, new _attributecommand__WEBPACK_IMPORTED_MODULE_1__["default"](editor, UNDERLINE)); - // Set the Ctrl+U keystroke. - editor.keystrokes.set('CTRL+U', 'underline'); - } -} - - -/***/ }), - -/***/ "./node_modules/@ckeditor/ckeditor5-basic-styles/src/underline/underlineui.js": -/*!************************************************************************************!*\ - !*** ./node_modules/@ckeditor/ckeditor5-basic-styles/src/underline/underlineui.js ***! - \************************************************************************************/ -/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { - -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export */ __webpack_require__.d(__webpack_exports__, { -/* harmony export */ "default": () => (/* binding */ UnderlineUI) -/* harmony export */ }); -/* harmony import */ var ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ckeditor5/src/core */ "./node_modules/ckeditor5/src/core.js"); -/* harmony import */ var ckeditor5_src_ui__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ckeditor5/src/ui */ "./node_modules/ckeditor5/src/ui.js"); -/* harmony import */ var _theme_icons_underline_svg__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../../theme/icons/underline.svg */ "./node_modules/@ckeditor/ckeditor5-basic-styles/theme/icons/underline.svg"); -/** - * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved. - * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license - */ -/** - * @module basic-styles/underline/underlineui - */ - - - -const UNDERLINE = 'underline'; -/** - * The underline UI feature. It introduces the Underline button. - */ -class UnderlineUI extends ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__.Plugin { - /** - * @inheritDoc - */ - static get pluginName() { - return 'UnderlineUI'; - } - /** - * @inheritDoc - */ - init() { - const editor = this.editor; - const t = editor.t; - // Add bold button to feature components. - editor.ui.componentFactory.add(UNDERLINE, locale => { - const command = editor.commands.get(UNDERLINE); - const view = new ckeditor5_src_ui__WEBPACK_IMPORTED_MODULE_1__.ButtonView(locale); - view.set({ - label: t('Underline'), - icon: _theme_icons_underline_svg__WEBPACK_IMPORTED_MODULE_2__["default"], - keystroke: 'CTRL+U', - tooltip: true, - isToggleable: true - }); - view.bind('isOn', 'isEnabled').to(command, 'value', 'isEnabled'); - // Execute command. - this.listenTo(view, 'execute', () => { - editor.execute(UNDERLINE); - editor.editing.view.focus(); - }); - return view; - }); - } -} - - -/***/ }), - -/***/ "./node_modules/@ckeditor/ckeditor5-block-quote/src/augmentation.js": -/*!**************************************************************************!*\ - !*** ./node_modules/@ckeditor/ckeditor5-block-quote/src/augmentation.js ***! - \**************************************************************************/ -/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { - -"use strict"; -__webpack_require__.r(__webpack_exports__); -/** - * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved. - * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license - */ - - - -/***/ }), - -/***/ "./node_modules/@ckeditor/ckeditor5-block-quote/src/blockquote.js": -/*!************************************************************************!*\ - !*** ./node_modules/@ckeditor/ckeditor5-block-quote/src/blockquote.js ***! - \************************************************************************/ -/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { - -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export */ __webpack_require__.d(__webpack_exports__, { -/* harmony export */ "default": () => (/* binding */ BlockQuote) -/* harmony export */ }); -/* harmony import */ var ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ckeditor5/src/core */ "./node_modules/ckeditor5/src/core.js"); -/* harmony import */ var _blockquoteediting__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./blockquoteediting */ "./node_modules/@ckeditor/ckeditor5-block-quote/src/blockquoteediting.js"); -/* harmony import */ var _blockquoteui__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./blockquoteui */ "./node_modules/@ckeditor/ckeditor5-block-quote/src/blockquoteui.js"); -/** - * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved. - * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license - */ -/** - * @module block-quote/blockquote - */ - - - -/** - * The block quote plugin. - * - * For more information about this feature check the {@glink api/block-quote package page}. - * - * This is a "glue" plugin which loads the {@link module:block-quote/blockquoteediting~BlockQuoteEditing block quote editing feature} - * and {@link module:block-quote/blockquoteui~BlockQuoteUI block quote UI feature}. - * - * @extends module:core/plugin~Plugin - */ -class BlockQuote extends ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__.Plugin { - /** - * @inheritDoc - */ - static get requires() { - return [_blockquoteediting__WEBPACK_IMPORTED_MODULE_1__["default"], _blockquoteui__WEBPACK_IMPORTED_MODULE_2__["default"]]; - } - /** - * @inheritDoc - */ - static get pluginName() { - return 'BlockQuote'; - } -} - - -/***/ }), - -/***/ "./node_modules/@ckeditor/ckeditor5-block-quote/src/blockquotecommand.js": -/*!*******************************************************************************!*\ - !*** ./node_modules/@ckeditor/ckeditor5-block-quote/src/blockquotecommand.js ***! - \*******************************************************************************/ -/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { - -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export */ __webpack_require__.d(__webpack_exports__, { -/* harmony export */ "default": () => (/* binding */ BlockQuoteCommand) -/* harmony export */ }); -/* harmony import */ var ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ckeditor5/src/core */ "./node_modules/ckeditor5/src/core.js"); -/* harmony import */ var ckeditor5_src_utils__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ckeditor5/src/utils */ "./node_modules/ckeditor5/src/utils.js"); -/** - * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved. - * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license - */ -/** - * @module block-quote/blockquotecommand - */ - - -/** - * The block quote command plugin. - * - * @extends module:core/command~Command - */ -class BlockQuoteCommand extends ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__.Command { - /** - * @inheritDoc - */ - refresh() { - this.value = this._getValue(); - this.isEnabled = this._checkEnabled(); - } - /** - * Executes the command. When the command {@link #value is on}, all top-most block quotes within - * the selection will be removed. If it is off, all selected blocks will be wrapped with - * a block quote. - * - * @fires execute - * @param options Command options. - * @param options.forceValue If set, it will force the command behavior. If `true`, the command will apply a block quote, - * otherwise the command will remove the block quote. If not set, the command will act basing on its current value. - */ - execute(options = {}) { - const model = this.editor.model; - const schema = model.schema; - const selection = model.document.selection; - const blocks = Array.from(selection.getSelectedBlocks()); - const value = (options.forceValue === undefined) ? !this.value : options.forceValue; - model.change(writer => { - if (!value) { - this._removeQuote(writer, blocks.filter(findQuote)); - } - else { - const blocksToQuote = blocks.filter(block => { - // Already quoted blocks needs to be considered while quoting too - // in order to reuse their elements. - return findQuote(block) || checkCanBeQuoted(schema, block); - }); - this._applyQuote(writer, blocksToQuote); - } - }); - } - /** - * Checks the command's {@link #value}. - */ - _getValue() { - const selection = this.editor.model.document.selection; - const firstBlock = (0,ckeditor5_src_utils__WEBPACK_IMPORTED_MODULE_1__.first)(selection.getSelectedBlocks()); - // In the current implementation, the block quote must be an immediate parent of a block element. - return !!(firstBlock && findQuote(firstBlock)); - } - /** - * Checks whether the command can be enabled in the current context. - * - * @returns Whether the command should be enabled. - */ - _checkEnabled() { - if (this.value) { - return true; - } - const selection = this.editor.model.document.selection; - const schema = this.editor.model.schema; - const firstBlock = (0,ckeditor5_src_utils__WEBPACK_IMPORTED_MODULE_1__.first)(selection.getSelectedBlocks()); - if (!firstBlock) { - return false; - } - return checkCanBeQuoted(schema, firstBlock); - } - /** - * Removes the quote from given blocks. - * - * If blocks which are supposed to be "unquoted" are in the middle of a quote, - * start it or end it, then the quote will be split (if needed) and the blocks - * will be moved out of it, so other quoted blocks remained quoted. - */ - _removeQuote(writer, blocks) { - // Unquote all groups of block. Iterate in the reverse order to not break following ranges. - getRangesOfBlockGroups(writer, blocks).reverse().forEach(groupRange => { - if (groupRange.start.isAtStart && groupRange.end.isAtEnd) { - writer.unwrap(groupRange.start.parent); - return; - } - // The group of blocks are at the beginning of an so let's move them left (out of the ). - if (groupRange.start.isAtStart) { - const positionBefore = writer.createPositionBefore(groupRange.start.parent); - writer.move(groupRange, positionBefore); - return; - } - // The blocks are in the middle of an so we need to split the after the last block - // so we move the items there. - if (!groupRange.end.isAtEnd) { - writer.split(groupRange.end); - } - // Now we are sure that groupRange.end.isAtEnd is true, so let's move the blocks right. - const positionAfter = writer.createPositionAfter(groupRange.end.parent); - writer.move(groupRange, positionAfter); - }); - } - /** - * Applies the quote to given blocks. - */ - _applyQuote(writer, blocks) { - const quotesToMerge = []; - // Quote all groups of block. Iterate in the reverse order to not break following ranges. - getRangesOfBlockGroups(writer, blocks).reverse().forEach(groupRange => { - let quote = findQuote(groupRange.start); - if (!quote) { - quote = writer.createElement('blockQuote'); - writer.wrap(groupRange, quote); - } - quotesToMerge.push(quote); - }); - // Merge subsequent elements. Reverse the order again because this time we want to go through - // the elements in the source order (due to how merge works – it moves the right element's content - // to the first element and removes the right one. Since we may need to merge a couple of subsequent ` ` elements - // we want to keep the reference to the first (furthest left) one. - quotesToMerge.reverse().reduce((currentQuote, nextQuote) => { - if (currentQuote.nextSibling == nextQuote) { - writer.merge(writer.createPositionAfter(currentQuote)); - return currentQuote; - } - return nextQuote; - }); - } -} -function findQuote(elementOrPosition) { - return elementOrPosition.parent.name == 'blockQuote' ? elementOrPosition.parent : null; -} -/** - * Returns a minimal array of ranges containing groups of subsequent blocks. - * - * content: abcdefgh - * blocks: [ a, b, d, f, g, h ] - * output ranges: [ab]c[d]e[fgh] - */ -function getRangesOfBlockGroups(writer, blocks) { - let startPosition; - let i = 0; - const ranges = []; - while (i < blocks.length) { - const block = blocks[i]; - const nextBlock = blocks[i + 1]; - if (!startPosition) { - startPosition = writer.createPositionBefore(block); - } - if (!nextBlock || block.nextSibling != nextBlock) { - ranges.push(writer.createRange(startPosition, writer.createPositionAfter(block))); - startPosition = null; - } - i++; - } - return ranges; -} -/** - * Checks whether can wrap the block. - */ -function checkCanBeQuoted(schema, block) { - // TMP will be replaced with schema.checkWrap(). - const isBQAllowed = schema.checkChild(block.parent, 'blockQuote'); - const isBlockAllowedInBQ = schema.checkChild(['$root', 'blockQuote'], block); - return isBQAllowed && isBlockAllowedInBQ; -} - - -/***/ }), - -/***/ "./node_modules/@ckeditor/ckeditor5-block-quote/src/blockquoteediting.js": -/*!*******************************************************************************!*\ - !*** ./node_modules/@ckeditor/ckeditor5-block-quote/src/blockquoteediting.js ***! - \*******************************************************************************/ -/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { - -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export */ __webpack_require__.d(__webpack_exports__, { -/* harmony export */ "default": () => (/* binding */ BlockQuoteEditing) -/* harmony export */ }); -/* harmony import */ var ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ckeditor5/src/core */ "./node_modules/ckeditor5/src/core.js"); -/* harmony import */ var ckeditor5_src_enter__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ckeditor5/src/enter */ "./node_modules/ckeditor5/src/enter.js"); -/* harmony import */ var ckeditor5_src_typing__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ckeditor5/src/typing */ "./node_modules/ckeditor5/src/typing.js"); -/* harmony import */ var _blockquotecommand__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./blockquotecommand */ "./node_modules/@ckeditor/ckeditor5-block-quote/src/blockquotecommand.js"); -/** - * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved. - * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license - */ -/** - * @module block-quote/blockquoteediting - */ - - - - -/** - * The block quote editing. - * - * Introduces the `'blockQuote'` command and the `'blockQuote'` model element. - * - * @extends module:core/plugin~Plugin - */ -class BlockQuoteEditing extends ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__.Plugin { - /** - * @inheritDoc - */ - static get pluginName() { - return 'BlockQuoteEditing'; - } - /** - * @inheritDoc - */ - static get requires() { - return [ckeditor5_src_enter__WEBPACK_IMPORTED_MODULE_1__.Enter, ckeditor5_src_typing__WEBPACK_IMPORTED_MODULE_2__.Delete]; - } - /** - * @inheritDoc - */ - init() { - const editor = this.editor; - const schema = editor.model.schema; - editor.commands.add('blockQuote', new _blockquotecommand__WEBPACK_IMPORTED_MODULE_3__["default"](editor)); - schema.register('blockQuote', { - inheritAllFrom: '$container' - }); - editor.conversion.elementToElement({ model: 'blockQuote', view: 'blockquote' }); - // Postfixer which cleans incorrect model states connected with block quotes. - editor.model.document.registerPostFixer(writer => { - const changes = editor.model.document.differ.getChanges(); - for (const entry of changes) { - if (entry.type == 'insert') { - const element = entry.position.nodeAfter; - if (!element) { - // We are inside a text node. - continue; - } - if (element.is('element', 'blockQuote') && element.isEmpty) { - // Added an empty blockQuote - remove it. - writer.remove(element); - return true; - } - else if (element.is('element', 'blockQuote') && !schema.checkChild(entry.position, element)) { - // Added a blockQuote in incorrect place. Unwrap it so the content inside is not lost. - writer.unwrap(element); - return true; - } - else if (element.is('element')) { - // Just added an element. Check that all children meet the scheme rules. - const range = writer.createRangeIn(element); - for (const child of range.getItems()) { - if (child.is('element', 'blockQuote') && - !schema.checkChild(writer.createPositionBefore(child), child)) { - writer.unwrap(child); - return true; - } - } - } - } - else if (entry.type == 'remove') { - const parent = entry.position.parent; - if (parent.is('element', 'blockQuote') && parent.isEmpty) { - // Something got removed and now blockQuote is empty. Remove the blockQuote as well. - writer.remove(parent); - return true; - } - } - } - return false; - }); - const viewDocument = this.editor.editing.view.document; - const selection = editor.model.document.selection; - const blockQuoteCommand = editor.commands.get('blockQuote'); - // Overwrite default Enter key behavior. - // If Enter key is pressed with selection collapsed in empty block inside a quote, break the quote. - this.listenTo(viewDocument, 'enter', (evt, data) => { - if (!selection.isCollapsed || !blockQuoteCommand.value) { - return; - } - const positionParent = selection.getLastPosition().parent; - if (positionParent.isEmpty) { - editor.execute('blockQuote'); - editor.editing.view.scrollToTheSelection(); - data.preventDefault(); - evt.stop(); - } - }, { context: 'blockquote' }); - // Overwrite default Backspace key behavior. - // If Backspace key is pressed with selection collapsed in first empty block inside a quote, break the quote. - this.listenTo(viewDocument, 'delete', (evt, data) => { - if (data.direction != 'backward' || !selection.isCollapsed || !blockQuoteCommand.value) { - return; - } - const positionParent = selection.getLastPosition().parent; - if (positionParent.isEmpty && !positionParent.previousSibling) { - editor.execute('blockQuote'); - editor.editing.view.scrollToTheSelection(); - data.preventDefault(); - evt.stop(); - } - }, { context: 'blockquote' }); - } -} - - -/***/ }), - -/***/ "./node_modules/@ckeditor/ckeditor5-block-quote/src/blockquoteui.js": -/*!**************************************************************************!*\ - !*** ./node_modules/@ckeditor/ckeditor5-block-quote/src/blockquoteui.js ***! - \**************************************************************************/ -/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { - -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export */ __webpack_require__.d(__webpack_exports__, { -/* harmony export */ "default": () => (/* binding */ BlockQuoteUI) -/* harmony export */ }); -/* harmony import */ var ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ckeditor5/src/core */ "./node_modules/ckeditor5/src/core.js"); -/* harmony import */ var ckeditor5_src_ui__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ckeditor5/src/ui */ "./node_modules/ckeditor5/src/ui.js"); -/* harmony import */ var _theme_blockquote_css__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../theme/blockquote.css */ "./node_modules/@ckeditor/ckeditor5-block-quote/theme/blockquote.css"); -/** - * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved. - * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license - */ -/** - * @module block-quote/blockquoteui - */ - - - -/** - * The block quote UI plugin. - * - * It introduces the `'blockQuote'` button. - * - * @extends module:core/plugin~Plugin - */ -class BlockQuoteUI extends ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__.Plugin { - /** - * @inheritDoc - */ - static get pluginName() { - return 'BlockQuoteUI'; - } - /** - * @inheritDoc - */ - init() { - const editor = this.editor; - const t = editor.t; - editor.ui.componentFactory.add('blockQuote', locale => { - const command = editor.commands.get('blockQuote'); - const buttonView = new ckeditor5_src_ui__WEBPACK_IMPORTED_MODULE_1__.ButtonView(locale); - buttonView.set({ - label: t('Block quote'), - icon: ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__.icons.quote, - tooltip: true, - isToggleable: true - }); - // Bind button model to command. - buttonView.bind('isOn', 'isEnabled').to(command, 'value', 'isEnabled'); - // Execute command. - this.listenTo(buttonView, 'execute', () => { - editor.execute('blockQuote'); - editor.editing.view.focus(); - }); - return buttonView; - }); - } -} - - -/***/ }), - -/***/ "./node_modules/@ckeditor/ckeditor5-block-quote/src/index.js": -/*!*******************************************************************!*\ - !*** ./node_modules/@ckeditor/ckeditor5-block-quote/src/index.js ***! - \*******************************************************************/ -/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { - -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export */ __webpack_require__.d(__webpack_exports__, { -/* harmony export */ BlockQuote: () => (/* reexport safe */ _blockquote__WEBPACK_IMPORTED_MODULE_0__["default"]), -/* harmony export */ BlockQuoteEditing: () => (/* reexport safe */ _blockquoteediting__WEBPACK_IMPORTED_MODULE_1__["default"]), -/* harmony export */ BlockQuoteUI: () => (/* reexport safe */ _blockquoteui__WEBPACK_IMPORTED_MODULE_2__["default"]) -/* harmony export */ }); -/* harmony import */ var _blockquote__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./blockquote */ "./node_modules/@ckeditor/ckeditor5-block-quote/src/blockquote.js"); -/* harmony import */ var _blockquoteediting__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./blockquoteediting */ "./node_modules/@ckeditor/ckeditor5-block-quote/src/blockquoteediting.js"); -/* harmony import */ var _blockquoteui__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./blockquoteui */ "./node_modules/@ckeditor/ckeditor5-block-quote/src/blockquoteui.js"); -/* harmony import */ var _augmentation__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./augmentation */ "./node_modules/@ckeditor/ckeditor5-block-quote/src/augmentation.js"); -/** - * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved. - * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license - */ -/** - * @module block-quote - */ - - - - - - -/***/ }), - -/***/ "./node_modules/@ckeditor/ckeditor5-clipboard/src/augmentation.js": -/*!************************************************************************!*\ - !*** ./node_modules/@ckeditor/ckeditor5-clipboard/src/augmentation.js ***! - \************************************************************************/ -/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { - -"use strict"; -__webpack_require__.r(__webpack_exports__); -/** - * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved. - * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license - */ - - - -/***/ }), - -/***/ "./node_modules/@ckeditor/ckeditor5-clipboard/src/clipboard.js": -/*!*********************************************************************!*\ - !*** ./node_modules/@ckeditor/ckeditor5-clipboard/src/clipboard.js ***! - \*********************************************************************/ -/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { - -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export */ __webpack_require__.d(__webpack_exports__, { -/* harmony export */ "default": () => (/* binding */ Clipboard) -/* harmony export */ }); -/* harmony import */ var _ckeditor_ckeditor5_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @ckeditor/ckeditor5-core */ "./node_modules/@ckeditor/ckeditor5-core/src/index.js"); -/* harmony import */ var _clipboardpipeline__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./clipboardpipeline */ "./node_modules/@ckeditor/ckeditor5-clipboard/src/clipboardpipeline.js"); -/* harmony import */ var _dragdrop__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./dragdrop */ "./node_modules/@ckeditor/ckeditor5-clipboard/src/dragdrop.js"); -/* harmony import */ var _pasteplaintext__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./pasteplaintext */ "./node_modules/@ckeditor/ckeditor5-clipboard/src/pasteplaintext.js"); -/** - * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved. - * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license - */ -/** - * @module clipboard/clipboard - */ - - - - -/** - * The clipboard feature. - * - * Read more about the clipboard integration in the {@glink framework/deep-dive/clipboard clipboard deep-dive} guide. - * - * This is a "glue" plugin which loads the following plugins: - * * {@link module:clipboard/clipboardpipeline~ClipboardPipeline} - * * {@link module:clipboard/dragdrop~DragDrop} - * * {@link module:clipboard/pasteplaintext~PastePlainText} - */ -class Clipboard extends _ckeditor_ckeditor5_core__WEBPACK_IMPORTED_MODULE_0__.Plugin { - /** - * @inheritDoc - */ - static get pluginName() { - return 'Clipboard'; - } - /** - * @inheritDoc - */ - static get requires() { - return [_clipboardpipeline__WEBPACK_IMPORTED_MODULE_1__["default"], _dragdrop__WEBPACK_IMPORTED_MODULE_2__["default"], _pasteplaintext__WEBPACK_IMPORTED_MODULE_3__["default"]]; - } -} - - -/***/ }), - -/***/ "./node_modules/@ckeditor/ckeditor5-clipboard/src/clipboardobserver.js": -/*!*****************************************************************************!*\ - !*** ./node_modules/@ckeditor/ckeditor5-clipboard/src/clipboardobserver.js ***! - \*****************************************************************************/ -/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { - -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export */ __webpack_require__.d(__webpack_exports__, { -/* harmony export */ "default": () => (/* binding */ ClipboardObserver) -/* harmony export */ }); -/* harmony import */ var _ckeditor_ckeditor5_utils__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @ckeditor/ckeditor5-utils */ "./node_modules/@ckeditor/ckeditor5-utils/src/index.js"); -/* harmony import */ var _ckeditor_ckeditor5_engine__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @ckeditor/ckeditor5-engine */ "./node_modules/@ckeditor/ckeditor5-engine/src/index.js"); -/** - * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved. - * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license - */ -/** - * @module clipboard/clipboardobserver - */ - - -/** - * Clipboard events observer. - * - * Fires the following events: - * - * * {@link module:engine/view/document~Document#event:clipboardInput}, - * * {@link module:engine/view/document~Document#event:paste}, - * * {@link module:engine/view/document~Document#event:copy}, - * * {@link module:engine/view/document~Document#event:cut}, - * * {@link module:engine/view/document~Document#event:drop}, - * * {@link module:engine/view/document~Document#event:dragover}, - * * {@link module:engine/view/document~Document#event:dragging}, - * * {@link module:engine/view/document~Document#event:dragstart}, - * * {@link module:engine/view/document~Document#event:dragend}, - * * {@link module:engine/view/document~Document#event:dragenter}, - * * {@link module:engine/view/document~Document#event:dragleave}. - * - * **Note**: This observer is not available by default (ckeditor5-engine does not add it on its own). - * To make it available, it needs to be added to {@link module:engine/view/document~Document} by using - * the {@link module:engine/view/view~View#addObserver `View#addObserver()`} method. Alternatively, you can load the - * {@link module:clipboard/clipboard~Clipboard} plugin which adds this observer automatically (because it uses it). - */ -class ClipboardObserver extends _ckeditor_ckeditor5_engine__WEBPACK_IMPORTED_MODULE_1__.DomEventObserver { - constructor(view) { - super(view); - this.domEventType = [ - 'paste', 'copy', 'cut', 'drop', 'dragover', 'dragstart', 'dragend', 'dragenter', 'dragleave' - ]; - const viewDocument = this.document; - this.listenTo(viewDocument, 'paste', handleInput('clipboardInput'), { priority: 'low' }); - this.listenTo(viewDocument, 'drop', handleInput('clipboardInput'), { priority: 'low' }); - this.listenTo(viewDocument, 'dragover', handleInput('dragging'), { priority: 'low' }); - function handleInput(type) { - return (evt, data) => { - data.preventDefault(); - const targetRanges = data.dropRange ? [data.dropRange] : null; - const eventInfo = new _ckeditor_ckeditor5_utils__WEBPACK_IMPORTED_MODULE_0__.EventInfo(viewDocument, type); - viewDocument.fire(eventInfo, { - dataTransfer: data.dataTransfer, - method: evt.name, - targetRanges, - target: data.target, - domEvent: data.domEvent - }); - // If CKEditor handled the input, do not bubble the original event any further. - // This helps external integrations recognize that fact and act accordingly. - // https://github.com/ckeditor/ckeditor5-upload/issues/92 - if (eventInfo.stop.called) { - data.stopPropagation(); - } - }; - } - } - onDomEvent(domEvent) { - const nativeDataTransfer = 'clipboardData' in domEvent ? domEvent.clipboardData : domEvent.dataTransfer; - const cacheFiles = domEvent.type == 'drop' || domEvent.type == 'paste'; - const evtData = { - dataTransfer: new _ckeditor_ckeditor5_engine__WEBPACK_IMPORTED_MODULE_1__.DataTransfer(nativeDataTransfer, { cacheFiles }) - }; - if (domEvent.type == 'drop' || domEvent.type == 'dragover') { - evtData.dropRange = getDropViewRange(this.view, domEvent); - } - this.fire(domEvent.type, domEvent, evtData); - } -} -function getDropViewRange(view, domEvent) { - const domDoc = domEvent.target.ownerDocument; - const x = domEvent.clientX; - const y = domEvent.clientY; - let domRange; - // Webkit & Blink. - if (domDoc.caretRangeFromPoint && domDoc.caretRangeFromPoint(x, y)) { - domRange = domDoc.caretRangeFromPoint(x, y); - } - // FF. - else if (domEvent.rangeParent) { - domRange = domDoc.createRange(); - domRange.setStart(domEvent.rangeParent, domEvent.rangeOffset); - domRange.collapse(true); - } - if (domRange) { - return view.domConverter.domRangeToView(domRange); - } - return null; -} - - -/***/ }), - -/***/ "./node_modules/@ckeditor/ckeditor5-clipboard/src/clipboardpipeline.js": -/*!*****************************************************************************!*\ - !*** ./node_modules/@ckeditor/ckeditor5-clipboard/src/clipboardpipeline.js ***! - \*****************************************************************************/ -/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { - -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export */ __webpack_require__.d(__webpack_exports__, { -/* harmony export */ "default": () => (/* binding */ ClipboardPipeline) -/* harmony export */ }); -/* harmony import */ var _ckeditor_ckeditor5_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @ckeditor/ckeditor5-core */ "./node_modules/@ckeditor/ckeditor5-core/src/index.js"); -/* harmony import */ var _ckeditor_ckeditor5_utils__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @ckeditor/ckeditor5-utils */ "./node_modules/@ckeditor/ckeditor5-utils/src/index.js"); -/* harmony import */ var _clipboardobserver__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./clipboardobserver */ "./node_modules/@ckeditor/ckeditor5-clipboard/src/clipboardobserver.js"); -/* harmony import */ var _utils_plaintexttohtml__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./utils/plaintexttohtml */ "./node_modules/@ckeditor/ckeditor5-clipboard/src/utils/plaintexttohtml.js"); -/* harmony import */ var _utils_normalizeclipboarddata__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./utils/normalizeclipboarddata */ "./node_modules/@ckeditor/ckeditor5-clipboard/src/utils/normalizeclipboarddata.js"); -/* harmony import */ var _utils_viewtoplaintext__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./utils/viewtoplaintext */ "./node_modules/@ckeditor/ckeditor5-clipboard/src/utils/viewtoplaintext.js"); -/** - * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved. - * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license - */ -/** - * @module clipboard/clipboardpipeline - */ - - - - - - -// Input pipeline events overview: -// -// ┌──────────────────────┐ ┌──────────────────────┐ -// │ view.Document │ │ view.Document │ -// │ paste │ │ drop │ -// └───────────┬──────────┘ └───────────┬──────────┘ -// │ │ -// └────────────────┌────────────────┘ -// │ -// ┌─────────V────────┐ -// │ view.Document │ Retrieves text/html or text/plain from data.dataTransfer -// │ clipboardInput │ and processes it to view.DocumentFragment. -// └─────────┬────────┘ -// │ -// ┌───────────V───────────┐ -// │ ClipboardPipeline │ Converts view.DocumentFragment to model.DocumentFragment. -// │ inputTransformation │ -// └───────────┬───────────┘ -// │ -// ┌──────────V──────────┐ -// │ ClipboardPipeline │ Calls model.insertContent(). -// │ contentInsertion │ -// └─────────────────────┘ -// -// -// Output pipeline events overview: -// -// ┌──────────────────────┐ ┌──────────────────────┐ -// │ view.Document │ │ view.Document │ Retrieves the selected model.DocumentFragment -// │ copy │ │ cut │ and converts it to view.DocumentFragment. -// └───────────┬──────────┘ └───────────┬──────────┘ -// │ │ -// └────────────────┌────────────────┘ -// │ -// ┌─────────V────────┐ -// │ view.Document │ Processes view.DocumentFragment to text/html and text/plain -// │ clipboardOutput │ and stores the results in data.dataTransfer. -// └──────────────────┘ -// -/** - * The clipboard pipeline feature. It is responsible for intercepting the `paste` and `drop` events and - * passing the pasted content through a series of events in order to insert it into the editor's content. - * It also handles the `cut` and `copy` events to fill the native clipboard with the serialized editor's data. - * - * # Input pipeline - * - * The behavior of the default handlers (all at a `low` priority): - * - * ## Event: `paste` or `drop` - * - * 1. Translates the event data. - * 2. Fires the {@link module:engine/view/document~Document#event:clipboardInput `view.Document#clipboardInput`} event. - * - * ## Event: `view.Document#clipboardInput` - * - * 1. If the `data.content` event field is already set (by some listener on a higher priority), it takes this content and fires the event - * from the last point. - * 2. Otherwise, it retrieves `text/html` or `text/plain` from `data.dataTransfer`. - * 3. Normalizes the raw data by applying simple filters on string data. - * 4. Processes the raw data to {@link module:engine/view/documentfragment~DocumentFragment `view.DocumentFragment`} with the - * {@link module:engine/controller/datacontroller~DataController#htmlProcessor `DataController#htmlProcessor`}. - * 5. Fires the {@link module:clipboard/clipboardpipeline~ClipboardPipeline#event:inputTransformation - * `ClipboardPipeline#inputTransformation`} event with the view document fragment in the `data.content` event field. - * - * ## Event: `ClipboardPipeline#inputTransformation` - * - * 1. Converts {@link module:engine/view/documentfragment~DocumentFragment `view.DocumentFragment`} from the `data.content` field to - * {@link module:engine/model/documentfragment~DocumentFragment `model.DocumentFragment`}. - * 2. Fires the {@link module:clipboard/clipboardpipeline~ClipboardPipeline#event:contentInsertion `ClipboardPipeline#contentInsertion`} - * event with the model document fragment in the `data.content` event field. - * **Note**: The `ClipboardPipeline#contentInsertion` event is fired within a model change block to allow other handlers - * to run in the same block without post-fixers called in between (i.e., the selection post-fixer). - * - * ## Event: `ClipboardPipeline#contentInsertion` - * - * 1. Calls {@link module:engine/model/model~Model#insertContent `model.insertContent()`} to insert `data.content` - * at the current selection position. - * - * # Output pipeline - * - * The behavior of the default handlers (all at a `low` priority): - * - * ## Event: `copy`, `cut` or `dragstart` - * - * 1. Retrieves the selected {@link module:engine/model/documentfragment~DocumentFragment `model.DocumentFragment`} by calling - * {@link module:engine/model/model~Model#getSelectedContent `model#getSelectedContent()`}. - * 2. Converts the model document fragment to {@link module:engine/view/documentfragment~DocumentFragment `view.DocumentFragment`}. - * 3. Fires the {@link module:engine/view/document~Document#event:clipboardOutput `view.Document#clipboardOutput`} event - * with the view document fragment in the `data.content` event field. - * - * ## Event: `view.Document#clipboardOutput` - * - * 1. Processes `data.content` to HTML and plain text with the - * {@link module:engine/controller/datacontroller~DataController#htmlProcessor `DataController#htmlProcessor`}. - * 2. Updates the `data.dataTransfer` data for `text/html` and `text/plain` with the processed data. - * 3. For the `cut` method, calls {@link module:engine/model/model~Model#deleteContent `model.deleteContent()`} - * on the current selection. - * - * Read more about the clipboard integration in the {@glink framework/deep-dive/clipboard clipboard deep-dive} guide. - */ -class ClipboardPipeline extends _ckeditor_ckeditor5_core__WEBPACK_IMPORTED_MODULE_0__.Plugin { - /** - * @inheritDoc - */ - static get pluginName() { - return 'ClipboardPipeline'; - } - /** - * @inheritDoc - */ - init() { - const editor = this.editor; - const view = editor.editing.view; - view.addObserver(_clipboardobserver__WEBPACK_IMPORTED_MODULE_2__["default"]); - this._setupPasteDrop(); - this._setupCopyCut(); - } - /** - * The clipboard paste pipeline. - */ - _setupPasteDrop() { - const editor = this.editor; - const model = editor.model; - const view = editor.editing.view; - const viewDocument = view.document; - // Pasting is disabled when selection is in non-editable place. - // Dropping is disabled in drag and drop handler. - this.listenTo(viewDocument, 'clipboardInput', (evt, data) => { - if (data.method == 'paste' && !editor.model.canEditAt(editor.model.document.selection)) { - evt.stop(); - } - }, { priority: 'highest' }); - this.listenTo(viewDocument, 'clipboardInput', (evt, data) => { - const dataTransfer = data.dataTransfer; - let content; - // Some feature could already inject content in the higher priority event handler (i.e., codeBlock). - if (data.content) { - content = data.content; - } - else { - let contentData = ''; - if (dataTransfer.getData('text/html')) { - contentData = (0,_utils_normalizeclipboarddata__WEBPACK_IMPORTED_MODULE_4__["default"])(dataTransfer.getData('text/html')); - } - else if (dataTransfer.getData('text/plain')) { - contentData = (0,_utils_plaintexttohtml__WEBPACK_IMPORTED_MODULE_3__["default"])(dataTransfer.getData('text/plain')); - } - content = this.editor.data.htmlProcessor.toView(contentData); - } - const eventInfo = new _ckeditor_ckeditor5_utils__WEBPACK_IMPORTED_MODULE_1__.EventInfo(this, 'inputTransformation'); - this.fire(eventInfo, { - content, - dataTransfer, - targetRanges: data.targetRanges, - method: data.method - }); - // If CKEditor handled the input, do not bubble the original event any further. - // This helps external integrations recognize this fact and act accordingly. - // https://github.com/ckeditor/ckeditor5-upload/issues/92 - if (eventInfo.stop.called) { - evt.stop(); - } - view.scrollToTheSelection(); - }, { priority: 'low' }); - this.listenTo(this, 'inputTransformation', (evt, data) => { - if (data.content.isEmpty) { - return; - } - const dataController = this.editor.data; - // Convert the pasted content into a model document fragment. - // The conversion is contextual, but in this case an "all allowed" context is needed - // and for that we use the $clipboardHolder item. - const modelFragment = dataController.toModel(data.content, '$clipboardHolder'); - if (modelFragment.childCount == 0) { - return; - } - evt.stop(); - // Fire content insertion event in a single change block to allow other handlers to run in the same block - // without post-fixers called in between (i.e., the selection post-fixer). - model.change(() => { - this.fire('contentInsertion', { - content: modelFragment, - method: data.method, - dataTransfer: data.dataTransfer, - targetRanges: data.targetRanges - }); - }); - }, { priority: 'low' }); - this.listenTo(this, 'contentInsertion', (evt, data) => { - data.resultRange = model.insertContent(data.content); - }, { priority: 'low' }); - } - /** - * The clipboard copy/cut pipeline. - */ - _setupCopyCut() { - const editor = this.editor; - const modelDocument = editor.model.document; - const view = editor.editing.view; - const viewDocument = view.document; - const onCopyCut = (evt, data) => { - const dataTransfer = data.dataTransfer; - data.preventDefault(); - const content = editor.data.toView(editor.model.getSelectedContent(modelDocument.selection)); - viewDocument.fire('clipboardOutput', { - dataTransfer, - content, - method: evt.name - }); - }; - this.listenTo(viewDocument, 'copy', onCopyCut, { priority: 'low' }); - this.listenTo(viewDocument, 'cut', (evt, data) => { - // Cutting is disabled when selection is in non-editable place. - // See: https://github.com/ckeditor/ckeditor5-clipboard/issues/26. - if (!editor.model.canEditAt(editor.model.document.selection)) { - data.preventDefault(); - } - else { - onCopyCut(evt, data); - } - }, { priority: 'low' }); - this.listenTo(viewDocument, 'clipboardOutput', (evt, data) => { - if (!data.content.isEmpty) { - data.dataTransfer.setData('text/html', this.editor.data.htmlProcessor.toData(data.content)); - data.dataTransfer.setData('text/plain', (0,_utils_viewtoplaintext__WEBPACK_IMPORTED_MODULE_5__["default"])(data.content)); - } - if (data.method == 'cut') { - editor.model.deleteContent(modelDocument.selection); - } - }, { priority: 'low' }); - } -} - - -/***/ }), - -/***/ "./node_modules/@ckeditor/ckeditor5-clipboard/src/dragdrop.js": -/*!********************************************************************!*\ - !*** ./node_modules/@ckeditor/ckeditor5-clipboard/src/dragdrop.js ***! - \********************************************************************/ -/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { - -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export */ __webpack_require__.d(__webpack_exports__, { -/* harmony export */ "default": () => (/* binding */ DragDrop) -/* harmony export */ }); -/* harmony import */ var _ckeditor_ckeditor5_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @ckeditor/ckeditor5-core */ "./node_modules/@ckeditor/ckeditor5-core/src/index.js"); -/* harmony import */ var _ckeditor_ckeditor5_engine__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @ckeditor/ckeditor5-engine */ "./node_modules/@ckeditor/ckeditor5-engine/src/index.js"); -/* harmony import */ var _ckeditor_ckeditor5_widget__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @ckeditor/ckeditor5-widget */ "./node_modules/@ckeditor/ckeditor5-widget/src/index.js"); -/* harmony import */ var _ckeditor_ckeditor5_utils__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @ckeditor/ckeditor5-utils */ "./node_modules/@ckeditor/ckeditor5-utils/src/index.js"); -/* harmony import */ var _clipboardpipeline__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./clipboardpipeline */ "./node_modules/@ckeditor/ckeditor5-clipboard/src/clipboardpipeline.js"); -/* harmony import */ var _clipboardobserver__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./clipboardobserver */ "./node_modules/@ckeditor/ckeditor5-clipboard/src/clipboardobserver.js"); -/* harmony import */ var lodash_es__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! lodash-es */ "./node_modules/lodash-es/throttle.js"); -/* harmony import */ var _theme_clipboard_css__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../theme/clipboard.css */ "./node_modules/@ckeditor/ckeditor5-clipboard/theme/clipboard.css"); -/** - * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved. - * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license - */ -/** - * @module clipboard/dragdrop - */ - - - - - - - - -// Drag and drop events overview: -// -// ┌──────────────────┐ -// │ mousedown │ Sets the draggable attribute. -// └─────────┬────────┘ -// │ -// └─────────────────────┐ -// │ │ -// │ ┌─────────V────────┐ -// │ │ mouseup │ Dragging did not start, removes the draggable attribute. -// │ └──────────────────┘ -// │ -// ┌─────────V────────┐ Retrieves the selected model.DocumentFragment -// │ dragstart │ and converts it to view.DocumentFragment. -// └─────────┬────────┘ -// │ -// ┌─────────V────────┐ Processes view.DocumentFragment to text/html and text/plain -// │ clipboardOutput │ and stores the results in data.dataTransfer. -// └─────────┬────────┘ -// │ -// │ DOM dragover -// ┌────────────┐ -// │ │ -// ┌─────────V────────┐ │ -// │ dragging │ │ Updates the drop target marker. -// └─────────┬────────┘ │ -// │ │ -// ┌─────────────└────────────┘ -// │ │ │ -// │ ┌─────────V────────┐ │ -// │ │ dragleave │ │ Removes the drop target marker. -// │ └─────────┬────────┘ │ -// │ │ │ -// ┌───│─────────────┘ │ -// │ │ │ │ -// │ │ ┌─────────V────────┐ │ -// │ │ │ dragenter │ │ Focuses the editor view. -// │ │ └─────────┬────────┘ │ -// │ │ │ │ -// │ │ └────────────┘ -// │ │ -// │ └─────────────┐ -// │ │ │ -// │ │ ┌─────────V────────┐ -// └───┐ │ drop │ (The default handler of the clipboard pipeline). -// │ └─────────┬────────┘ -// │ │ -// │ ┌─────────V────────┐ Resolves the final data.targetRanges. -// │ │ clipboardInput │ Aborts if dropping on dragged content. -// │ └─────────┬────────┘ -// │ │ -// │ ┌─────────V────────┐ -// │ │ clipboardInput │ (The default handler of the clipboard pipeline). -// │ └─────────┬────────┘ -// │ │ -// │ ┌───────────V───────────┐ -// │ │ inputTransformation │ (The default handler of the clipboard pipeline). -// │ └───────────┬───────────┘ -// │ │ -// │ ┌──────────V──────────┐ -// │ │ contentInsertion │ Updates the document selection to drop range. -// │ └──────────┬──────────┘ -// │ │ -// │ ┌──────────V──────────┐ -// │ │ contentInsertion │ (The default handler of the clipboard pipeline). -// │ └──────────┬──────────┘ -// │ │ -// │ ┌──────────V──────────┐ -// │ │ contentInsertion │ Removes the content from the original range if the insertion was successful. -// │ └──────────┬──────────┘ -// │ │ -// └─────────────┐ -// │ -// ┌─────────V────────┐ -// │ dragend │ Removes the drop marker and cleans the state. -// └──────────────────┘ -// -/** - * The drag and drop feature. It works on top of the {@link module:clipboard/clipboardpipeline~ClipboardPipeline}. - * - * Read more about the clipboard integration in the {@glink framework/deep-dive/clipboard clipboard deep-dive} guide. - */ -class DragDrop extends _ckeditor_ckeditor5_core__WEBPACK_IMPORTED_MODULE_0__.Plugin { - /** - * @inheritDoc - */ - static get pluginName() { - return 'DragDrop'; - } - /** - * @inheritDoc - */ - static get requires() { - return [_clipboardpipeline__WEBPACK_IMPORTED_MODULE_4__["default"], _ckeditor_ckeditor5_widget__WEBPACK_IMPORTED_MODULE_2__.Widget]; - } - /** - * @inheritDoc - */ - init() { - const editor = this.editor; - const view = editor.editing.view; - this._draggedRange = null; - this._draggingUid = ''; - this._draggableElement = null; - this._updateDropMarkerThrottled = (0,lodash_es__WEBPACK_IMPORTED_MODULE_7__["default"])(targetRange => this._updateDropMarker(targetRange), 40); - this._removeDropMarkerDelayed = (0,_ckeditor_ckeditor5_utils__WEBPACK_IMPORTED_MODULE_3__.delay)(() => this._removeDropMarker(), 40); - this._clearDraggableAttributesDelayed = (0,_ckeditor_ckeditor5_utils__WEBPACK_IMPORTED_MODULE_3__.delay)(() => this._clearDraggableAttributes(), 40); - if (editor.plugins.has('DragDropExperimental')) { - this.forceDisabled('DragDropExperimental'); - return; - } - view.addObserver(_clipboardobserver__WEBPACK_IMPORTED_MODULE_5__["default"]); - view.addObserver(_ckeditor_ckeditor5_engine__WEBPACK_IMPORTED_MODULE_1__.MouseObserver); - this._setupDragging(); - this._setupContentInsertionIntegration(); - this._setupClipboardInputIntegration(); - this._setupDropMarker(); - this._setupDraggableAttributeHandling(); - this.listenTo(editor, 'change:isReadOnly', (evt, name, isReadOnly) => { - if (isReadOnly) { - this.forceDisabled('readOnlyMode'); - } - else { - this.clearForceDisabled('readOnlyMode'); - } - }); - this.on('change:isEnabled', (evt, name, isEnabled) => { - if (!isEnabled) { - this._finalizeDragging(false); - } - }); - if (_ckeditor_ckeditor5_utils__WEBPACK_IMPORTED_MODULE_3__.env.isAndroid) { - this.forceDisabled('noAndroidSupport'); - } - } - /** - * @inheritDoc - */ - destroy() { - if (this._draggedRange) { - this._draggedRange.detach(); - this._draggedRange = null; - } - this._updateDropMarkerThrottled.cancel(); - this._removeDropMarkerDelayed.cancel(); - this._clearDraggableAttributesDelayed.cancel(); - return super.destroy(); - } - /** - * Drag and drop events handling. - */ - _setupDragging() { - const editor = this.editor; - const model = editor.model; - const modelDocument = model.document; - const view = editor.editing.view; - const viewDocument = view.document; - // The handler for the drag start; it is responsible for setting data transfer object. - this.listenTo(viewDocument, 'dragstart', (evt, data) => { - const selection = modelDocument.selection; - // Don't drag the editable element itself. - if (data.target && data.target.is('editableElement')) { - data.preventDefault(); - return; - } - // TODO we could clone this node somewhere and style it to match editing view but without handles, - // selection outline, WTA buttons, etc. - // data.dataTransfer._native.setDragImage( data.domTarget, 0, 0 ); - // Check if this is dragstart over the widget (but not a nested editable). - const draggableWidget = data.target ? findDraggableWidget(data.target) : null; - if (draggableWidget) { - const modelElement = editor.editing.mapper.toModelElement(draggableWidget); - this._draggedRange = _ckeditor_ckeditor5_engine__WEBPACK_IMPORTED_MODULE_1__.LiveRange.fromRange(model.createRangeOn(modelElement)); - // Disable toolbars so they won't obscure the drop area. - if (editor.plugins.has('WidgetToolbarRepository')) { - const widgetToolbarRepository = editor.plugins.get('WidgetToolbarRepository'); - widgetToolbarRepository.forceDisabled('dragDrop'); - } - } - // If this was not a widget we should check if we need to drag some text content. - else if (!viewDocument.selection.isCollapsed) { - const selectedElement = viewDocument.selection.getSelectedElement(); - if (!selectedElement || !(0,_ckeditor_ckeditor5_widget__WEBPACK_IMPORTED_MODULE_2__.isWidget)(selectedElement)) { - this._draggedRange = _ckeditor_ckeditor5_engine__WEBPACK_IMPORTED_MODULE_1__.LiveRange.fromRange(selection.getFirstRange()); - } - } - if (!this._draggedRange) { - data.preventDefault(); - return; - } - this._draggingUid = (0,_ckeditor_ckeditor5_utils__WEBPACK_IMPORTED_MODULE_3__.uid)(); - const canEditAtDraggedRange = this.isEnabled && editor.model.canEditAt(this._draggedRange); - data.dataTransfer.effectAllowed = canEditAtDraggedRange ? 'copyMove' : 'copy'; - data.dataTransfer.setData('application/ckeditor5-dragging-uid', this._draggingUid); - const draggedSelection = model.createSelection(this._draggedRange.toRange()); - const content = editor.data.toView(model.getSelectedContent(draggedSelection)); - viewDocument.fire('clipboardOutput', { - dataTransfer: data.dataTransfer, - content, - method: 'dragstart' - }); - if (!canEditAtDraggedRange) { - this._draggedRange.detach(); - this._draggedRange = null; - this._draggingUid = ''; - } - }, { priority: 'low' }); - // The handler for finalizing drag and drop. It should always be triggered after dragging completes - // even if it was completed in a different application. - // Note: This is not fired if source text node got removed while downcasting a marker. - this.listenTo(viewDocument, 'dragend', (evt, data) => { - this._finalizeDragging(!data.dataTransfer.isCanceled && data.dataTransfer.dropEffect == 'move'); - }, { priority: 'low' }); - // Dragging over the editable. - this.listenTo(viewDocument, 'dragenter', () => { - if (!this.isEnabled) { - return; - } - view.focus(); - }); - // Dragging out of the editable. - this.listenTo(viewDocument, 'dragleave', () => { - // We do not know if the mouse left the editor or just some element in it, so let us wait a few milliseconds - // to check if 'dragover' is not fired. - this._removeDropMarkerDelayed(); - }); - // Handler for moving dragged content over the target area. - this.listenTo(viewDocument, 'dragging', (evt, data) => { - if (!this.isEnabled) { - data.dataTransfer.dropEffect = 'none'; - return; - } - this._removeDropMarkerDelayed.cancel(); - const targetRange = findDropTargetRange(editor, data.targetRanges, data.target); - // Do not drop if target place is not editable. - if (!editor.model.canEditAt(targetRange)) { - data.dataTransfer.dropEffect = 'none'; - return; - } - // If this is content being dragged from another editor, moving out of current editor instance - // is not possible until 'dragend' event case will be fixed. - if (!this._draggedRange) { - data.dataTransfer.dropEffect = 'copy'; - } - // In Firefox it is already set and effect allowed remains the same as originally set. - if (!_ckeditor_ckeditor5_utils__WEBPACK_IMPORTED_MODULE_3__.env.isGecko) { - if (data.dataTransfer.effectAllowed == 'copy') { - data.dataTransfer.dropEffect = 'copy'; - } - else if (['all', 'copyMove'].includes(data.dataTransfer.effectAllowed)) { - data.dataTransfer.dropEffect = 'move'; - } - } - /* istanbul ignore else -- @preserve */ - if (targetRange) { - this._updateDropMarkerThrottled(targetRange); - } - }, { priority: 'low' }); - } - /** - * Integration with the `clipboardInput` event. - */ - _setupClipboardInputIntegration() { - const editor = this.editor; - const view = editor.editing.view; - const viewDocument = view.document; - // Update the event target ranges and abort dropping if dropping over itself. - this.listenTo(viewDocument, 'clipboardInput', (evt, data) => { - if (data.method != 'drop') { - return; - } - const targetRange = findDropTargetRange(editor, data.targetRanges, data.target); - // The dragging markers must be removed after searching for the target range because sometimes - // the target lands on the marker itself. - this._removeDropMarker(); - /* istanbul ignore if -- @preserve */ - if (!targetRange || !editor.model.canEditAt(targetRange)) { - this._finalizeDragging(false); - evt.stop(); - return; - } - // Since we cannot rely on the drag end event, we must check if the local drag range is from the current drag and drop - // or it is from some previous not cleared one. - if (this._draggedRange && this._draggingUid != data.dataTransfer.getData('application/ckeditor5-dragging-uid')) { - this._draggedRange.detach(); - this._draggedRange = null; - this._draggingUid = ''; - } - // Do not do anything if some content was dragged within the same document to the same position. - const isMove = getFinalDropEffect(data.dataTransfer) == 'move'; - if (isMove && this._draggedRange && this._draggedRange.containsRange(targetRange, true)) { - this._finalizeDragging(false); - evt.stop(); - return; - } - // Override the target ranges with the one adjusted to the best one for a drop. - data.targetRanges = [editor.editing.mapper.toViewRange(targetRange)]; - }, { priority: 'high' }); - } - /** - * Integration with the `contentInsertion` event of the clipboard pipeline. - */ - _setupContentInsertionIntegration() { - const clipboardPipeline = this.editor.plugins.get(_clipboardpipeline__WEBPACK_IMPORTED_MODULE_4__["default"]); - clipboardPipeline.on('contentInsertion', (evt, data) => { - if (!this.isEnabled || data.method !== 'drop') { - return; - } - // Update the selection to the target range in the same change block to avoid selection post-fixing - // and to be able to clone text attributes for plain text dropping. - const ranges = data.targetRanges.map(viewRange => this.editor.editing.mapper.toModelRange(viewRange)); - this.editor.model.change(writer => writer.setSelection(ranges)); - }, { priority: 'high' }); - clipboardPipeline.on('contentInsertion', (evt, data) => { - if (!this.isEnabled || data.method !== 'drop') { - return; - } - // Remove dragged range content, remove markers, clean after dragging. - const isMove = getFinalDropEffect(data.dataTransfer) == 'move'; - // Whether any content was inserted (insertion might fail if the schema is disallowing some elements - // (for example an image caption allows only the content of a block but not blocks themselves. - // Some integrations might not return valid range (i.e., table pasting). - const isSuccess = !data.resultRange || !data.resultRange.isCollapsed; - this._finalizeDragging(isSuccess && isMove); - }, { priority: 'lowest' }); - } - /** - * Adds listeners that add the `draggable` attribute to the elements while the mouse button is down so the dragging could start. - */ - _setupDraggableAttributeHandling() { - const editor = this.editor; - const view = editor.editing.view; - const viewDocument = view.document; - // Add the 'draggable' attribute to the widget while pressing the selection handle. - // This is required for widgets to be draggable. In Chrome it will enable dragging text nodes. - this.listenTo(viewDocument, 'mousedown', (evt, data) => { - // The lack of data can be caused by editor tests firing fake mouse events. This should not occur - // in real-life scenarios but this greatly simplifies editor tests that would otherwise fail a lot. - if (_ckeditor_ckeditor5_utils__WEBPACK_IMPORTED_MODULE_3__.env.isAndroid || !data) { - return; - } - this._clearDraggableAttributesDelayed.cancel(); - // Check if this is a mousedown over the widget (but not a nested editable). - let draggableElement = findDraggableWidget(data.target); - // Note: There is a limitation that if more than a widget is selected (a widget and some text) - // and dragging starts on the widget, then only the widget is dragged. - // If this was not a widget then we should check if we need to drag some text content. - // In Chrome set a 'draggable' attribute on closest editable to allow immediate dragging of the selected text range. - // In Firefox this is not needed. In Safari it makes the whole editable draggable (not just textual content). - // Disabled in read-only mode because draggable="true" + contenteditable="false" results - // in not firing selectionchange event ever, which makes the selection stuck in read-only mode. - if (_ckeditor_ckeditor5_utils__WEBPACK_IMPORTED_MODULE_3__.env.isBlink && !draggableElement && !viewDocument.selection.isCollapsed) { - const selectedElement = viewDocument.selection.getSelectedElement(); - if (!selectedElement || !(0,_ckeditor_ckeditor5_widget__WEBPACK_IMPORTED_MODULE_2__.isWidget)(selectedElement)) { - const editableElement = viewDocument.selection.editableElement; - if (editableElement && !editableElement.isReadOnly) { - draggableElement = editableElement; - } - } - } - if (draggableElement) { - view.change(writer => { - writer.setAttribute('draggable', 'true', draggableElement); - }); - // Keep the reference to the model element in case the view element gets removed while dragging. - this._draggableElement = editor.editing.mapper.toModelElement(draggableElement); - } - }); - // Remove the draggable attribute in case no dragging started (only mousedown + mouseup). - this.listenTo(viewDocument, 'mouseup', () => { - if (!_ckeditor_ckeditor5_utils__WEBPACK_IMPORTED_MODULE_3__.env.isAndroid) { - this._clearDraggableAttributesDelayed(); - } - }); - } - /** - * Removes the `draggable` attribute from the element that was used for dragging. - */ - _clearDraggableAttributes() { - const editing = this.editor.editing; - editing.view.change(writer => { - // Remove 'draggable' attribute. - if (this._draggableElement && this._draggableElement.root.rootName != '$graveyard') { - writer.removeAttribute('draggable', editing.mapper.toViewElement(this._draggableElement)); - } - this._draggableElement = null; - }); - } - /** - * Creates downcast conversion for the drop target marker. - */ - _setupDropMarker() { - const editor = this.editor; - // Drop marker conversion for hovering over widgets. - editor.conversion.for('editingDowncast').markerToHighlight({ - model: 'drop-target', - view: { - classes: ['ck-clipboard-drop-target-range'] - } - }); - // Drop marker conversion for in text drop target. - editor.conversion.for('editingDowncast').markerToElement({ - model: 'drop-target', - view: (data, { writer }) => { - const inText = editor.model.schema.checkChild(data.markerRange.start, '$text'); - if (!inText) { - return; - } - return writer.createUIElement('span', { class: 'ck ck-clipboard-drop-target-position' }, function (domDocument) { - const domElement = this.toDomElement(domDocument); - // Using word joiner to make this marker as high as text and also making text not break on marker. - domElement.append('\u2060', domDocument.createElement('span'), '\u2060'); - return domElement; - }); - } - }); - } - /** - * Updates the drop target marker to the provided range. - * - * @param targetRange The range to set the marker to. - */ - _updateDropMarker(targetRange) { - const editor = this.editor; - const markers = editor.model.markers; - editor.model.change(writer => { - if (markers.has('drop-target')) { - if (!markers.get('drop-target').getRange().isEqual(targetRange)) { - writer.updateMarker('drop-target', { range: targetRange }); - } - } - else { - writer.addMarker('drop-target', { - range: targetRange, - usingOperation: false, - affectsData: false - }); - } - }); - } - /** - * Removes the drop target marker. - */ - _removeDropMarker() { - const model = this.editor.model; - this._removeDropMarkerDelayed.cancel(); - this._updateDropMarkerThrottled.cancel(); - if (model.markers.has('drop-target')) { - model.change(writer => { - writer.removeMarker('drop-target'); - }); - } - } - /** - * Deletes the dragged content from its original range and clears the dragging state. - * - * @param moved Whether the move succeeded. - */ - _finalizeDragging(moved) { - const editor = this.editor; - const model = editor.model; - this._removeDropMarker(); - this._clearDraggableAttributes(); - if (editor.plugins.has('WidgetToolbarRepository')) { - const widgetToolbarRepository = editor.plugins.get('WidgetToolbarRepository'); - widgetToolbarRepository.clearForceDisabled('dragDrop'); - } - this._draggingUid = ''; - if (!this._draggedRange) { - return; - } - // Delete moved content. - if (moved && this.isEnabled) { - model.deleteContent(model.createSelection(this._draggedRange), { doNotAutoparagraph: true }); - } - this._draggedRange.detach(); - this._draggedRange = null; - } -} -/** - * Returns fixed selection range for given position and target element. - */ -function findDropTargetRange(editor, targetViewRanges, targetViewElement) { - const model = editor.model; - const mapper = editor.editing.mapper; - let range = null; - const targetViewPosition = targetViewRanges ? targetViewRanges[0].start : null; - // A UIElement is not a valid drop element, use parent (this could be a drop marker or any other UIElement). - if (targetViewElement.is('uiElement')) { - targetViewElement = targetViewElement.parent; - } - // Quick win if the target is a widget (but not a nested editable). - range = findDropTargetRangeOnWidget(editor, targetViewElement); - if (range) { - return range; - } - // The easiest part is over, now we need to move to the model space. - // Find target model element and position. - const targetModelElement = getClosestMappedModelElement(editor, targetViewElement); - const targetModelPosition = targetViewPosition ? mapper.toModelPosition(targetViewPosition) : null; - // There is no target position while hovering over an empty table cell. - // In Safari, target position can be empty while hovering over a widget (e.g., a page-break). - // Find the drop position inside the element. - if (!targetModelPosition) { - return findDropTargetRangeInElement(editor, targetModelElement); - } - // Check if target position is between blocks and adjust drop position to the next object. - // This is because while hovering over a root element next to a widget the target position can jump in crazy places. - range = findDropTargetRangeBetweenBlocks(editor, targetModelPosition, targetModelElement); - if (range) { - return range; - } - // Try fixing selection position. - // In Firefox, the target position lands before widgets but in other browsers it tends to land after a widget. - range = model.schema.getNearestSelectionRange(targetModelPosition, _ckeditor_ckeditor5_utils__WEBPACK_IMPORTED_MODULE_3__.env.isGecko ? 'forward' : 'backward'); - if (range) { - return range; - } - // There is no valid selection position inside the current limit element so find a closest object ancestor. - // This happens if the model position lands directly in the element itself (view target element was a `
` - // so a nested editable, but view target position was directly in the ` ` element). - return findDropTargetRangeOnAncestorObject(editor, targetModelPosition.parent); -} -/** - * Returns fixed selection range for a given position and a target element if it is over the widget but not over its nested editable. - */ -function findDropTargetRangeOnWidget(editor, targetViewElement) { - const model = editor.model; - const mapper = editor.editing.mapper; - // Quick win if the target is a widget. - if ((0,_ckeditor_ckeditor5_widget__WEBPACK_IMPORTED_MODULE_2__.isWidget)(targetViewElement)) { - return model.createRangeOn(mapper.toModelElement(targetViewElement)); - } - // Check if we are deeper over a widget (but not over a nested editable). - if (!targetViewElement.is('editableElement')) { - // Find a closest ancestor that is either a widget or an editable element... - const ancestor = targetViewElement.findAncestor(node => (0,_ckeditor_ckeditor5_widget__WEBPACK_IMPORTED_MODULE_2__.isWidget)(node) || node.is('editableElement')); - // ...and if the widget was closer then it is a drop target. - if ((0,_ckeditor_ckeditor5_widget__WEBPACK_IMPORTED_MODULE_2__.isWidget)(ancestor)) { - return model.createRangeOn(mapper.toModelElement(ancestor)); - } - } - return null; -} -/** - * Returns fixed selection range inside a model element. - */ -function findDropTargetRangeInElement(editor, targetModelElement) { - const model = editor.model; - const schema = model.schema; - const positionAtElementStart = model.createPositionAt(targetModelElement, 0); - return schema.getNearestSelectionRange(positionAtElementStart, 'forward'); -} -/** - * Returns fixed selection range for a given position and a target element if the drop is between blocks. - */ -function findDropTargetRangeBetweenBlocks(editor, targetModelPosition, targetModelElement) { - const model = editor.model; - // Check if target is between blocks. - if (!model.schema.checkChild(targetModelElement, '$block')) { - return null; - } - // Find position between blocks. - const positionAtElementStart = model.createPositionAt(targetModelElement, 0); - // Get the common part of the path (inside the target element and the target position). - const commonPath = targetModelPosition.path.slice(0, positionAtElementStart.path.length); - // Position between the blocks. - const betweenBlocksPosition = model.createPositionFromPath(targetModelPosition.root, commonPath); - const nodeAfter = betweenBlocksPosition.nodeAfter; - // Adjust drop position to the next object. - // This is because while hovering over a root element next to a widget the target position can jump in crazy places. - if (nodeAfter && model.schema.isObject(nodeAfter)) { - return model.createRangeOn(nodeAfter); - } - return null; -} -/** - * Returns a selection range on the ancestor object. - */ -function findDropTargetRangeOnAncestorObject(editor, element) { - const model = editor.model; - let currentElement = element; - while (currentElement) { - if (model.schema.isObject(currentElement)) { - return model.createRangeOn(currentElement); - } - currentElement = currentElement.parent; - } - /* istanbul ignore next -- @preserve */ - return null; -} -/** - * Returns the closest model element for the specified view element. - */ -function getClosestMappedModelElement(editor, element) { - const mapper = editor.editing.mapper; - const view = editor.editing.view; - const targetModelElement = mapper.toModelElement(element); - if (targetModelElement) { - return targetModelElement; - } - // Find mapped ancestor if the target is inside not mapped element (for example inline code element). - const viewPosition = view.createPositionBefore(element); - const viewElement = mapper.findMappedViewAncestor(viewPosition); - return mapper.toModelElement(viewElement); -} -/** - * Returns the drop effect that should be a result of dragging the content. - * This function is handling a quirk when checking the effect in the 'drop' DOM event. - */ -function getFinalDropEffect(dataTransfer) { - if (_ckeditor_ckeditor5_utils__WEBPACK_IMPORTED_MODULE_3__.env.isGecko) { - return dataTransfer.dropEffect; - } - return ['all', 'copyMove'].includes(dataTransfer.effectAllowed) ? 'move' : 'copy'; -} -/** - * Returns a widget element that should be dragged. - */ -function findDraggableWidget(target) { - // This is directly an editable so not a widget for sure. - if (target.is('editableElement')) { - return null; - } - // TODO: Let's have a isWidgetSelectionHandleDomElement() helper in ckeditor5-widget utils. - if (target.hasClass('ck-widget__selection-handle')) { - return target.findAncestor(_ckeditor_ckeditor5_widget__WEBPACK_IMPORTED_MODULE_2__.isWidget); - } - // Direct hit on a widget. - if ((0,_ckeditor_ckeditor5_widget__WEBPACK_IMPORTED_MODULE_2__.isWidget)(target)) { - return target; - } - // Find closest ancestor that is either a widget or an editable element... - const ancestor = target.findAncestor(node => (0,_ckeditor_ckeditor5_widget__WEBPACK_IMPORTED_MODULE_2__.isWidget)(node) || node.is('editableElement')); - // ...and if closer was the widget then enable dragging it. - if ((0,_ckeditor_ckeditor5_widget__WEBPACK_IMPORTED_MODULE_2__.isWidget)(ancestor)) { - return ancestor; - } - return null; -} - - -/***/ }), - -/***/ "./node_modules/@ckeditor/ckeditor5-clipboard/src/dragdropblocktoolbar.js": -/*!********************************************************************************!*\ - !*** ./node_modules/@ckeditor/ckeditor5-clipboard/src/dragdropblocktoolbar.js ***! - \********************************************************************************/ -/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { - -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export */ __webpack_require__.d(__webpack_exports__, { -/* harmony export */ "default": () => (/* binding */ DragDropBlockToolbar) -/* harmony export */ }); -/* harmony import */ var _ckeditor_ckeditor5_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @ckeditor/ckeditor5-core */ "./node_modules/@ckeditor/ckeditor5-core/src/index.js"); -/* harmony import */ var _ckeditor_ckeditor5_utils__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @ckeditor/ckeditor5-utils */ "./node_modules/@ckeditor/ckeditor5-utils/src/index.js"); -/* harmony import */ var _clipboardobserver__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./clipboardobserver */ "./node_modules/@ckeditor/ckeditor5-clipboard/src/clipboardobserver.js"); -/** - * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved. - * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license - */ -/** - * @module clipboard/dragdropblocktoolbar - */ -/* istanbul ignore file -- @preserve */ - - - -/** - * Integration of an experimental block Drag and drop support with the block toolbar. - * - * @internal - */ -class DragDropBlockToolbar extends _ckeditor_ckeditor5_core__WEBPACK_IMPORTED_MODULE_0__.Plugin { - constructor() { - super(...arguments); - /** - * Whether current dragging is started by block toolbar button dragging. - */ - this._isBlockDragging = false; - /** - * DOM Emitter. - */ - this._domEmitter = new ((0,_ckeditor_ckeditor5_utils__WEBPACK_IMPORTED_MODULE_1__.DomEmitterMixin)())(); - } - /** - * @inheritDoc - */ - static get pluginName() { - return 'DragDropBlockToolbar'; - } - /** - * @inheritDoc - */ - init() { - const editor = this.editor; - this.listenTo(editor, 'change:isReadOnly', (evt, name, isReadOnly) => { - if (isReadOnly) { - this.forceDisabled('readOnlyMode'); - this._isBlockDragging = false; - } - else { - this.clearForceDisabled('readOnlyMode'); - } - }); - if (_ckeditor_ckeditor5_utils__WEBPACK_IMPORTED_MODULE_1__.env.isAndroid) { - this.forceDisabled('noAndroidSupport'); - } - if (editor.plugins.has('BlockToolbar')) { - const blockToolbar = editor.plugins.get('BlockToolbar'); - const element = blockToolbar.buttonView.element; - element.setAttribute('draggable', 'true'); - this._domEmitter.listenTo(element, 'dragstart', (evt, data) => this._handleBlockDragStart(data)); - this._domEmitter.listenTo(_ckeditor_ckeditor5_utils__WEBPACK_IMPORTED_MODULE_1__.global.document, 'dragover', (evt, data) => this._handleBlockDragging(data)); - this._domEmitter.listenTo(_ckeditor_ckeditor5_utils__WEBPACK_IMPORTED_MODULE_1__.global.document, 'drop', (evt, data) => this._handleBlockDragging(data)); - this._domEmitter.listenTo(_ckeditor_ckeditor5_utils__WEBPACK_IMPORTED_MODULE_1__.global.document, 'dragend', () => this._handleBlockDragEnd(), { useCapture: true }); - } - } - /** - * @inheritDoc - */ - destroy() { - this._domEmitter.stopListening(); - return super.destroy(); - } - /** - * The `dragstart` event handler. - */ - _handleBlockDragStart(domEvent) { - if (!this.isEnabled) { - return; - } - const model = this.editor.model; - const selection = model.document.selection; - const blocks = Array.from(selection.getSelectedBlocks()); - const draggedRange = model.createRange(model.createPositionBefore(blocks[0]), model.createPositionAfter(blocks[blocks.length - 1])); - model.change(writer => writer.setSelection(draggedRange)); - this._isBlockDragging = true; - this.editor.editing.view.getObserver(_clipboardobserver__WEBPACK_IMPORTED_MODULE_2__["default"]).onDomEvent(domEvent); - } - /** - * The `dragover` and `drop` event handler. - */ - _handleBlockDragging(domEvent) { - if (!this.isEnabled || !this._isBlockDragging) { - return; - } - const clientX = domEvent.clientX + 100; - const clientY = domEvent.clientY; - const target = document.elementFromPoint(clientX, clientY); - if (!target || !target.closest('.ck-editor__editable')) { - return; - } - this.editor.editing.view.getObserver(_clipboardobserver__WEBPACK_IMPORTED_MODULE_2__["default"]).onDomEvent({ - ...domEvent, - type: domEvent.type, - dataTransfer: domEvent.dataTransfer, - target, - clientX, - clientY, - preventDefault: () => domEvent.preventDefault(), - stopPropagation: () => domEvent.stopPropagation() - }); - } - /** - * The `dragend` event handler. - */ - _handleBlockDragEnd() { - this._isBlockDragging = false; - } -} - - -/***/ }), - -/***/ "./node_modules/@ckeditor/ckeditor5-clipboard/src/dragdropexperimental.js": -/*!********************************************************************************!*\ - !*** ./node_modules/@ckeditor/ckeditor5-clipboard/src/dragdropexperimental.js ***! - \********************************************************************************/ -/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { - -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export */ __webpack_require__.d(__webpack_exports__, { -/* harmony export */ "default": () => (/* binding */ DragDropExperimental) -/* harmony export */ }); -/* harmony import */ var _ckeditor_ckeditor5_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @ckeditor/ckeditor5-core */ "./node_modules/@ckeditor/ckeditor5-core/src/index.js"); -/* harmony import */ var _ckeditor_ckeditor5_engine__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @ckeditor/ckeditor5-engine */ "./node_modules/@ckeditor/ckeditor5-engine/src/index.js"); -/* harmony import */ var _ckeditor_ckeditor5_widget__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @ckeditor/ckeditor5-widget */ "./node_modules/@ckeditor/ckeditor5-widget/src/index.js"); -/* harmony import */ var _ckeditor_ckeditor5_utils__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @ckeditor/ckeditor5-utils */ "./node_modules/@ckeditor/ckeditor5-utils/src/index.js"); -/* harmony import */ var _clipboardpipeline__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./clipboardpipeline */ "./node_modules/@ckeditor/ckeditor5-clipboard/src/clipboardpipeline.js"); -/* harmony import */ var _clipboardobserver__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./clipboardobserver */ "./node_modules/@ckeditor/ckeditor5-clipboard/src/clipboardobserver.js"); -/* harmony import */ var _dragdroptarget__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./dragdroptarget */ "./node_modules/@ckeditor/ckeditor5-clipboard/src/dragdroptarget.js"); -/* harmony import */ var _theme_clipboard_css__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ../theme/clipboard.css */ "./node_modules/@ckeditor/ckeditor5-clipboard/theme/clipboard.css"); -/** - * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved. - * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license - */ -/** - * @module clipboard/dragdropexperimental - */ -/* istanbul ignore file -- @preserve */ - - - - - - - - -// Drag and drop events overview: -// -// ┌──────────────────┐ -// │ mousedown │ Sets the draggable attribute. -// └─────────┬────────┘ -// │ -// └─────────────────────┐ -// │ │ -// │ ┌─────────V────────┐ -// │ │ mouseup │ Dragging did not start, removes the draggable attribute. -// │ └──────────────────┘ -// │ -// ┌─────────V────────┐ Retrieves the selected model.DocumentFragment -// │ dragstart │ and converts it to view.DocumentFragment. -// └─────────┬────────┘ -// │ -// ┌─────────V────────┐ Processes view.DocumentFragment to text/html and text/plain -// │ clipboardOutput │ and stores the results in data.dataTransfer. -// └─────────┬────────┘ -// │ -// │ DOM dragover -// ┌────────────┐ -// │ │ -// ┌─────────V────────┐ │ -// │ dragging │ │ Updates the drop target marker. -// └─────────┬────────┘ │ -// │ │ -// ┌─────────────└────────────┘ -// │ │ │ -// │ ┌─────────V────────┐ │ -// │ │ dragleave │ │ Removes the drop target marker. -// │ └─────────┬────────┘ │ -// │ │ │ -// ┌───│─────────────┘ │ -// │ │ │ │ -// │ │ ┌─────────V────────┐ │ -// │ │ │ dragenter │ │ Focuses the editor view. -// │ │ └─────────┬────────┘ │ -// │ │ │ │ -// │ │ └────────────┘ -// │ │ -// │ └─────────────┐ -// │ │ │ -// │ │ ┌─────────V────────┐ -// └───┐ │ drop │ (The default handler of the clipboard pipeline). -// │ └─────────┬────────┘ -// │ │ -// │ ┌─────────V────────┐ Resolves the final data.targetRanges. -// │ │ clipboardInput │ Aborts if dropping on dragged content. -// │ └─────────┬────────┘ -// │ │ -// │ ┌─────────V────────┐ -// │ │ clipboardInput │ (The default handler of the clipboard pipeline). -// │ └─────────┬────────┘ -// │ │ -// │ ┌───────────V───────────┐ -// │ │ inputTransformation │ (The default handler of the clipboard pipeline). -// │ └───────────┬───────────┘ -// │ │ -// │ ┌──────────V──────────┐ -// │ │ contentInsertion │ Updates the document selection to drop range. -// │ └──────────┬──────────┘ -// │ │ -// │ ┌──────────V──────────┐ -// │ │ contentInsertion │ (The default handler of the clipboard pipeline). -// │ └──────────┬──────────┘ -// │ │ -// │ ┌──────────V──────────┐ -// │ │ contentInsertion │ Removes the content from the original range if the insertion was successful. -// │ └──────────┬──────────┘ -// │ │ -// └─────────────┐ -// │ -// ┌─────────V────────┐ -// │ dragend │ Removes the drop marker and cleans the state. -// └──────────────────┘ -// -/** - * The drag and drop feature. It works on top of the {@link module:clipboard/clipboardpipeline~ClipboardPipeline}. - * - * Read more about the clipboard integration in the {@glink framework/deep-dive/clipboard clipboard deep-dive} guide. - * - * @internal - */ -class DragDropExperimental extends _ckeditor_ckeditor5_core__WEBPACK_IMPORTED_MODULE_0__.Plugin { - constructor() { - super(...arguments); - /** - * A delayed callback removing draggable attributes. - */ - this._clearDraggableAttributesDelayed = (0,_ckeditor_ckeditor5_utils__WEBPACK_IMPORTED_MODULE_3__.delay)(() => this._clearDraggableAttributes(), 40); - /** - * Whether the dragged content can be dropped only in block context. - */ - // TODO handle drag from other editor instance - // TODO configure to use block, inline or both - this._blockMode = false; - /** - * DOM Emitter. - */ - this._domEmitter = new ((0,_ckeditor_ckeditor5_utils__WEBPACK_IMPORTED_MODULE_3__.DomEmitterMixin)())(); - } - /** - * @inheritDoc - */ - static get pluginName() { - return 'DragDropExperimental'; - } - /** - * @inheritDoc - */ - static get requires() { - return [_clipboardpipeline__WEBPACK_IMPORTED_MODULE_4__["default"], _ckeditor_ckeditor5_widget__WEBPACK_IMPORTED_MODULE_2__.Widget, _dragdroptarget__WEBPACK_IMPORTED_MODULE_6__["default"]]; - } - /** - * @inheritDoc - */ - init() { - const editor = this.editor; - const view = editor.editing.view; - this._draggedRange = null; - this._draggingUid = ''; - this._draggableElement = null; - view.addObserver(_clipboardobserver__WEBPACK_IMPORTED_MODULE_5__["default"]); - view.addObserver(_ckeditor_ckeditor5_engine__WEBPACK_IMPORTED_MODULE_1__.MouseObserver); - this._setupDragging(); - this._setupContentInsertionIntegration(); - this._setupClipboardInputIntegration(); - this._setupDraggableAttributeHandling(); - this.listenTo(editor, 'change:isReadOnly', (evt, name, isReadOnly) => { - if (isReadOnly) { - this.forceDisabled('readOnlyMode'); - } - else { - this.clearForceDisabled('readOnlyMode'); - } - }); - this.on('change:isEnabled', (evt, name, isEnabled) => { - if (!isEnabled) { - this._finalizeDragging(false); - } - }); - if (_ckeditor_ckeditor5_utils__WEBPACK_IMPORTED_MODULE_3__.env.isAndroid) { - this.forceDisabled('noAndroidSupport'); - } - } - /** - * @inheritDoc - */ - destroy() { - if (this._draggedRange) { - this._draggedRange.detach(); - this._draggedRange = null; - } - if (this._previewContainer) { - this._previewContainer.remove(); - } - this._domEmitter.stopListening(); - this._clearDraggableAttributesDelayed.cancel(); - return super.destroy(); - } - /** - * Drag and drop events handling. - */ - _setupDragging() { - const editor = this.editor; - const model = editor.model; - const view = editor.editing.view; - const viewDocument = view.document; - const dragDropTarget = editor.plugins.get(_dragdroptarget__WEBPACK_IMPORTED_MODULE_6__["default"]); - // The handler for the drag start; it is responsible for setting data transfer object. - this.listenTo(viewDocument, 'dragstart', (evt, data) => { - // Don't drag the editable element itself. - if (data.target && data.target.is('editableElement')) { - data.preventDefault(); - return; - } - this._prepareDraggedRange(data.target); - if (!this._draggedRange) { - data.preventDefault(); - return; - } - this._draggingUid = (0,_ckeditor_ckeditor5_utils__WEBPACK_IMPORTED_MODULE_3__.uid)(); - data.dataTransfer.effectAllowed = this.isEnabled ? 'copyMove' : 'copy'; - data.dataTransfer.setData('application/ckeditor5-dragging-uid', this._draggingUid); - const draggedSelection = model.createSelection(this._draggedRange.toRange()); - const content = editor.data.toView(model.getSelectedContent(draggedSelection)); - viewDocument.fire('clipboardOutput', { - dataTransfer: data.dataTransfer, - content, - method: 'dragstart' - }); - this._updatePreview(data.dataTransfer); - data.stopPropagation(); - if (!this.isEnabled) { - this._draggedRange.detach(); - this._draggedRange = null; - this._draggingUid = ''; - } - }, { priority: 'low' }); - // The handler for finalizing drag and drop. It should always be triggered after dragging completes - // even if it was completed in a different application. - // Note: This is not fired if source text node got removed while downcasting a marker. - this.listenTo(viewDocument, 'dragend', (evt, data) => { - this._finalizeDragging(!data.dataTransfer.isCanceled && data.dataTransfer.dropEffect == 'move'); - }, { priority: 'low' }); - // Reset block dragging mode even if dropped outside the editable. - this._domEmitter.listenTo(_ckeditor_ckeditor5_utils__WEBPACK_IMPORTED_MODULE_3__.global.document, 'dragend', () => { - this._blockMode = false; - }, { useCapture: true }); - // Dragging over the editable. - this.listenTo(viewDocument, 'dragenter', () => { - if (!this.isEnabled) { - return; - } - view.focus(); - }); - // Dragging out of the editable. - this.listenTo(viewDocument, 'dragleave', () => { - // We do not know if the mouse left the editor or just some element in it, so let us wait a few milliseconds - // to check if 'dragover' is not fired. - dragDropTarget.removeDropMarkerDelayed(); - }); - // Handler for moving dragged content over the target area. - this.listenTo(viewDocument, 'dragging', (evt, data) => { - if (!this.isEnabled) { - data.dataTransfer.dropEffect = 'none'; - return; - } - const { clientX, clientY } = data.domEvent; - dragDropTarget.updateDropMarker(data.target, data.targetRanges, clientX, clientY, this._blockMode); - // If this is content being dragged from another editor, moving out of current editor instance - // is not possible until 'dragend' event case will be fixed. - if (!this._draggedRange) { - data.dataTransfer.dropEffect = 'copy'; - } - // In Firefox it is already set and effect allowed remains the same as originally set. - if (!_ckeditor_ckeditor5_utils__WEBPACK_IMPORTED_MODULE_3__.env.isGecko) { - if (data.dataTransfer.effectAllowed == 'copy') { - data.dataTransfer.dropEffect = 'copy'; - } - else if (['all', 'copyMove'].includes(data.dataTransfer.effectAllowed)) { - data.dataTransfer.dropEffect = 'move'; - } - } - evt.stop(); - }, { priority: 'low' }); - } - /** - * Integration with the `clipboardInput` event. - */ - _setupClipboardInputIntegration() { - const editor = this.editor; - const view = editor.editing.view; - const viewDocument = view.document; - const dragDropTarget = editor.plugins.get(_dragdroptarget__WEBPACK_IMPORTED_MODULE_6__["default"]); - // Update the event target ranges and abort dropping if dropping over itself. - this.listenTo(viewDocument, 'clipboardInput', (evt, data) => { - if (data.method != 'drop') { - return; - } - const { clientX, clientY } = data.domEvent; - const targetRange = dragDropTarget.getFinalDropRange(data.target, data.targetRanges, clientX, clientY, this._blockMode); - /* istanbul ignore if -- @preserve */ - if (!targetRange) { - this._finalizeDragging(false); - evt.stop(); - return; - } - // Since we cannot rely on the drag end event, we must check if the local drag range is from the current drag and drop - // or it is from some previous not cleared one. - if (this._draggedRange && this._draggingUid != data.dataTransfer.getData('application/ckeditor5-dragging-uid')) { - this._draggedRange.detach(); - this._draggedRange = null; - this._draggingUid = ''; - } - // Do not do anything if some content was dragged within the same document to the same position. - const isMove = getFinalDropEffect(data.dataTransfer) == 'move'; - if (isMove && this._draggedRange && this._draggedRange.containsRange(targetRange, true)) { - this._finalizeDragging(false); - evt.stop(); - return; - } - // Override the target ranges with the one adjusted to the best one for a drop. - data.targetRanges = [editor.editing.mapper.toViewRange(targetRange)]; - }, { priority: 'high' }); - } - /** - * Integration with the `contentInsertion` event of the clipboard pipeline. - */ - _setupContentInsertionIntegration() { - const clipboardPipeline = this.editor.plugins.get(_clipboardpipeline__WEBPACK_IMPORTED_MODULE_4__["default"]); - clipboardPipeline.on('contentInsertion', (evt, data) => { - if (!this.isEnabled || data.method !== 'drop') { - return; - } - // Update the selection to the target range in the same change block to avoid selection post-fixing - // and to be able to clone text attributes for plain text dropping. - const ranges = data.targetRanges.map(viewRange => this.editor.editing.mapper.toModelRange(viewRange)); - this.editor.model.change(writer => writer.setSelection(ranges)); - }, { priority: 'high' }); - clipboardPipeline.on('contentInsertion', (evt, data) => { - if (!this.isEnabled || data.method !== 'drop') { - return; - } - // Remove dragged range content, remove markers, clean after dragging. - const isMove = getFinalDropEffect(data.dataTransfer) == 'move'; - // Whether any content was inserted (insertion might fail if the schema is disallowing some elements - // (for example an image caption allows only the content of a block but not blocks themselves. - // Some integrations might not return valid range (i.e., table pasting). - const isSuccess = !data.resultRange || !data.resultRange.isCollapsed; - this._finalizeDragging(isSuccess && isMove); - }, { priority: 'lowest' }); - } - /** - * Adds listeners that add the `draggable` attribute to the elements while the mouse button is down so the dragging could start. - */ - _setupDraggableAttributeHandling() { - const editor = this.editor; - const view = editor.editing.view; - const viewDocument = view.document; - // Add the 'draggable' attribute to the widget while pressing the selection handle. - // This is required for widgets to be draggable. In Chrome it will enable dragging text nodes. - this.listenTo(viewDocument, 'mousedown', (evt, data) => { - // The lack of data can be caused by editor tests firing fake mouse events. This should not occur - // in real-life scenarios but this greatly simplifies editor tests that would otherwise fail a lot. - if (_ckeditor_ckeditor5_utils__WEBPACK_IMPORTED_MODULE_3__.env.isAndroid || !data) { - return; - } - this._clearDraggableAttributesDelayed.cancel(); - // Check if this is a mousedown over the widget (but not a nested editable). - let draggableElement = findDraggableWidget(data.target); - // Note: There is a limitation that if more than a widget is selected (a widget and some text) - // and dragging starts on the widget, then only the widget is dragged. - // If this was not a widget then we should check if we need to drag some text content. - // In Chrome set a 'draggable' attribute on closest editable to allow immediate dragging of the selected text range. - // In Firefox this is not needed. In Safari it makes the whole editable draggable (not just textual content). - // Disabled in read-only mode because draggable="true" + contenteditable="false" results - // in not firing selectionchange event ever, which makes the selection stuck in read-only mode. - if (_ckeditor_ckeditor5_utils__WEBPACK_IMPORTED_MODULE_3__.env.isBlink && !editor.isReadOnly && !draggableElement && !viewDocument.selection.isCollapsed) { - const selectedElement = viewDocument.selection.getSelectedElement(); - if (!selectedElement || !(0,_ckeditor_ckeditor5_widget__WEBPACK_IMPORTED_MODULE_2__.isWidget)(selectedElement)) { - draggableElement = viewDocument.selection.editableElement; - } - } - if (draggableElement) { - view.change(writer => { - writer.setAttribute('draggable', 'true', draggableElement); - }); - // Keep the reference to the model element in case the view element gets removed while dragging. - this._draggableElement = editor.editing.mapper.toModelElement(draggableElement); - } - }); - // Remove the draggable attribute in case no dragging started (only mousedown + mouseup). - this.listenTo(viewDocument, 'mouseup', () => { - if (!_ckeditor_ckeditor5_utils__WEBPACK_IMPORTED_MODULE_3__.env.isAndroid) { - this._clearDraggableAttributesDelayed(); - } - }); - } - /** - * Removes the `draggable` attribute from the element that was used for dragging. - */ - _clearDraggableAttributes() { - const editing = this.editor.editing; - editing.view.change(writer => { - // Remove 'draggable' attribute. - if (this._draggableElement && this._draggableElement.root.rootName != '$graveyard') { - writer.removeAttribute('draggable', editing.mapper.toViewElement(this._draggableElement)); - } - this._draggableElement = null; - }); - } - /** - * Deletes the dragged content from its original range and clears the dragging state. - * - * @param moved Whether the move succeeded. - */ - _finalizeDragging(moved) { - const editor = this.editor; - const model = editor.model; - const dragDropTarget = editor.plugins.get(_dragdroptarget__WEBPACK_IMPORTED_MODULE_6__["default"]); - dragDropTarget.removeDropMarker(); - this._clearDraggableAttributes(); - if (editor.plugins.has('WidgetToolbarRepository')) { - const widgetToolbarRepository = editor.plugins.get('WidgetToolbarRepository'); - widgetToolbarRepository.clearForceDisabled('dragDrop'); - } - this._draggingUid = ''; - if (this._previewContainer) { - this._previewContainer.remove(); - this._previewContainer = undefined; - } - if (!this._draggedRange) { - return; - } - // Delete moved content. - if (moved && this.isEnabled) { - model.deleteContent(model.createSelection(this._draggedRange), { doNotAutoparagraph: true }); - } - this._draggedRange.detach(); - this._draggedRange = null; - } - /** - * Sets the dragged source range based on event target and document selection. - */ - _prepareDraggedRange(target) { - const editor = this.editor; - const model = editor.model; - const selection = model.document.selection; - // Check if this is dragstart over the widget (but not a nested editable). - const draggableWidget = target ? findDraggableWidget(target) : null; - if (draggableWidget) { - const modelElement = editor.editing.mapper.toModelElement(draggableWidget); - this._draggedRange = _ckeditor_ckeditor5_engine__WEBPACK_IMPORTED_MODULE_1__.LiveRange.fromRange(model.createRangeOn(modelElement)); - this._blockMode = model.schema.isBlock(modelElement); - // Disable toolbars so they won't obscure the drop area. - if (editor.plugins.has('WidgetToolbarRepository')) { - const widgetToolbarRepository = editor.plugins.get('WidgetToolbarRepository'); - widgetToolbarRepository.forceDisabled('dragDrop'); - } - } - // If this was not a widget we should check if we need to drag some text content. - else if (!selection.isCollapsed || selection.getFirstPosition().parent.isEmpty) { - const blocks = Array.from(selection.getSelectedBlocks()); - if (blocks.length > 1) { - this._draggedRange = _ckeditor_ckeditor5_engine__WEBPACK_IMPORTED_MODULE_1__.LiveRange.fromRange(model.createRange(model.createPositionBefore(blocks[0]), model.createPositionAfter(blocks[blocks.length - 1]))); - model.change(writer => writer.setSelection(this._draggedRange.toRange())); - this._blockMode = true; - // TODO block mode for dragging from outside editor? or inline? or both? - } - else if (blocks.length == 1) { - const draggedRange = selection.getFirstRange(); - const blockRange = model.createRange(model.createPositionBefore(blocks[0]), model.createPositionAfter(blocks[0])); - if (draggedRange.start.isTouching(blockRange.start) && - draggedRange.end.isTouching(blockRange.end)) { - this._draggedRange = _ckeditor_ckeditor5_engine__WEBPACK_IMPORTED_MODULE_1__.LiveRange.fromRange(blockRange); - this._blockMode = true; - } - else { - this._draggedRange = _ckeditor_ckeditor5_engine__WEBPACK_IMPORTED_MODULE_1__.LiveRange.fromRange(selection.getFirstRange()); - this._blockMode = false; - } - } - } - } - /** - * Updates the dragged preview image. - */ - _updatePreview(dataTransfer) { - const view = this.editor.editing.view; - const editable = view.document.selection.editableElement; - const domEditable = view.domConverter.mapViewToDom(editable); - const computedStyle = _ckeditor_ckeditor5_utils__WEBPACK_IMPORTED_MODULE_3__.global.window.getComputedStyle(domEditable); - if (!this._previewContainer) { - this._previewContainer = (0,_ckeditor_ckeditor5_utils__WEBPACK_IMPORTED_MODULE_3__.createElement)(_ckeditor_ckeditor5_utils__WEBPACK_IMPORTED_MODULE_3__.global.document, 'div', { - style: 'position: fixed; left: -999999px;' - }); - _ckeditor_ckeditor5_utils__WEBPACK_IMPORTED_MODULE_3__.global.document.body.appendChild(this._previewContainer); - } - else { - this._previewContainer.removeChild(this._previewContainer.firstElementChild); - } - const preview = (0,_ckeditor_ckeditor5_utils__WEBPACK_IMPORTED_MODULE_3__.createElement)(_ckeditor_ckeditor5_utils__WEBPACK_IMPORTED_MODULE_3__.global.document, 'div'); - preview.className = 'ck ck-content'; - preview.style.width = computedStyle.width; - preview.innerHTML = dataTransfer.getData('text/html'); - dataTransfer.setDragImage(preview, 0, 0); - // TODO set x to make dragged widget stick to the mouse cursor - this._previewContainer.appendChild(preview); - } -} -/** - * Returns the drop effect that should be a result of dragging the content. - * This function is handling a quirk when checking the effect in the 'drop' DOM event. - */ -function getFinalDropEffect(dataTransfer) { - if (_ckeditor_ckeditor5_utils__WEBPACK_IMPORTED_MODULE_3__.env.isGecko) { - return dataTransfer.dropEffect; - } - return ['all', 'copyMove'].includes(dataTransfer.effectAllowed) ? 'move' : 'copy'; -} -/** - * Returns a widget element that should be dragged. - */ -function findDraggableWidget(target) { - // This is directly an editable so not a widget for sure. - if (target.is('editableElement')) { - return null; - } - // TODO: Let's have a isWidgetSelectionHandleDomElement() helper in ckeditor5-widget utils. - if (target.hasClass('ck-widget__selection-handle')) { - return target.findAncestor(_ckeditor_ckeditor5_widget__WEBPACK_IMPORTED_MODULE_2__.isWidget); - } - // Direct hit on a widget. - if ((0,_ckeditor_ckeditor5_widget__WEBPACK_IMPORTED_MODULE_2__.isWidget)(target)) { - return target; - } - // Find closest ancestor that is either a widget or an editable element... - const ancestor = target.findAncestor(node => (0,_ckeditor_ckeditor5_widget__WEBPACK_IMPORTED_MODULE_2__.isWidget)(node) || node.is('editableElement')); - // ...and if closer was the widget then enable dragging it. - if ((0,_ckeditor_ckeditor5_widget__WEBPACK_IMPORTED_MODULE_2__.isWidget)(ancestor)) { - return ancestor; - } - return null; -} - - -/***/ }), - -/***/ "./node_modules/@ckeditor/ckeditor5-clipboard/src/dragdroptarget.js": -/*!**************************************************************************!*\ - !*** ./node_modules/@ckeditor/ckeditor5-clipboard/src/dragdroptarget.js ***! - \**************************************************************************/ -/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { - -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export */ __webpack_require__.d(__webpack_exports__, { -/* harmony export */ "default": () => (/* binding */ DragDropTarget) -/* harmony export */ }); -/* harmony import */ var _ckeditor_ckeditor5_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @ckeditor/ckeditor5-core */ "./node_modules/@ckeditor/ckeditor5-core/src/index.js"); -/* harmony import */ var _ckeditor_ckeditor5_utils__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @ckeditor/ckeditor5-utils */ "./node_modules/@ckeditor/ckeditor5-utils/src/index.js"); -/* harmony import */ var _lineview__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./lineview */ "./node_modules/@ckeditor/ckeditor5-clipboard/src/lineview.js"); -/* harmony import */ var lodash_es__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! lodash-es */ "./node_modules/lodash-es/throttle.js"); -/** - * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved. - * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license - */ -/** - * @module clipboard/dragdroptarget - */ -/* istanbul ignore file -- @preserve */ - - - - -/** - * Part of the Drag and Drop handling. Responsible for finding and displaying the drop target. - * - * @internal - */ -class DragDropTarget extends _ckeditor_ckeditor5_core__WEBPACK_IMPORTED_MODULE_0__.Plugin { - constructor() { - super(...arguments); - /** - * A delayed callback removing the drop marker. - * - * @internal - */ - this.removeDropMarkerDelayed = (0,_ckeditor_ckeditor5_utils__WEBPACK_IMPORTED_MODULE_1__.delay)(() => this.removeDropMarker(), 40); - /** - * A throttled callback updating the drop marker. - */ - this._updateDropMarkerThrottled = (0,lodash_es__WEBPACK_IMPORTED_MODULE_3__["default"])(targetRange => this._updateDropMarker(targetRange), 40); - /** - * A throttled callback reconverting the drop parker. - */ - this._reconvertMarkerThrottled = (0,lodash_es__WEBPACK_IMPORTED_MODULE_3__["default"])(() => { - if (this.editor.model.markers.has('drop-target')) { - this.editor.editing.reconvertMarker('drop-target'); - } - }, 0); - /** - * The horizontal drop target line view. - */ - this._dropTargetLineView = new _lineview__WEBPACK_IMPORTED_MODULE_2__["default"](); - /** - * DOM Emitter. - */ - this._domEmitter = new ((0,_ckeditor_ckeditor5_utils__WEBPACK_IMPORTED_MODULE_1__.DomEmitterMixin)())(); - /** - * Map of document scrollable elements. - */ - this._scrollables = new Map(); - } - /** - * @inheritDoc - */ - static get pluginName() { - return 'DragDropTarget'; - } - /** - * @inheritDoc - */ - init() { - this._setupDropMarker(); - } - /** - * @inheritDoc - */ - destroy() { - this._domEmitter.stopListening(); - for (const { resizeObserver } of this._scrollables.values()) { - resizeObserver.destroy(); - } - this._updateDropMarkerThrottled.cancel(); - this.removeDropMarkerDelayed.cancel(); - this._reconvertMarkerThrottled.cancel(); - return super.destroy(); - } - /** - * Finds the drop target range and updates the drop marker. - * - * @internal - */ - updateDropMarker(targetViewElement, targetViewRanges, clientX, clientY, blockMode) { - this.removeDropMarkerDelayed.cancel(); - const targetRange = findDropTargetRange(this.editor, targetViewElement, targetViewRanges, clientX, clientY, blockMode); - /* istanbul ignore else -- @preserve */ - if (targetRange) { - this._updateDropMarkerThrottled(targetRange); - } - } - /** - * Finds the final drop target range. - * - * @internal - */ - getFinalDropRange(targetViewElement, targetViewRanges, clientX, clientY, blockMode) { - const targetRange = findDropTargetRange(this.editor, targetViewElement, targetViewRanges, clientX, clientY, blockMode); - // The dragging markers must be removed after searching for the target range because sometimes - // the target lands on the marker itself. - this.removeDropMarker(); - return targetRange; - } - /** - * Removes the drop target marker. - * - * @internal - */ - removeDropMarker() { - const model = this.editor.model; - this.removeDropMarkerDelayed.cancel(); - this._updateDropMarkerThrottled.cancel(); - this._dropTargetLineView.isVisible = false; - if (model.markers.has('drop-target')) { - model.change(writer => { - writer.removeMarker('drop-target'); - }); - } - } - /** - * Creates downcast conversion for the drop target marker. - */ - _setupDropMarker() { - const editor = this.editor; - editor.ui.view.body.add(this._dropTargetLineView); - // Drop marker conversion for hovering over widgets. - editor.conversion.for('editingDowncast').markerToHighlight({ - model: 'drop-target', - view: { - classes: ['ck-clipboard-drop-target-range'] - } - }); - // Drop marker conversion for in text and block drop target. - editor.conversion.for('editingDowncast').markerToElement({ - model: 'drop-target', - view: (data, { writer }) => { - // Inline drop. - if (editor.model.schema.checkChild(data.markerRange.start, '$text')) { - this._dropTargetLineView.isVisible = false; - return this._createDropTargetPosition(writer); - } - // Block drop. - else { - if (data.markerRange.isCollapsed) { - this._updateDropTargetLine(data.markerRange); - } - else { - this._dropTargetLineView.isVisible = false; - } - } - } - }); - } - /** - * Updates the drop target marker to the provided range. - * - * @param targetRange The range to set the marker to. - */ - _updateDropMarker(targetRange) { - const editor = this.editor; - const markers = editor.model.markers; - editor.model.change(writer => { - if (markers.has('drop-target')) { - if (!markers.get('drop-target').getRange().isEqual(targetRange)) { - writer.updateMarker('drop-target', { range: targetRange }); - } - } - else { - writer.addMarker('drop-target', { - range: targetRange, - usingOperation: false, - affectsData: false - }); - } - }); - } - /** - * Creates the UI element for vertical (in-line) drop target. - */ - _createDropTargetPosition(writer) { - return writer.createUIElement('span', { class: 'ck ck-clipboard-drop-target-position' }, function (domDocument) { - const domElement = this.toDomElement(domDocument); - // Using word joiner to make this marker as high as text and also making text not break on marker. - domElement.append('\u2060', domDocument.createElement('span'), '\u2060'); - return domElement; - }); - } - /** - * Updates the horizontal drop target line. - */ - _updateDropTargetLine(range) { - const editing = this.editor.editing; - const nodeBefore = range.start.nodeBefore; - const nodeAfter = range.start.nodeAfter; - const nodeParent = range.start.parent; - const viewElementBefore = nodeBefore ? editing.mapper.toViewElement(nodeBefore) : null; - const domElementBefore = viewElementBefore ? editing.view.domConverter.mapViewToDom(viewElementBefore) : null; - const viewElementAfter = nodeAfter ? editing.mapper.toViewElement(nodeAfter) : null; - const domElementAfter = viewElementAfter ? editing.view.domConverter.mapViewToDom(viewElementAfter) : null; - const viewElementParent = editing.mapper.toViewElement(nodeParent); - const domElementParent = editing.view.domConverter.mapViewToDom(viewElementParent); - const domScrollableRect = this._getScrollableRect(viewElementParent); - const { scrollX, scrollY } = _ckeditor_ckeditor5_utils__WEBPACK_IMPORTED_MODULE_1__.global.window; - const rectBefore = domElementBefore ? new _ckeditor_ckeditor5_utils__WEBPACK_IMPORTED_MODULE_1__.Rect(domElementBefore) : null; - const rectAfter = domElementAfter ? new _ckeditor_ckeditor5_utils__WEBPACK_IMPORTED_MODULE_1__.Rect(domElementAfter) : null; - const rectParent = new _ckeditor_ckeditor5_utils__WEBPACK_IMPORTED_MODULE_1__.Rect(domElementParent).excludeScrollbarsAndBorders(); - const above = rectBefore ? rectBefore.bottom : rectParent.top; - const below = rectAfter ? rectAfter.top : rectParent.bottom; - const parentStyle = _ckeditor_ckeditor5_utils__WEBPACK_IMPORTED_MODULE_1__.global.window.getComputedStyle(domElementParent); - const top = (above <= below ? (above + below) / 2 : below); - if (domScrollableRect.top < top && top < domScrollableRect.bottom) { - const left = rectParent.left + parseFloat(parentStyle.paddingLeft); - const right = rectParent.right - parseFloat(parentStyle.paddingRight); - const leftClamped = Math.max(left + scrollX, domScrollableRect.left); - const rightClamped = Math.min(right + scrollX, domScrollableRect.right); - this._dropTargetLineView.set({ - isVisible: true, - left: leftClamped, - top: top + scrollY, - width: rightClamped - leftClamped - }); - } - else { - this._dropTargetLineView.isVisible = false; - } - } - /** - * Finds the closest scrollable element rect for the given view element. - */ - _getScrollableRect(viewElement) { - const rootName = viewElement.root.rootName; - let domScrollable; - if (this._scrollables.has(rootName)) { - domScrollable = this._scrollables.get(rootName).domElement; - } - else { - const domElement = this.editor.editing.view.domConverter.mapViewToDom(viewElement); - domScrollable = findScrollableElement(domElement); - this._domEmitter.listenTo(domScrollable, 'scroll', this._reconvertMarkerThrottled, { usePassive: true }); - const resizeObserver = new _ckeditor_ckeditor5_utils__WEBPACK_IMPORTED_MODULE_1__.ResizeObserver(domScrollable, this._reconvertMarkerThrottled); - this._scrollables.set(rootName, { - domElement: domScrollable, - resizeObserver - }); - } - return new _ckeditor_ckeditor5_utils__WEBPACK_IMPORTED_MODULE_1__.Rect(domScrollable).excludeScrollbarsAndBorders(); - } -} -/** - * Returns fixed selection range for given position and target element. - */ -function findDropTargetRange(editor, targetViewElement, targetViewRanges, clientX, clientY, blockMode) { - const model = editor.model; - const mapper = editor.editing.mapper; - const targetModelElement = getClosestMappedModelElement(editor, targetViewElement); - let modelElement = targetModelElement; - while (modelElement) { - if (!blockMode) { - if (model.schema.checkChild(modelElement, '$text')) { - const targetViewPosition = targetViewRanges ? targetViewRanges[0].start : null; - const targetModelPosition = targetViewPosition ? mapper.toModelPosition(targetViewPosition) : null; - if (targetModelPosition) { - if (model.schema.checkChild(targetModelPosition, '$text')) { - return model.createRange(targetModelPosition); - } - else if (targetViewPosition) { - // This is the case of dropping inside a span wrapper of an inline image. - return findDropTargetRangeForElement(editor, getClosestMappedModelElement(editor, targetViewPosition.parent), clientX, clientY); - } - } - } - else if (model.schema.isInline(modelElement)) { - return findDropTargetRangeForElement(editor, modelElement, clientX, clientY); - } - } - if (model.schema.isBlock(modelElement)) { - return findDropTargetRangeForElement(editor, modelElement, clientX, clientY); - } - else if (model.schema.checkChild(modelElement, '$block')) { - const childNodes = Array.from(modelElement.getChildren()) - .filter((node) => node.is('element') && !isFloatingElement(editor, node)); - let startIndex = 0; - let endIndex = childNodes.length; - while (startIndex < endIndex - 1) { - const middleIndex = Math.floor((startIndex + endIndex) / 2); - const side = findElementSide(editor, childNodes[middleIndex], clientX, clientY); - if (side == 'before') { - endIndex = middleIndex; - } - else { - startIndex = middleIndex; - } - } - return findDropTargetRangeForElement(editor, childNodes[startIndex], clientX, clientY); - } - modelElement = modelElement.parent; - } - console.warn('none:', targetModelElement.name); - return null; -} -/** - * Returns true for elements with floating style set. - */ -function isFloatingElement(editor, modelElement) { - const mapper = editor.editing.mapper; - const domConverter = editor.editing.view.domConverter; - const viewElement = mapper.toViewElement(modelElement); - const domElement = domConverter.mapViewToDom(viewElement); - return _ckeditor_ckeditor5_utils__WEBPACK_IMPORTED_MODULE_1__.global.window.getComputedStyle(domElement).float != 'none'; -} -/** - * Returns target range relative to the given element. - */ -function findDropTargetRangeForElement(editor, modelElement, clientX, clientY) { - const model = editor.model; - return model.createRange(model.createPositionAt(modelElement, findElementSide(editor, modelElement, clientX, clientY))); -} -/** - * Resolves whether drop marker should be before or after the given element. - */ -function findElementSide(editor, modelElement, clientX, clientY) { - const mapper = editor.editing.mapper; - const domConverter = editor.editing.view.domConverter; - const viewElement = mapper.toViewElement(modelElement); - const domElement = domConverter.mapViewToDom(viewElement); - const rect = new _ckeditor_ckeditor5_utils__WEBPACK_IMPORTED_MODULE_1__.Rect(domElement); - if (editor.model.schema.isInline(modelElement)) { - return clientX < (rect.left + rect.right) / 2 ? 'before' : 'after'; - } - else { - return clientY < (rect.top + rect.bottom) / 2 ? 'before' : 'after'; - } -} -/** - * Returns the closest model element for the specified view element. - */ -function getClosestMappedModelElement(editor, element) { - const mapper = editor.editing.mapper; - const view = editor.editing.view; - const targetModelElement = mapper.toModelElement(element); - if (targetModelElement) { - return targetModelElement; - } - // Find mapped ancestor if the target is inside not mapped element (for example inline code element). - const viewPosition = view.createPositionBefore(element); - const viewElement = mapper.findMappedViewAncestor(viewPosition); - return mapper.toModelElement(viewElement); -} -/** - * Returns the closest scrollable ancestor DOM element. - * - * It is assumed that `domNode` is attached to the document. - */ -function findScrollableElement(domNode) { - let domElement = domNode; - do { - domElement = domElement.parentElement; - const overflow = _ckeditor_ckeditor5_utils__WEBPACK_IMPORTED_MODULE_1__.global.window.getComputedStyle(domElement).overflowY; - if (overflow == 'auto' || overflow == 'scroll') { - break; - } - } while (domElement.tagName != 'BODY'); - return domElement; -} - - -/***/ }), - -/***/ "./node_modules/@ckeditor/ckeditor5-clipboard/src/index.js": -/*!*****************************************************************!*\ - !*** ./node_modules/@ckeditor/ckeditor5-clipboard/src/index.js ***! - \*****************************************************************/ -/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { - -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export */ __webpack_require__.d(__webpack_exports__, { -/* harmony export */ Clipboard: () => (/* reexport safe */ _clipboard__WEBPACK_IMPORTED_MODULE_0__["default"]), -/* harmony export */ ClipboardPipeline: () => (/* reexport safe */ _clipboardpipeline__WEBPACK_IMPORTED_MODULE_1__["default"]), -/* harmony export */ DragDrop: () => (/* reexport safe */ _dragdrop__WEBPACK_IMPORTED_MODULE_2__["default"]), -/* harmony export */ DragDropBlockToolbar: () => (/* reexport safe */ _dragdropblocktoolbar__WEBPACK_IMPORTED_MODULE_6__["default"]), -/* harmony export */ DragDropExperimental: () => (/* reexport safe */ _dragdropexperimental__WEBPACK_IMPORTED_MODULE_4__["default"]), -/* harmony export */ DragDropTarget: () => (/* reexport safe */ _dragdroptarget__WEBPACK_IMPORTED_MODULE_5__["default"]), -/* harmony export */ PastePlainText: () => (/* reexport safe */ _pasteplaintext__WEBPACK_IMPORTED_MODULE_3__["default"]) -/* harmony export */ }); -/* harmony import */ var _clipboard__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./clipboard */ "./node_modules/@ckeditor/ckeditor5-clipboard/src/clipboard.js"); -/* harmony import */ var _clipboardpipeline__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./clipboardpipeline */ "./node_modules/@ckeditor/ckeditor5-clipboard/src/clipboardpipeline.js"); -/* harmony import */ var _dragdrop__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./dragdrop */ "./node_modules/@ckeditor/ckeditor5-clipboard/src/dragdrop.js"); -/* harmony import */ var _pasteplaintext__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./pasteplaintext */ "./node_modules/@ckeditor/ckeditor5-clipboard/src/pasteplaintext.js"); -/* harmony import */ var _dragdropexperimental__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./dragdropexperimental */ "./node_modules/@ckeditor/ckeditor5-clipboard/src/dragdropexperimental.js"); -/* harmony import */ var _dragdroptarget__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./dragdroptarget */ "./node_modules/@ckeditor/ckeditor5-clipboard/src/dragdroptarget.js"); -/* harmony import */ var _dragdropblocktoolbar__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./dragdropblocktoolbar */ "./node_modules/@ckeditor/ckeditor5-clipboard/src/dragdropblocktoolbar.js"); -/* harmony import */ var _augmentation__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./augmentation */ "./node_modules/@ckeditor/ckeditor5-clipboard/src/augmentation.js"); -/** - * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved. - * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license - */ -/** - * @module clipboard - */ - - - - - - - - - - -/***/ }), - -/***/ "./node_modules/@ckeditor/ckeditor5-clipboard/src/lineview.js": -/*!********************************************************************!*\ - !*** ./node_modules/@ckeditor/ckeditor5-clipboard/src/lineview.js ***! - \********************************************************************/ -/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { - -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export */ __webpack_require__.d(__webpack_exports__, { -/* harmony export */ "default": () => (/* binding */ LineView) -/* harmony export */ }); -/* harmony import */ var _ckeditor_ckeditor5_ui__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @ckeditor/ckeditor5-ui */ "./node_modules/@ckeditor/ckeditor5-ui/src/index.js"); -/* harmony import */ var _ckeditor_ckeditor5_utils__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @ckeditor/ckeditor5-utils */ "./node_modules/@ckeditor/ckeditor5-utils/src/index.js"); -/** - * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved. - * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license - */ -/** - * @module clipboard/lineview - */ -/* istanbul ignore file -- @preserve */ - - -const toPx = (0,_ckeditor_ckeditor5_utils__WEBPACK_IMPORTED_MODULE_1__.toUnit)('px'); -/** - * The horizontal drop target line view. - */ -class LineView extends _ckeditor_ckeditor5_ui__WEBPACK_IMPORTED_MODULE_0__.View { - /** - * @inheritDoc - */ - constructor() { - super(); - const bind = this.bindTemplate; - this.set({ - isVisible: false, - left: null, - top: null, - width: null - }); - this.setTemplate({ - tag: 'div', - attributes: { - class: [ - 'ck', - 'ck-clipboard-drop-target-line', - bind.if('isVisible', 'ck-hidden', value => !value) - ], - style: { - left: bind.to('left', left => toPx(left)), - top: bind.to('top', top => toPx(top)), - width: bind.to('width', width => toPx(width)) - } - } - }); - } -} - - -/***/ }), - -/***/ "./node_modules/@ckeditor/ckeditor5-clipboard/src/pasteplaintext.js": -/*!**************************************************************************!*\ - !*** ./node_modules/@ckeditor/ckeditor5-clipboard/src/pasteplaintext.js ***! - \**************************************************************************/ -/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { - -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export */ __webpack_require__.d(__webpack_exports__, { -/* harmony export */ "default": () => (/* binding */ PastePlainText) -/* harmony export */ }); -/* harmony import */ var _ckeditor_ckeditor5_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @ckeditor/ckeditor5-core */ "./node_modules/@ckeditor/ckeditor5-core/src/index.js"); -/* harmony import */ var _clipboardobserver__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./clipboardobserver */ "./node_modules/@ckeditor/ckeditor5-clipboard/src/clipboardobserver.js"); -/* harmony import */ var _clipboardpipeline__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./clipboardpipeline */ "./node_modules/@ckeditor/ckeditor5-clipboard/src/clipboardpipeline.js"); -/** - * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved. - * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license - */ -/** - * @module clipboard/pasteplaintext - */ - - - -/** - * The plugin detects the user's intention to paste plain text. - * - * For example, it detects the Ctrl/Cmd + Shift + V keystroke. - */ -class PastePlainText extends _ckeditor_ckeditor5_core__WEBPACK_IMPORTED_MODULE_0__.Plugin { - /** - * @inheritDoc - */ - static get pluginName() { - return 'PastePlainText'; - } - /** - * @inheritDoc - */ - static get requires() { - return [_clipboardpipeline__WEBPACK_IMPORTED_MODULE_2__["default"]]; - } - /** - * @inheritDoc - */ - init() { - const editor = this.editor; - const model = editor.model; - const view = editor.editing.view; - const viewDocument = view.document; - const selection = model.document.selection; - let shiftPressed = false; - view.addObserver(_clipboardobserver__WEBPACK_IMPORTED_MODULE_1__["default"]); - this.listenTo(viewDocument, 'keydown', (evt, data) => { - shiftPressed = data.shiftKey; - }); - editor.plugins.get(_clipboardpipeline__WEBPACK_IMPORTED_MODULE_2__["default"]).on('contentInsertion', (evt, data) => { - // Plain text can be determined based on the event flag (#7799) or auto-detection (#1006). If detected, - // preserve selection attributes on pasted items. - if (!shiftPressed && !isPlainTextFragment(data.content, model.schema)) { - return; - } - model.change(writer => { - // Formatting attributes should be preserved. - const textAttributes = Array.from(selection.getAttributes()) - .filter(([key]) => model.schema.getAttributeProperties(key).isFormatting); - if (!selection.isCollapsed) { - model.deleteContent(selection, { doNotAutoparagraph: true }); - } - // Also preserve other attributes if they survived the content deletion (because they were not fully selected). - // For example linkHref is not a formatting attribute but it should be preserved if pasted text was in the middle - // of a link. - textAttributes.push(...selection.getAttributes()); - const range = writer.createRangeIn(data.content); - for (const item of range.getItems()) { - if (item.is('$textProxy')) { - writer.setAttributes(textAttributes, item); - } - } - }); - }); - } -} -/** - * Returns true if specified `documentFragment` represents a plain text. - */ -function isPlainTextFragment(documentFragment, schema) { - if (documentFragment.childCount > 1) { - return false; - } - const child = documentFragment.getChild(0); - if (schema.isObject(child)) { - return false; - } - return Array.from(child.getAttributeKeys()).length == 0; -} - - -/***/ }), - -/***/ "./node_modules/@ckeditor/ckeditor5-clipboard/src/utils/normalizeclipboarddata.js": -/*!****************************************************************************************!*\ - !*** ./node_modules/@ckeditor/ckeditor5-clipboard/src/utils/normalizeclipboarddata.js ***! - \****************************************************************************************/ -/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { - -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export */ __webpack_require__.d(__webpack_exports__, { -/* harmony export */ "default": () => (/* binding */ normalizeClipboardData) -/* harmony export */ }); -/** - * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved. - * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license - */ -/** - * @module clipboard/utils/normalizeclipboarddata - */ -/** - * Removes some popular browser quirks out of the clipboard data (HTML). - * Removes all HTML comments. These are considered an internal thing and it makes little sense if they leak into the editor data. - * - * @param data The HTML data to normalize. - * @returns Normalized HTML. - */ -function normalizeClipboardData(data) { - return data - .replace(/(\s+)<\/span>/g, (fullMatch, spaces) => { - // Handle the most popular and problematic case when even a single space becomes an nbsp;. - // Decode those to normal spaces. Read more in https://github.com/ckeditor/ckeditor5-clipboard/issues/2. - if (spaces.length == 1) { - return ' '; - } - return spaces; - }) - // Remove all HTML comments. - .replace(//g, ''); -} - - -/***/ }), - -/***/ "./node_modules/@ckeditor/ckeditor5-clipboard/src/utils/plaintexttohtml.js": -/*!*********************************************************************************!*\ - !*** ./node_modules/@ckeditor/ckeditor5-clipboard/src/utils/plaintexttohtml.js ***! - \*********************************************************************************/ -/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { - -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export */ __webpack_require__.d(__webpack_exports__, { -/* harmony export */ "default": () => (/* binding */ plainTextToHtml) -/* harmony export */ }); -/** - * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved. - * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license - */ -/** - * @module clipboard/utils/plaintexttohtml - */ -/** - * Converts plain text to its HTML-ized version. - * - * @param text The plain text to convert. - * @returns HTML generated from the plain text. - */ -function plainTextToHtml(text) { - text = text - // Encode <>. - .replace(//g, '>') - // Creates a paragraph for each double line break. - .replace(/\r?\n\r?\n/g, '') - // Creates a line break for each single line break. - .replace(/\r?\n/g, '
') - // Replace tabs with four spaces. - .replace(/\t/g, ' ') - // Preserve trailing spaces (only the first and last one – the rest is handled below). - .replace(/^\s/, ' ') - .replace(/\s$/, ' ') - // Preserve other subsequent spaces now. - .replace(/\s\s/g, ' '); - if (text.includes('') || text.includes('
')) { - // If we created paragraphs above, add the trailing ones. - text = `${text}
`; - } - // TODO: - // * What about '\nfoo' vs ' foo'? - return text; -} - - -/***/ }), - -/***/ "./node_modules/@ckeditor/ckeditor5-clipboard/src/utils/viewtoplaintext.js": -/*!*********************************************************************************!*\ - !*** ./node_modules/@ckeditor/ckeditor5-clipboard/src/utils/viewtoplaintext.js ***! - \*********************************************************************************/ -/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { - -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export */ __webpack_require__.d(__webpack_exports__, { -/* harmony export */ "default": () => (/* binding */ viewToPlainText) -/* harmony export */ }); -/** - * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved. - * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license - */ -// Elements which should not have empty-line padding. -// Most `view.ContainerElement` want to be separate by new-line, but some are creating one structure -// together (like ``) so it is better to separate them by only one "\n". -const smallPaddingElements = ['figcaption', 'li']; -/** - * Converts {@link module:engine/view/item~Item view item} and all of its children to plain text. - * - * @param viewItem View item to convert. - * @returns Plain text representation of `viewItem`. - */ -function viewToPlainText(viewItem) { - let text = ''; - if (viewItem.is('$text') || viewItem.is('$textProxy')) { - // If item is `Text` or `TextProxy` simple take its text data. - text = viewItem.data; - } - else if (viewItem.is('element', 'img') && viewItem.hasAttribute('alt')) { - // Special case for images - use alt attribute if it is provided. - text = viewItem.getAttribute('alt'); - } - else if (viewItem.is('element', 'br')) { - // A soft break should be converted into a single line break (#8045). - text = '\n'; - } - else { - // Other elements are document fragments, attribute elements or container elements. - // They don't have their own text value, so convert their children. - let prev = null; - for (const child of viewItem.getChildren()) { - const childText = viewToPlainText(child); - // Separate container element children with one or more new-line characters. - if (prev && (prev.is('containerElement') || child.is('containerElement'))) { - if (smallPaddingElements.includes(prev.name) || - smallPaddingElements.includes(child.name)) { - text += '\n'; - } - else { - text += '\n\n'; - } - } - text += childText; - prev = child; - } - } - return text; -} - - -/***/ }), - -/***/ "./node_modules/@ckeditor/ckeditor5-core/src/augmentation.js": -/*!*******************************************************************!*\ - !*** ./node_modules/@ckeditor/ckeditor5-core/src/augmentation.js ***! - \*******************************************************************/ -/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { - -"use strict"; -__webpack_require__.r(__webpack_exports__); -/** - * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved. - * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license - */ - - - -/***/ }), - -/***/ "./node_modules/@ckeditor/ckeditor5-core/src/command.js": -/*!**************************************************************!*\ - !*** ./node_modules/@ckeditor/ckeditor5-core/src/command.js ***! - \**************************************************************/ -/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { - -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export */ __webpack_require__.d(__webpack_exports__, { -/* harmony export */ "default": () => (/* binding */ Command) -/* harmony export */ }); -/* harmony import */ var _ckeditor_ckeditor5_utils__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @ckeditor/ckeditor5-utils */ "./node_modules/@ckeditor/ckeditor5-utils/src/index.js"); -/** - * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved. - * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license - */ -/** - * @module core/command - */ - -/** - * Base class for the CKEditor commands. - * - * Commands are the main way to manipulate the editor contents and state. They are mostly used by UI elements (or by other - * commands) to make changes in the model. Commands are available in every part of the code that has access to - * the {@link module:core/editor/editor~Editor editor} instance. - * - * Instances of registered commands can be retrieved from {@link module:core/editor/editor~Editor#commands `editor.commands`}. - * The easiest way to execute a command is through {@link module:core/editor/editor~Editor#execute `editor.execute()`}. - * - * By default, commands are disabled when the editor is in the {@link module:core/editor/editor~Editor#isReadOnly read-only} mode - * but commands with the {@link module:core/command~Command#affectsData `affectsData`} flag set to `false` will not be disabled. - */ -class Command extends (0,_ckeditor_ckeditor5_utils__WEBPACK_IMPORTED_MODULE_0__.ObservableMixin)() { - /** - * Creates a new `Command` instance. - * - * @param editor The editor on which this command will be used. - */ - constructor(editor) { - super(); - this.editor = editor; - this.set('value', undefined); - this.set('isEnabled', false); - this._affectsData = true; - this._isEnabledBasedOnSelection = true; - this._disableStack = new Set(); - this.decorate('execute'); - // By default, every command is refreshed when changes are applied to the model. - this.listenTo(this.editor.model.document, 'change', () => { - this.refresh(); - }); - this.listenTo(editor, 'change:isReadOnly', () => { - this.refresh(); - }); - // By default, commands are disabled if the selection is in non-editable place or editor is in read-only mode. - this.on('set:isEnabled', evt => { - if (!this.affectsData) { - return; - } - // Checking `editor.isReadOnly` is needed for all commands that have `_isEnabledBasedOnSelection == false`. - // E.g. undo does not base on selection, but affects data and should be disabled when the editor is in read-only mode. - if (editor.isReadOnly || this._isEnabledBasedOnSelection && !editor.model.canEditAt(editor.model.document.selection)) { - evt.return = false; - evt.stop(); - } - }, { priority: 'highest' }); - this.on('execute', evt => { - if (!this.isEnabled) { - evt.stop(); - } - }, { priority: 'high' }); - } - /** - * A flag indicating whether a command execution changes the editor data or not. - * - * Commands with `affectsData` set to `false` will not be automatically disabled in - * the {@link module:core/editor/editor~Editor#isReadOnly read-only mode} and - * {@glink features/read-only#related-features other editor modes} with restricted user write permissions. - * - * **Note:** You do not have to set it for your every command. It is `true` by default. - * - * @default true - */ - get affectsData() { - return this._affectsData; - } - set affectsData(affectsData) { - this._affectsData = affectsData; - } - /** - * Refreshes the command. The command should update its {@link #isEnabled} and {@link #value} properties - * in this method. - * - * This method is automatically called when - * {@link module:engine/model/document~Document#event:change any changes are applied to the document}. - */ - refresh() { - this.isEnabled = true; - } - /** - * Disables the command. - * - * Command may be disabled by multiple features or algorithms (at once). When disabling a command, unique id should be passed - * (e.g. the feature name). The same identifier should be used when {@link #clearForceDisabled enabling back} the command. - * The command becomes enabled only after all features {@link #clearForceDisabled enabled it back}. - * - * Disabling and enabling a command: - * - * ```ts - * command.isEnabled; // -> true - * command.forceDisabled( 'MyFeature' ); - * command.isEnabled; // -> false - * command.clearForceDisabled( 'MyFeature' ); - * command.isEnabled; // -> true - * ``` - * - * Command disabled by multiple features: - * - * ```ts - * command.forceDisabled( 'MyFeature' ); - * command.forceDisabled( 'OtherFeature' ); - * command.clearForceDisabled( 'MyFeature' ); - * command.isEnabled; // -> false - * command.clearForceDisabled( 'OtherFeature' ); - * command.isEnabled; // -> true - * ``` - * - * Multiple disabling with the same identifier is redundant: - * - * ```ts - * command.forceDisabled( 'MyFeature' ); - * command.forceDisabled( 'MyFeature' ); - * command.clearForceDisabled( 'MyFeature' ); - * command.isEnabled; // -> true - * ``` - * - * **Note:** some commands or algorithms may have more complex logic when it comes to enabling or disabling certain commands, - * so the command might be still disabled after {@link #clearForceDisabled} was used. - * - * @param id Unique identifier for disabling. Use the same id when {@link #clearForceDisabled enabling back} the command. - */ - forceDisabled(id) { - this._disableStack.add(id); - if (this._disableStack.size == 1) { - this.on('set:isEnabled', forceDisable, { priority: 'highest' }); - this.isEnabled = false; - } - } - /** - * Clears forced disable previously set through {@link #forceDisabled}. See {@link #forceDisabled}. - * - * @param id Unique identifier, equal to the one passed in {@link #forceDisabled} call. - */ - clearForceDisabled(id) { - this._disableStack.delete(id); - if (this._disableStack.size == 0) { - this.off('set:isEnabled', forceDisable); - this.refresh(); - } - } - /** - * Executes the command. - * - * A command may accept parameters. They will be passed from {@link module:core/editor/editor~Editor#execute `editor.execute()`} - * to the command. - * - * The `execute()` method will automatically abort when the command is disabled ({@link #isEnabled} is `false`). - * This behavior is implemented by a high priority listener to the {@link #event:execute} event. - * - * In order to see how to disable a command from "outside" see the {@link #isEnabled} documentation. - * - * This method may return a value, which would be forwarded all the way down to the - * {@link module:core/editor/editor~Editor#execute `editor.execute()`}. - * - * @fires execute - */ - execute(...args) { return undefined; } - /** - * Destroys the command. - */ - destroy() { - this.stopListening(); - } -} -/** - * Helper function that forces command to be disabled. - */ -function forceDisable(evt) { - evt.return = false; - evt.stop(); -} - - -/***/ }), - -/***/ "./node_modules/@ckeditor/ckeditor5-core/src/commandcollection.js": -/*!************************************************************************!*\ - !*** ./node_modules/@ckeditor/ckeditor5-core/src/commandcollection.js ***! - \************************************************************************/ -/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { - -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export */ __webpack_require__.d(__webpack_exports__, { -/* harmony export */ "default": () => (/* binding */ CommandCollection) -/* harmony export */ }); -/* harmony import */ var _ckeditor_ckeditor5_utils__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @ckeditor/ckeditor5-utils */ "./node_modules/@ckeditor/ckeditor5-utils/src/index.js"); -/** - * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved. - * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license - */ -/** - * @module core/commandcollection - */ - -/** - * Collection of commands. Its instance is available in {@link module:core/editor/editor~Editor#commands `editor.commands`}. - */ -class CommandCollection { - /** - * Creates collection instance. - */ - constructor() { - this._commands = new Map(); - } - /** - * Registers a new command. - * - * @param commandName The name of the command. - */ - add(commandName, command) { - this._commands.set(commandName, command); - } - /** - * Retrieves a command from the collection. - * - * @param commandName The name of the command. - */ - get(commandName) { - return this._commands.get(commandName); - } - /** - * Executes a command. - * - * @param commandName The name of the command. - * @param commandParams Command parameters. - * @returns The value returned by the {@link module:core/command~Command#execute `command.execute()`}. - */ - execute(commandName, ...commandParams) { - const command = this.get(commandName); - if (!command) { - /** - * Command does not exist. - * - * @error commandcollection-command-not-found - * @param commandName Name of the command. - */ - throw new _ckeditor_ckeditor5_utils__WEBPACK_IMPORTED_MODULE_0__.CKEditorError('commandcollection-command-not-found', this, { commandName }); - } - return command.execute(...commandParams); - } - /** - * Returns iterator of command names. - */ - *names() { - yield* this._commands.keys(); - } - /** - * Returns iterator of command instances. - */ - *commands() { - yield* this._commands.values(); - } - /** - * Iterable interface. - * - * Returns `[ commandName, commandInstance ]` pairs. - */ - [Symbol.iterator]() { - return this._commands[Symbol.iterator](); - } - /** - * Destroys all collection commands. - */ - destroy() { - for (const command of this.commands()) { - command.destroy(); - } - } -} - - -/***/ }), - -/***/ "./node_modules/@ckeditor/ckeditor5-core/src/context.js": -/*!**************************************************************!*\ - !*** ./node_modules/@ckeditor/ckeditor5-core/src/context.js ***! - \**************************************************************/ -/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { - -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export */ __webpack_require__.d(__webpack_exports__, { -/* harmony export */ "default": () => (/* binding */ Context) -/* harmony export */ }); -/* harmony import */ var _ckeditor_ckeditor5_utils__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @ckeditor/ckeditor5-utils */ "./node_modules/@ckeditor/ckeditor5-utils/src/index.js"); -/* harmony import */ var _plugincollection__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./plugincollection */ "./node_modules/@ckeditor/ckeditor5-core/src/plugincollection.js"); -/** - * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved. - * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license - */ -/** - * @module core/context - */ - - -/** - * Provides a common, higher-level environment for solutions that use multiple {@link module:core/editor/editor~Editor editors} - * or plugins that work outside the editor. Use it instead of {@link module:core/editor/editor~Editor.create `Editor.create()`} - * in advanced application integrations. - * - * All configuration options passed to a context will be used as default options for the editor instances initialized in that context. - * - * {@link module:core/contextplugin~ContextPlugin Context plugins} passed to a context instance will be shared among all - * editor instances initialized in this context. These will be the same plugin instances for all the editors. - * - * **Note:** The context can only be initialized with {@link module:core/contextplugin~ContextPlugin context plugins} - * (e.g. [comments](https://ckeditor.com/collaboration/comments/)). Regular {@link module:core/plugin~Plugin plugins} require an - * editor instance to work and cannot be added to a context. - * - * **Note:** You can add a context plugin to an editor instance, though. - * - * If you are using multiple editor instances on one page and use any context plugins, create a context to share the configuration and - * plugins among these editors. Some plugins will use the information about all existing editors to better integrate between them. - * - * If you are using plugins that do not require an editor to work (e.g. [comments](https://ckeditor.com/collaboration/comments/)), - * enable and configure them using the context. - * - * If you are using only a single editor on each page, use {@link module:core/editor/editor~Editor.create `Editor.create()`} instead. - * In such a case, a context instance will be created by the editor instance in a transparent way. - * - * See {@link ~Context.create `Context.create()`} for usage examples. - */ -class Context { - /** - * Creates a context instance with a given configuration. - * - * Usually not to be used directly. See the static {@link module:core/context~Context.create `create()`} method. - * - * @param config The context configuration. - */ - constructor(config) { - /** - * Reference to the editor which created the context. - * Null when the context was created outside of the editor. - * - * It is used to destroy the context when removing the editor that has created the context. - */ - this._contextOwner = null; - this.config = new _ckeditor_ckeditor5_utils__WEBPACK_IMPORTED_MODULE_0__.Config(config, this.constructor.defaultConfig); - const availablePlugins = this.constructor.builtinPlugins; - this.config.define('plugins', availablePlugins); - this.plugins = new _plugincollection__WEBPACK_IMPORTED_MODULE_1__["default"](this, availablePlugins); - const languageConfig = this.config.get('language') || {}; - this.locale = new _ckeditor_ckeditor5_utils__WEBPACK_IMPORTED_MODULE_0__.Locale({ - uiLanguage: typeof languageConfig === 'string' ? languageConfig : languageConfig.ui, - contentLanguage: this.config.get('language.content') - }); - this.t = this.locale.t; - this.editors = new _ckeditor_ckeditor5_utils__WEBPACK_IMPORTED_MODULE_0__.Collection(); - } - /** - * Loads and initializes plugins specified in the configuration. - * - * @returns A promise which resolves once the initialization is completed, providing an array of loaded plugins. - */ - initPlugins() { - const plugins = this.config.get('plugins') || []; - const substitutePlugins = this.config.get('substitutePlugins') || []; - // Plugins for substitution should be checked as well. - for (const Plugin of plugins.concat(substitutePlugins)) { - if (typeof Plugin != 'function') { - /** - * Only a constructor function is allowed as a {@link module:core/contextplugin~ContextPlugin context plugin}. - * - * @error context-initplugins-constructor-only - */ - throw new _ckeditor_ckeditor5_utils__WEBPACK_IMPORTED_MODULE_0__.CKEditorError('context-initplugins-constructor-only', null, { Plugin }); - } - if (Plugin.isContextPlugin !== true) { - /** - * Only a plugin marked as a {@link module:core/contextplugin~ContextPlugin.isContextPlugin context plugin} - * is allowed to be used with a context. - * - * @error context-initplugins-invalid-plugin - */ - throw new _ckeditor_ckeditor5_utils__WEBPACK_IMPORTED_MODULE_0__.CKEditorError('context-initplugins-invalid-plugin', null, { Plugin }); - } - } - return this.plugins.init(plugins, [], substitutePlugins); - } - /** - * Destroys the context instance and all editors used with the context, - * releasing all resources used by the context. - * - * @returns A promise that resolves once the context instance is fully destroyed. - */ - destroy() { - return Promise.all(Array.from(this.editors, editor => editor.destroy())) - .then(() => this.plugins.destroy()); - } - /** - * Adds a reference to the editor which is used with this context. - * - * When the given editor has created the context, the reference to this editor will be stored - * as a {@link ~Context#_contextOwner}. - * - * This method should only be used by the editor. - * - * @internal - * @param isContextOwner Stores the given editor as a context owner. - */ - _addEditor(editor, isContextOwner) { - if (this._contextOwner) { - /** - * Cannot add multiple editors to the context which is created by the editor. - * - * @error context-addeditor-private-context - */ - throw new _ckeditor_ckeditor5_utils__WEBPACK_IMPORTED_MODULE_0__.CKEditorError('context-addeditor-private-context'); - } - this.editors.add(editor); - if (isContextOwner) { - this._contextOwner = editor; - } - } - /** - * Removes a reference to the editor which was used with this context. - * When the context was created by the given editor, the context will be destroyed. - * - * This method should only be used by the editor. - * - * @internal - * @return A promise that resolves once the editor is removed from the context or when the context was destroyed. - */ - _removeEditor(editor) { - if (this.editors.has(editor)) { - this.editors.remove(editor); - } - if (this._contextOwner === editor) { - return this.destroy(); - } - return Promise.resolve(); - } - /** - * Returns the context configuration which will be copied to the editors created using this context. - * - * The configuration returned by this method has the plugins configuration removed — plugins are shared with all editors - * through another mechanism. - * - * This method should only be used by the editor. - * - * @internal - * @returns Configuration as a plain object. - */ - _getEditorConfig() { - const result = {}; - for (const name of this.config.names()) { - if (!['plugins', 'removePlugins', 'extraPlugins'].includes(name)) { - result[name] = this.config.get(name); - } - } - return result; - } - /** - * Creates and initializes a new context instance. - * - * ```ts - * const commonConfig = { ... }; // Configuration for all the plugins and editors. - * const editorPlugins = [ ... ]; // Regular plugins here. - * - * Context - * .create( { - * // Only context plugins here. - * plugins: [ ... ], - * - * // Configure the language for all the editors (it cannot be overwritten). - * language: { ... }, - * - * // Configuration for context plugins. - * comments: { ... }, - * ... - * - * // Default configuration for editor plugins. - * toolbar: { ... }, - * image: { ... }, - * ... - * } ) - * .then( context => { - * const promises = []; - * - * promises.push( ClassicEditor.create( - * document.getElementById( 'editor1' ), - * { - * editorPlugins, - * context - * } - * ) ); - * - * promises.push( ClassicEditor.create( - * document.getElementById( 'editor2' ), - * { - * editorPlugins, - * context, - * toolbar: { ... } // You can overwrite the configuration of the context. - * } - * ) ); - * - * return Promise.all( promises ); - * } ); - * ``` - * - * @param config The context configuration. - * @returns A promise resolved once the context is ready. The promise resolves with the created context instance. - */ - static create(config) { - return new Promise(resolve => { - const context = new this(config); - resolve(context.initPlugins().then(() => context)); - }); - } -} - - -/***/ }), - -/***/ "./node_modules/@ckeditor/ckeditor5-core/src/contextplugin.js": -/*!********************************************************************!*\ - !*** ./node_modules/@ckeditor/ckeditor5-core/src/contextplugin.js ***! - \********************************************************************/ -/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { - -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export */ __webpack_require__.d(__webpack_exports__, { -/* harmony export */ "default": () => (/* binding */ ContextPlugin) -/* harmony export */ }); -/* harmony import */ var _ckeditor_ckeditor5_utils__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @ckeditor/ckeditor5-utils */ "./node_modules/@ckeditor/ckeditor5-utils/src/index.js"); -/** - * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved. - * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license - */ -/** - * @module core/contextplugin - */ - -/** - * The base class for {@link module:core/context~Context} plugin classes. - * - * A context plugin can either be initialized for an {@link module:core/editor/editor~Editor editor} or for - * a {@link module:core/context~Context context}. In other words, it can either - * work within one editor instance or with one or more editor instances that use a single context. - * It is the context plugin's role to implement handling for both modes. - * - * There are a few rules for interaction between the editor plugins and context plugins: - * - * * A context plugin can require another context plugin. - * * An {@link module:core/plugin~Plugin editor plugin} can require a context plugin. - * * A context plugin MUST NOT require an {@link module:core/plugin~Plugin editor plugin}. - */ -class ContextPlugin extends (0,_ckeditor_ckeditor5_utils__WEBPACK_IMPORTED_MODULE_0__.ObservableMixin)() { - /** - * Creates a new plugin instance. - */ - constructor(context) { - super(); - this.context = context; - } - /** - * @inheritDoc - */ - destroy() { - this.stopListening(); - } - /** - * @inheritDoc - */ - static get isContextPlugin() { - return true; - } -} - - -/***/ }), - -/***/ "./node_modules/@ckeditor/ckeditor5-core/src/editingkeystrokehandler.js": -/*!******************************************************************************!*\ - !*** ./node_modules/@ckeditor/ckeditor5-core/src/editingkeystrokehandler.js ***! - \******************************************************************************/ -/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { - -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export */ __webpack_require__.d(__webpack_exports__, { -/* harmony export */ "default": () => (/* binding */ EditingKeystrokeHandler) -/* harmony export */ }); -/* harmony import */ var _ckeditor_ckeditor5_utils__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @ckeditor/ckeditor5-utils */ "./node_modules/@ckeditor/ckeditor5-utils/src/index.js"); -/** - * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved. - * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license - */ -/** - * @module core/editingkeystrokehandler - */ - -/** - * A keystroke handler for editor editing. Its instance is available - * in {@link module:core/editor/editor~Editor#keystrokes} so plugins - * can register their keystrokes. - * - * E.g. an undo plugin would do this: - * - * ```ts - * editor.keystrokes.set( 'Ctrl+Z', 'undo' ); - * editor.keystrokes.set( 'Ctrl+Shift+Z', 'redo' ); - * editor.keystrokes.set( 'Ctrl+Y', 'redo' ); - * ``` - */ -class EditingKeystrokeHandler extends _ckeditor_ckeditor5_utils__WEBPACK_IMPORTED_MODULE_0__.KeystrokeHandler { - /** - * Creates an instance of the keystroke handler. - */ - constructor(editor) { - super(); - this.editor = editor; - } - /** - * Registers a handler for the specified keystroke. - * - * The handler can be specified as a command name or a callback. - * - * @param keystroke Keystroke defined in a format accepted by - * the {@link module:utils/keyboard~parseKeystroke} function. - * @param callback If a string is passed, then the keystroke will - * {@link module:core/editor/editor~Editor#execute execute a command}. - * If a function, then it will be called with the - * {@link module:engine/view/observer/keyobserver~KeyEventData key event data} object and - * a `cancel()` helper to both `preventDefault()` and `stopPropagation()` of the event. - * @param options Additional options. - * @param options.priority The priority of the keystroke callback. The higher the priority value - * the sooner the callback will be executed. Keystrokes having the same priority - * are called in the order they were added. - */ - set(keystroke, callback, options = {}) { - if (typeof callback == 'string') { - const commandName = callback; - callback = (evtData, cancel) => { - this.editor.execute(commandName); - cancel(); - }; - } - super.set(keystroke, callback, options); - } -} - - -/***/ }), - -/***/ "./node_modules/@ckeditor/ckeditor5-core/src/editor/editor.js": -/*!********************************************************************!*\ - !*** ./node_modules/@ckeditor/ckeditor5-core/src/editor/editor.js ***! - \********************************************************************/ -/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { - -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export */ __webpack_require__.d(__webpack_exports__, { -/* harmony export */ "default": () => (/* binding */ Editor) -/* harmony export */ }); -/* harmony import */ var _ckeditor_ckeditor5_utils__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @ckeditor/ckeditor5-utils */ "./node_modules/@ckeditor/ckeditor5-utils/src/index.js"); -/* harmony import */ var _ckeditor_ckeditor5_engine__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @ckeditor/ckeditor5-engine */ "./node_modules/@ckeditor/ckeditor5-engine/src/index.js"); -/* harmony import */ var _context__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../context */ "./node_modules/@ckeditor/ckeditor5-core/src/context.js"); -/* harmony import */ var _plugincollection__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../plugincollection */ "./node_modules/@ckeditor/ckeditor5-core/src/plugincollection.js"); -/* harmony import */ var _commandcollection__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../commandcollection */ "./node_modules/@ckeditor/ckeditor5-core/src/commandcollection.js"); -/* harmony import */ var _editingkeystrokehandler__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../editingkeystrokehandler */ "./node_modules/@ckeditor/ckeditor5-core/src/editingkeystrokehandler.js"); -/** - * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved. - * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license - */ -/** - * @module core/editor/editor - */ - - - - - - -/** - * The class representing a basic, generic editor. - * - * Check out the list of its subclasses to learn about specific editor implementations. - * - * All editor implementations (like {@link module:editor-classic/classiceditor~ClassicEditor} or - * {@link module:editor-inline/inlineeditor~InlineEditor}) should extend this class. They can add their - * own methods and properties. - * - * When you are implementing a plugin, this editor represents the API - * which your plugin can expect to get when using its {@link module:core/plugin~Plugin#editor} property. - * - * This API should be sufficient in order to implement the "editing" part of your feature - * (schema definition, conversion, commands, keystrokes, etc.). - * It does not define the editor UI, which is available only if - * the specific editor implements also the {@link ~Editor#ui} property - * (as most editor implementations do). - */ -class Editor extends (0,_ckeditor_ckeditor5_utils__WEBPACK_IMPORTED_MODULE_0__.ObservableMixin)() { - /** - * Creates a new instance of the editor class. - * - * Usually, not to be used directly. See the static {@link module:core/editor/editor~Editor.create `create()`} method. - * - * @param config The editor configuration. - */ - constructor(config = {}) { - super(); - const constructor = this.constructor; - // Prefer the language passed as the argument to the constructor instead of the constructor's `defaultConfig`, if both are set. - const language = config.language || (constructor.defaultConfig && constructor.defaultConfig.language); - this._context = config.context || new _context__WEBPACK_IMPORTED_MODULE_2__["default"]({ language }); - this._context._addEditor(this, !config.context); - // Clone the plugins to make sure that the plugin array will not be shared - // between editors and make the watchdog feature work correctly. - const availablePlugins = Array.from(constructor.builtinPlugins || []); - this.config = new _ckeditor_ckeditor5_utils__WEBPACK_IMPORTED_MODULE_0__.Config(config, constructor.defaultConfig); - this.config.define('plugins', availablePlugins); - this.config.define(this._context._getEditorConfig()); - this.plugins = new _plugincollection__WEBPACK_IMPORTED_MODULE_3__["default"](this, availablePlugins, this._context.plugins); - this.locale = this._context.locale; - this.t = this.locale.t; - this._readOnlyLocks = new Set(); - this.commands = new _commandcollection__WEBPACK_IMPORTED_MODULE_4__["default"](); - this.set('state', 'initializing'); - this.once('ready', () => (this.state = 'ready'), { priority: 'high' }); - this.once('destroy', () => (this.state = 'destroyed'), { priority: 'high' }); - this.model = new _ckeditor_ckeditor5_engine__WEBPACK_IMPORTED_MODULE_1__.Model(); - this.on('change:isReadOnly', () => { - this.model.document.isReadOnly = this.isReadOnly; - }); - const stylesProcessor = new _ckeditor_ckeditor5_engine__WEBPACK_IMPORTED_MODULE_1__.StylesProcessor(); - this.data = new _ckeditor_ckeditor5_engine__WEBPACK_IMPORTED_MODULE_1__.DataController(this.model, stylesProcessor); - this.editing = new _ckeditor_ckeditor5_engine__WEBPACK_IMPORTED_MODULE_1__.EditingController(this.model, stylesProcessor); - this.editing.view.document.bind('isReadOnly').to(this); - this.conversion = new _ckeditor_ckeditor5_engine__WEBPACK_IMPORTED_MODULE_1__.Conversion([this.editing.downcastDispatcher, this.data.downcastDispatcher], this.data.upcastDispatcher); - this.conversion.addAlias('dataDowncast', this.data.downcastDispatcher); - this.conversion.addAlias('editingDowncast', this.editing.downcastDispatcher); - this.keystrokes = new _editingkeystrokehandler__WEBPACK_IMPORTED_MODULE_5__["default"](this); - this.keystrokes.listenTo(this.editing.view.document); - } - /** - * Defines whether the editor is in the read-only mode. - * - * In read-only mode the editor {@link #commands commands} are disabled so it is not possible - * to modify the document by using them. Also, the editable element(s) become non-editable. - * - * In order to make the editor read-only, you need to call the {@link #enableReadOnlyMode} method: - * - * ```ts - * editor.enableReadOnlyMode( 'feature-id' ); - * ``` - * - * Later, to turn off the read-only mode, call {@link #disableReadOnlyMode}: - * - * ```ts - * editor.disableReadOnlyMode( 'feature-id' ); - * ``` - * - * @readonly - * @observable - */ - get isReadOnly() { - return this._readOnlyLocks.size > 0; - } - set isReadOnly(value) { - /** - * The {@link module:core/editor/editor~Editor#isReadOnly Editor#isReadOnly} property is read-only since version `34.0.0` - * and can be set only using {@link module:core/editor/editor~Editor#enableReadOnlyMode `Editor#enableReadOnlyMode( lockId )`} and - * {@link module:core/editor/editor~Editor#disableReadOnlyMode `Editor#disableReadOnlyMode( lockId )`}. - * - * Usage before version `34.0.0`: - * - * ```ts - * editor.isReadOnly = true; - * editor.isReadOnly = false; - * ``` - * - * Usage since version `34.0.0`: - * - * ```ts - * editor.enableReadOnlyMode( 'my-feature-id' ); - * editor.disableReadOnlyMode( 'my-feature-id' ); - * ``` - * - * @error editor-isreadonly-has-no-setter - */ - throw new _ckeditor_ckeditor5_utils__WEBPACK_IMPORTED_MODULE_0__.CKEditorError('editor-isreadonly-has-no-setter'); - } - /** - * Turns on the read-only mode in the editor. - * - * Editor can be switched to or out of the read-only mode by many features, under various circumstances. The editor supports locking - * mechanism for the read-only mode. It enables easy control over the read-only mode when many features wants to turn it on or off at - * the same time, without conflicting with each other. It guarantees that you will not make the editor editable accidentally (which - * could lead to errors). - * - * Each read-only mode request is identified by a unique id (also called "lock"). If multiple plugins requested to turn on the - * read-only mode, then, the editor will become editable only after all these plugins turn the read-only mode off (using the same ids). - * - * Note, that you cannot force the editor to disable the read-only mode if other plugins set it. - * - * After the first `enableReadOnlyMode()` call, the {@link #isReadOnly `isReadOnly` property} will be set to `true`: - * - * ```ts - * editor.isReadOnly; // `false`. - * editor.enableReadOnlyMode( 'my-feature-id' ); - * editor.isReadOnly; // `true`. - * ``` - * - * You can turn off the read-only mode ("clear the lock") using the {@link #disableReadOnlyMode `disableReadOnlyMode()`} method: - * - * ```ts - * editor.enableReadOnlyMode( 'my-feature-id' ); - * // ... - * editor.disableReadOnlyMode( 'my-feature-id' ); - * editor.isReadOnly; // `false`. - * ``` - * - * All "locks" need to be removed to enable editing: - * - * ```ts - * editor.enableReadOnlyMode( 'my-feature-id' ); - * editor.enableReadOnlyMode( 'my-other-feature-id' ); - * // ... - * editor.disableReadOnlyMode( 'my-feature-id' ); - * editor.isReadOnly; // `true`. - * editor.disableReadOnlyMode( 'my-other-feature-id' ); - * editor.isReadOnly; // `false`. - * ``` - * - * @param lockId A unique ID for setting the editor to the read-only state. - */ - enableReadOnlyMode(lockId) { - if (typeof lockId !== 'string' && typeof lockId !== 'symbol') { - /** - * The lock ID is missing or it is not a string or symbol. - * - * @error editor-read-only-lock-id-invalid - */ - throw new _ckeditor_ckeditor5_utils__WEBPACK_IMPORTED_MODULE_0__.CKEditorError('editor-read-only-lock-id-invalid', null, { lockId }); - } - if (this._readOnlyLocks.has(lockId)) { - return; - } - this._readOnlyLocks.add(lockId); - if (this._readOnlyLocks.size === 1) { - // Manually fire the `change:isReadOnly` event as only getter is provided. - this.fire('change:isReadOnly', 'isReadOnly', true, false); - } - } - /** - * Removes the read-only lock from the editor with given lock ID. - * - * When no lock is present on the editor anymore, then the {@link #isReadOnly `isReadOnly` property} will be set to `false`. - * - * @param lockId The lock ID for setting the editor to the read-only state. - */ - disableReadOnlyMode(lockId) { - if (typeof lockId !== 'string' && typeof lockId !== 'symbol') { - throw new _ckeditor_ckeditor5_utils__WEBPACK_IMPORTED_MODULE_0__.CKEditorError('editor-read-only-lock-id-invalid', null, { lockId }); - } - if (!this._readOnlyLocks.has(lockId)) { - return; - } - this._readOnlyLocks.delete(lockId); - if (this._readOnlyLocks.size === 0) { - // Manually fire the `change:isReadOnly` event as only getter is provided. - this.fire('change:isReadOnly', 'isReadOnly', false, true); - } - } - /** - * Loads and initializes plugins specified in the configuration. - * - * @returns A promise which resolves once the initialization is completed, providing an array of loaded plugins. - */ - initPlugins() { - const config = this.config; - const plugins = config.get('plugins'); - const removePlugins = config.get('removePlugins') || []; - const extraPlugins = config.get('extraPlugins') || []; - const substitutePlugins = config.get('substitutePlugins') || []; - return this.plugins.init(plugins.concat(extraPlugins), removePlugins, substitutePlugins); - } - /** - * Destroys the editor instance, releasing all resources used by it. - * - * **Note** The editor cannot be destroyed during the initialization phase so if it is called - * while the editor {@link #state is being initialized}, it will wait for the editor initialization before destroying it. - * - * @fires destroy - * @returns A promise that resolves once the editor instance is fully destroyed. - */ - destroy() { - let readyPromise = Promise.resolve(); - if (this.state == 'initializing') { - readyPromise = new Promise(resolve => this.once('ready', resolve)); - } - return readyPromise - .then(() => { - this.fire('destroy'); - this.stopListening(); - this.commands.destroy(); - }) - .then(() => this.plugins.destroy()) - .then(() => { - this.model.destroy(); - this.data.destroy(); - this.editing.destroy(); - this.keystrokes.destroy(); - }) - // Remove the editor from the context. - // When the context was created by this editor, the context will be destroyed. - .then(() => this._context._removeEditor(this)); - } - /** - * Executes the specified command with given parameters. - * - * Shorthand for: - * - * ```ts - * editor.commands.get( commandName ).execute( ... ); - * ``` - * - * @param commandName The name of the command to execute. - * @param commandParams Command parameters. - * @returns The value returned by the {@link module:core/commandcollection~CommandCollection#execute `commands.execute()`}. - */ - execute(commandName, ...commandParams) { - try { - return this.commands.execute(commandName, ...commandParams); - } - catch (err) { - // @if CK_DEBUG // throw err; - /* istanbul ignore next -- @preserve */ - _ckeditor_ckeditor5_utils__WEBPACK_IMPORTED_MODULE_0__.CKEditorError.rethrowUnexpectedError(err, this); - } - } - /** - * Focuses the editor. - * - * **Note** To explicitly focus the editing area of the editor, use the - * {@link module:engine/view/view~View#focus `editor.editing.view.focus()`} method of the editing view. - * - * Check out the {@glink framework/deep-dive/ui/focus-tracking#focus-in-the-editor-ui Focus in the editor UI} section - * of the {@glink framework/deep-dive/ui/focus-tracking Deep dive into focus tracking} guide to learn more. - */ - focus() { - this.editing.view.focus(); - } - /* istanbul ignore next -- @preserve */ - /** - * Creates and initializes a new editor instance. - * - * This is an abstract method. Every editor type needs to implement its own initialization logic. - * - * See the `create()` methods of the existing editor types to learn how to use them: - * - * * {@link module:editor-classic/classiceditor~ClassicEditor.create `ClassicEditor.create()`} - * * {@link module:editor-balloon/ballooneditor~BalloonEditor.create `BalloonEditor.create()`} - * * {@link module:editor-decoupled/decouplededitor~DecoupledEditor.create `DecoupledEditor.create()`} - * * {@link module:editor-inline/inlineeditor~InlineEditor.create `InlineEditor.create()`} - */ - static create(...args) { - throw new Error('This is an abstract method.'); - } -} -/** - * This error is thrown when trying to pass a `