diff --git a/Gemfile.lock b/Gemfile.lock index 4cb778cacf9877c83c73d854e9c51b05f8897961..ff0e6e62953afed7180b45c6d2139b51f3b465b6 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -103,7 +103,7 @@ GEM autoprefixer-rails (10.4.13.0) execjs (~> 2) aws-eventstream (1.2.0) - aws-partitions (1.788.0) + aws-partitions (1.790.0) aws-sdk-core (3.178.0) aws-eventstream (~> 1, >= 1.0.2) aws-partitions (~> 1, >= 1.651.0) @@ -112,7 +112,7 @@ GEM aws-sdk-kms (1.71.0) aws-sdk-core (~> 3, >= 3.177.0) aws-sigv4 (~> 1.1) - aws-sdk-s3 (1.130.0) + aws-sdk-s3 (1.131.0) aws-sdk-core (~> 3, >= 3.177.0) aws-sdk-kms (~> 1) aws-sigv4 (~> 1.6) @@ -131,7 +131,7 @@ GEM rails (>= 3.1) breadcrumbs_on_rails (4.1.0) railties (>= 5.0) - bugsnag (6.25.2) + bugsnag (6.26.0) concurrent-ruby (~> 1.0) builder (3.2.4) byebug (11.1.3) diff --git a/app/assets/javascripts/admin/commons/content_editor.js b/app/assets/javascripts/admin/commons/content_editor.js index 6abb359f00760a48d680d511d92b15f0bfd14bd6..5b19742d72d7fd7738b144a8344d3104d62c0b42 100644 --- a/app/assets/javascripts/admin/commons/content_editor.js +++ b/app/assets/javascripts/admin/commons/content_editor.js @@ -10,124 +10,98 @@ window.osuny.contentEditor = { } this.sortHeadingsUrl = this.container.getAttribute('data-sort-headings-url'); this.sortBlocksUrl = this.container.getAttribute('data-sort-blocks-url'); - - this.initElements(); + this.modeWriteContainer = this.container.querySelector('#mode-write-container'); + this.modeStructureContainer = this.container.querySelector('#mode-structure-container'); + this.initTabs(); this.initSortable(); }, - initElements: function () { + initTabs: function () { 'use strict'; - var elementsContainers = this.container.querySelectorAll('.js-content-editor-element'), - elementInstance, + var tabs = document.querySelectorAll('[data-bs-toggle="tab"]'), i; - - this.elements = []; - for (i = 0; i < elementsContainers.length; i += 1) { - elementInstance = new window.osuny.contentEditor.Element(elementsContainers[i]); - this.elements.push(elementInstance); + for (i = 0; i < tabs.length; i += 1) { + tabs[i].addEventListener('shown.bs.tab', this.tabChanged.bind(this)); } }, initSortable: function () { 'use strict'; var sortableContainers = this.container.querySelectorAll('.js-content-editor-sortable-container'), - sortableInstance, i; - this.sortableRootContainer = document.getElementById('content-editor-elements-root'); - this.sortableInstances = []; - for (i = 0; i < sortableContainers.length; i += 1) { - sortableInstance = new Sortable(sortableContainers[i], { - group: 'nested', + new Sortable(sortableContainers[i], { handle: '.content-editor__elements__handle', - animation: 150, - fallbackOnBody: true, - swapThreshold: 0.65, - onUnchoose: this.onSortableUnchoose.bind(this), - onStart: this.onSortableStart.bind(this), - onMove: this.onSortableMove.bind(this), + fallbackOnBody: false, onEnd: this.onSortableEnd.bind(this) }); - this.sortableInstances.push(sortableInstance); } }, - onSortableStart: function (event) { + tabChanged: function (event) { 'use strict'; - var item = event.item, - kind = item.dataset.kind; - this.sortableRootContainer.classList.add('content-editor__elements__root--dragging'); - if (kind === 'block') { - this.sortableRootContainer.classList.add('content-editor__elements__root--dragging-block'); - } else if (kind === 'heading') { - this.sortableRootContainer.classList.add('content-editor__elements__root--dragging-heading'); - } + var tab = event.target, + id = tab.getAttribute('data-bs-target'), + div = this.container.querySelector(id), + source = div.dataset.source; + this.target = this.container.querySelector(div.dataset.target); + this.target.innerHTML = ''; + this.xhr = new XMLHttpRequest(); + this.xhr.open('GET', source, true); + this.xhr.onreadystatechange = this.tabLoaded.bind(this); + this.xhr.send(); }, - onSortableMove: function (event) { + tabLoaded: function () { 'use strict'; - var draggedKind = event.dragged.dataset.kind, - relatedKind = event.related.dataset.kind, - firstHeading = this.sortableRootContainer.querySelector('.js-content-editor-element[data-kind="heading"]'); - - if (draggedKind === 'block') { - // Prevent dragging a block after a heading, instead of inside - return relatedKind !== 'heading' || !event.willInsertAfter && event.related === firstHeading; + if (this.xhr.readyState === XMLHttpRequest.DONE) { + if (this.xhr.status === 200) { + this.target.innerHTML = this.xhr.responseText; + this.initSortable(); + } } - return true; }, onSortableEnd: function (event) { 'use strict'; - var item = event.item, - kind = item.dataset.kind, - url = this.getUrlFromKind(kind), - to = event.to, - ids = [], - headingId = null, - child, - i; - - if (to.id !== 'content-editor-elements-root') { - // Dragged to heading's children list - headingId = event.to.parentNode.dataset.id; + if (event.from.classList.contains('content-editor--write')) { + this.sortModeWrite(event.to); + } else if (event.from.classList.contains('content-editor--organize')) { + this.sortModeOrganize(event.to); } + }, + // Mode écriture du contenu + sortModeWrite: function (to) { + 'use strict'; + var ids = [], + child, + i; for (i = 0; i < to.children.length; i += 1) { child = to.children[i]; - if (child.dataset.kind === kind) { - ids.push(child.dataset.id); - } + // Nous utilisons une route déjà existante, dédiée aux blocs, + // pour gérer à la fois des blocs et des headings. + // Ca manque d'élégance. + ids.push({ + id: child.dataset.id, + kind: child.dataset.kind + }); } - - // call to application - $.post(url, { - heading: headingId, - ids: ids - }); + $.post(this.sortBlocksUrl, { ids: ids }); }, - onSortableUnchoose: function () { + // Mode organisation du plan + sortModeOrganize: function (to) { 'use strict'; - this.sortableRootContainer.classList.remove('content-editor__elements__root--dragging', - 'content-editor__elements__root--dragging-block', - 'content-editor__elements__root--dragging-heading'); - }, - - getUrlFromKind: function (kind) { - 'use strict'; - if (kind === 'block') { - return this.sortBlocksUrl; - } else if (kind === 'heading') { - return this.sortHeadingsUrl; + var ids = [], + child, + i; + for (i = 0; i < to.children.length; i += 1) { + child = to.children[i]; + ids.push(child.dataset.id); } - return null; - }, - - getElementById: function (id) { - 'use strict'; - return this.elements[id]; + $.post(this.sortHeadingsUrl, { ids: ids }); }, invoke: function () { diff --git a/app/assets/stylesheets/admin/commons/content-editor.sass b/app/assets/stylesheets/admin/commons/content-editor.sass index c10f1d4de19d750dd83581cfd89357f3d8391e6b..a9cc2e2f3b639dde33c5d34841ea4519ffe28de6 100644 --- a/app/assets/stylesheets/admin/commons/content-editor.sass +++ b/app/assets/stylesheets/admin/commons/content-editor.sass @@ -1,9 +1,5 @@ .content-editor &__elements - &__root - &--dragging-heading - .content-editor__elements__element--block - display: none &__element .draft .kind @@ -13,18 +9,14 @@ &.sortable-chosen .content-editor__elements display: none + &--mode-structure + .content-editor__elements__handle + cursor: move &--hover opacity: 0 transition: opacity 0.25s ease - // @alex @olivia désolé - // j'ai besoin de rendre visible le hover du heading mais pas tous les enfants pour autant - // @arnaud &:hover - > .content-editor__elements__element--hover, - > * > .content-editor__elements__element--hover, - > * > * > .content-editor__elements__element--hover, - > * > * > * > .content-editor__elements__element--hover, - > * > * > * > * > .content-editor__elements__element--hover + .content-editor__elements__element--hover opacity: 1 &__handle margin-left: 10px diff --git a/app/assets/stylesheets/admin/commons/treeview.sass b/app/assets/stylesheets/admin/commons/treeview.sass index 971a90d4545f53fa4f3c2003d53c324d81e68ef4..0b0ed1aaa1a24eb47acbf3069339293777b0ce64 100644 --- a/app/assets/stylesheets/admin/commons/treeview.sass +++ b/app/assets/stylesheets/admin/commons/treeview.sass @@ -1,6 +1,6 @@ .treeview &__element - a + a:not(.action) text-decoration: none & > .treeview__children .treeview__empty display: none diff --git a/app/controllers/admin/communication/blocks/headings_controller.rb b/app/controllers/admin/communication/blocks/headings_controller.rb index b0a68426d2131bf94cc6755d8ba50ad114d92fb6..53e597801d721d002943bb1879034058a51121e6 100644 --- a/app/controllers/admin/communication/blocks/headings_controller.rb +++ b/app/controllers/admin/communication/blocks/headings_controller.rb @@ -9,6 +9,8 @@ class Admin::Communication::Blocks::HeadingsController < Admin::Communication::B ids.each.with_index do |id, index| @heading = current_university.communication_block_headings.find(id) @heading.update_columns parent_id: parent_id, + parent_id: nil, + level: Communication::Block::Heading::DEFAULT_LEVEL, position: index + 1 end if @heading.about&.respond_to?(:is_direct_object?) diff --git a/app/controllers/admin/communication/blocks_controller.rb b/app/controllers/admin/communication/blocks_controller.rb index 808d3796f3d84f9487e1ecd64a8963e63be92732..ef8895f693388c9d17a9a7678107db0ae53284fd 100644 --- a/app/controllers/admin/communication/blocks_controller.rb +++ b/app/controllers/admin/communication/blocks_controller.rb @@ -4,17 +4,17 @@ class Admin::Communication::BlocksController < Admin::Communication::Application through_association: :communication_blocks def reorder - heading_id = params[:heading] - ids = params[:ids] || [] - ids.each.with_index do |id, index| - @block = current_university.communication_blocks.find(id) - @block.update_columns position: index + 1, - heading_id: heading_id - end - if @block.about&.respond_to?(:is_direct_object?) - @block.about.is_direct_object? ? @block.about.sync_with_git - : @block.about.touch # Sync indirect object's direct sources through after_touch + # Cette action est très étrange, elle ne met pas en ordre les blocs seuls. + # En fait, elle met en ordre dans le mode "Ecrire le contenu", à la fois les headings et les blocks. + @ids = params[:ids] || [] + @index_block = 0 + @index_heading = 0 + @heading = nil + @ids.values.each do |object| + @object = object + reorder_object end + sync_after_reorder end def new @@ -66,6 +66,32 @@ class Admin::Communication::BlocksController < Admin::Communication::Application protected + def reorder_object + @id = @object[:id] + @object[:kind] == 'heading' ? reorder_heading + : reorder_block + end + + def reorder_heading + @heading = current_university.communication_block_headings.find(@id) + @heading.update_columns position: @index_heading + @index_block = 0 + @index_heading += 1 + end + + def reorder_block + @block = current_university.communication_blocks.find(@id) + @block.update_columns position: @index_block, + heading_id: @heading&.id + @index_block += 1 + end + + def sync_after_reorder + return unless @block && @block.about&.respond_to?(:is_direct_object?) + @block.about.is_direct_object? ? @block.about.sync_with_git + : @block.about.touch # Sync indirect object's direct sources through after_touch + end + def website_id params[:website_id] || @block.about&.website.id rescue diff --git a/app/controllers/admin/communication/contents_controller.rb b/app/controllers/admin/communication/contents_controller.rb new file mode 100644 index 0000000000000000000000000000000000000000..ff344cda5f4cd5c317525ee6fe728c11f649decb --- /dev/null +++ b/app/controllers/admin/communication/contents_controller.rb @@ -0,0 +1,20 @@ +class Admin::Communication::ContentsController < Admin::Communication::ApplicationController + before_action :load_about + layout false + + # /admin/communication/contents/Communication::Website::Page/a788f3ab-a3a8-4d26-9440-6cb12fbf442c/write + def write + end + + # /admin/communication/contents/Communication::Website::Page/a788f3ab-a3a8-4d26-9440-6cb12fbf442c/structure + def structure + end + + protected + + def load_about + @about = PolymorphicObjectFinder.find(params, :about) + raise_403_unless @about.university == current_university + raise_403_unless can?(:edit, @about) + end +end \ No newline at end of file diff --git a/app/views/admin/application/i18n/_inline.html.erb b/app/views/admin/application/i18n/_inline.html.erb index 2f6378a7ad390798e833c668ae317f98c61de26e..4c5b3bc773b67690f2b7c07ad3212bf4d40f208d 100644 --- a/app/views/admin/application/i18n/_inline.html.erb +++ b/app/views/admin/application/i18n/_inline.html.erb @@ -1,5 +1,5 @@ <% if about.available_languages.many? %> - <br> <%= t('admin.i18n.in', lang: language_name(about.language.iso_code).downcase) %> + <%= t('admin.i18n.in', lang: language_name(about.language.iso_code).downcase) %> <% route_args = about.is_direct_object? ? [:admin, about.becomes(about.class.base_class)] @@ -12,5 +12,5 @@ [*route_args, lang: language.iso_code] }.compact %> - <br>(<%= t('admin.i18n.switch_to', choices: links.to_sentence).html_safe %>) + (<%= t('admin.i18n.switch_to', choices: links.to_sentence).html_safe %>) <% end %> \ No newline at end of file diff --git a/app/views/admin/communication/blocks/_block.html.erb b/app/views/admin/communication/blocks/_block.html.erb index f85fe076bc795fd60fe9013afcfc690d5cb08eb9..dfd640583c7f7bf2b47ebdae23339e63f61d8812 100644 --- a/app/views/admin/communication/blocks/_block.html.erb +++ b/app/views/admin/communication/blocks/_block.html.erb @@ -19,7 +19,7 @@ <span class=" content-editor__elements__handle content-editor__elements__element--hover"> <span class="handle"> - <span class="small"><%= t 'organize' %></span> + <span class="small"><%= t 'move' %></span> <i class="<%= Icon::SORT %>"></i> </span> </span> diff --git a/app/views/admin/communication/blocks/content/_editor.html.erb b/app/views/admin/communication/blocks/content/_editor.html.erb index 8831804f2b863c3c8ba4e905f6869019be42021b..258ff7c877031e580c7640408e561982ff2b9c06 100644 --- a/app/views/admin/communication/blocks/content/_editor.html.erb +++ b/app/views/admin/communication/blocks/content/_editor.html.erb @@ -1,27 +1,75 @@ +<% +mode_expert = about.headings.many? +%> <div class="js-content-editor mb-5" data-sort-blocks-url="<%= reorder_admin_communication_blocks_path(lang: nil, website_id: nil, extranet_id: nil) %>" - data-sort-headings-url="<%= reorder_admin_communication_headings_path(lang: nil, website_id: nil, extranet_id: nil) %>"> - <div class=" content-editor__elements - content-editor__elements__root - js-content-editor-sortable-container" - id="content-editor-elements-root"> - <% about.blocks.without_heading.ordered.each do |block| %> - <%= render 'admin/communication/blocks/block', block: block %> - <% end %> - <% about.headings.root.ordered.each do |heading| %> - <%= render 'admin/communication/blocks/headings/heading', heading: heading %> - <% end %> - </div> - <div class="content-editor__actions row mt-5"> - <div class="col-lg-4"> - <%= link_to t('admin.communication.blocks.headings.add'), - new_admin_communication_heading_path(about_id: about.id, about_type: about.class.name), - class: 'py-5 px-2 d-block bg-light text-center border h4' if can? :create, Communication::Block::Heading %> + data-sort-headings-url="<%= reorder_admin_communication_headings_path(lang: nil, website_id: nil, extranet_id: nil) %>" + > + <% if mode_expert %> + <ul class="nav nav-tabs justify-content-md-end"> + <li class="nav-item small"> + <a class="nav-link active" + id="mode-write-tab" + data-bs-toggle="tab" + data-bs-target="#mode-write" + type="button" + role="tab" + aria-controls="mode-write" + aria-selected="true"> + <%= t('admin.communication.contents.modes.write.tab') %> + </a> + </li> + <li class="nav-item small"> + <a class="nav-link" + id="mode-structure-tab" + data-bs-toggle="tab" + data-bs-target="#mode-structure" + type="button" + role="tab" + aria-controls="mode-structure" + aria-selected="false"> + <%= t('admin.communication.contents.modes.structure.tab') %> + </a> + </li> + </ul> + <% end %> + <div class="tab-content"> + <div class="tab-pane show active" + id="mode-write" + data-source="<%= admin_communication_contents_write_path(about_type: about.class.polymorphic_name, about_id: about.id) %>" + data-target="#mode-write-container" + role="tabpanel" + aria-labelledby="mode-write-tab" + tabindex="0"> + <% if mode_expert %> + <div class="row"> + <div class="offset-xl-6 col-xl-6"> + <p class="text-lg-end text-muted small mt-2"> + <%= t('admin.communication.contents.modes.write.description') %> + </p> + </div> + </div> + <% end %> + <div id="mode-write-container"> + <%= render 'admin/communication/contents/write', about: about %> + </div> </div> - <div class="col-lg-8"> - <%= link_to t('admin.communication.blocks.add'), - new_admin_communication_block_path(about_id: about.id, about_type: about.class.name), - class: 'py-5 px-2 d-block bg-light text-center border h4' if can? :create, Communication::Block %> + <div class="tab-pane" + id="mode-structure" + data-source="<%= admin_communication_contents_structure_path(about_type: about.class.polymorphic_name, about_id: about.id) %>" + data-target="#mode-structure-container" + role="tabpanel" + aria-labelledby="profile-tab" + tabindex="1"> + <div class="row"> + <div class="offset-xl-6 col-xl-6"> + <p class="text-lg-end text-muted small mt-2"> + <%= t('admin.communication.contents.modes.structure.description') %> + </p> + </div> + </div> + <div id="mode-structure-container"></div> </div> </div> + </div> diff --git a/app/views/admin/communication/blocks/headings/_heading-for-mode-structure.html.erb b/app/views/admin/communication/blocks/headings/_heading-for-mode-structure.html.erb new file mode 100644 index 0000000000000000000000000000000000000000..029ab25ed4138bf0e26e33c7f82f4ab329e2cd17 --- /dev/null +++ b/app/views/admin/communication/blocks/headings/_heading-for-mode-structure.html.erb @@ -0,0 +1,20 @@ +<div class=" content-editor__elements__element + content-editor__elements__element--heading + content-editor__elements__element--mode-structure + js-content-editor-element + mt-3" + data-id="<%= heading.id %>" + data-level="<%= heading.level %>" + data-kind="heading"> + <div class="content-editor__elements__handle" + style="padding-left: <%= (heading.level - Communication::Block::Heading::DEFAULT_LEVEL) * 48 %>px"> + <span class="h4"><%= heading %></span> + <i class="<%= Icon::SORT %>"></i> + <p class="small text-muted"> + <%= t('admin.communication.contents.blocks.quantity', count: heading.blocks.count) %> + </p> + </div> +</div> +<% heading.children.ordered.each do |child| %> + <%= render 'admin/communication/blocks/headings/heading', heading: child %> +<% end %> diff --git a/app/views/admin/communication/blocks/headings/_heading.html.erb b/app/views/admin/communication/blocks/headings/_heading.html.erb index 599eb524547aa3fe6bb3472b4f810accb43d1172..26822180e5b13add9cf116d4a44d5bb2e84ac416 100644 --- a/app/views/admin/communication/blocks/headings/_heading.html.erb +++ b/app/views/admin/communication/blocks/headings/_heading.html.erb @@ -9,24 +9,21 @@ <span class="h4"><%= heading %></span> <%= link_to t('edit'), edit_admin_communication_heading_path(heading), - class: 'action ms-2' %> + class: 'action ms-2'%> <% if can?(:update, heading) %> <span class=" content-editor__elements__handle content-editor__elements__element--hover"> <span class="handle"> - <span class="small"><%= t 'organize' %></span> + <span class="small"><%= t 'move' %></span> <i class="<%= Icon::SORT %>"></i> </span> </span> <% end %> </div> - <div class="content-editor__elements - js-content-editor-sortable-container"> - <% heading.blocks.ordered.each do |block| %> - <%= render 'admin/communication/blocks/block', block: block %> - <% end %> - <% heading.children.ordered.each do |child| %> - <%= render 'admin/communication/blocks/headings/heading', heading: child %> - <% end %> - </div> </div> +<% heading.blocks.ordered.each do |block| %> + <%= render 'admin/communication/blocks/block', block: block %> +<% end %> +<% heading.children.ordered.each do |child| %> + <%= render 'admin/communication/blocks/headings/heading', heading: child %> +<% end %> diff --git a/app/views/admin/communication/contents/_structure.html.erb b/app/views/admin/communication/contents/_structure.html.erb new file mode 100644 index 0000000000000000000000000000000000000000..e60d2a42e5ff4b2184a2d24e3f44824f12eeb8d4 --- /dev/null +++ b/app/views/admin/communication/contents/_structure.html.erb @@ -0,0 +1,7 @@ +<div class=" content-editor__elements + content-editor--organize + js-content-editor-sortable-container"> + <% about.headings.root.ordered.each do |heading| %> + <%= render 'admin/communication/blocks/headings/heading-for-mode-structure', heading: heading %> + <% end %> +</div> diff --git a/app/views/admin/communication/contents/_write.html.erb b/app/views/admin/communication/contents/_write.html.erb new file mode 100644 index 0000000000000000000000000000000000000000..78200449958af13e845ed3a8f8c1d20c97060576 --- /dev/null +++ b/app/views/admin/communication/contents/_write.html.erb @@ -0,0 +1,24 @@ +<div class=" content-editor__elements + content-editor--write + content-editor__elements__root + js-content-editor-sortable-container" + id="content-editor-elements-root"> + <% about.blocks.without_heading.ordered.each do |block| %> + <%= render 'admin/communication/blocks/block', block: block %> + <% end %> + <% about.headings.root.ordered.each do |heading| %> + <%= render 'admin/communication/blocks/headings/heading', heading: heading %> + <% end %> +</div> +<div class="content-editor__actions row mt-5"> + <div class="col-lg-4"> + <%= link_to t('admin.communication.blocks.headings.add'), + new_admin_communication_heading_path(about_id: about.id, about_type: about.class.name), + class: 'py-5 px-2 d-block bg-light text-center border h4' if can? :create, Communication::Block::Heading %> + </div> + <div class="col-lg-8"> + <%= link_to t('admin.communication.blocks.add'), + new_admin_communication_block_path(about_id: about.id, about_type: about.class.name), + class: 'py-5 px-2 d-block bg-light text-center border h4' if can? :create, Communication::Block %> + </div> +</div> \ No newline at end of file diff --git a/app/views/admin/communication/contents/structure.html.erb b/app/views/admin/communication/contents/structure.html.erb new file mode 100644 index 0000000000000000000000000000000000000000..e9b2189d3202323f9e22928c78e1ac1798e44a89 --- /dev/null +++ b/app/views/admin/communication/contents/structure.html.erb @@ -0,0 +1 @@ +<%= render 'admin/communication/contents/structure', about: @about %> \ No newline at end of file diff --git a/app/views/admin/communication/contents/write.html.erb b/app/views/admin/communication/contents/write.html.erb new file mode 100644 index 0000000000000000000000000000000000000000..d34ab2bc5978b8e88803848b52fa315ec2530341 --- /dev/null +++ b/app/views/admin/communication/contents/write.html.erb @@ -0,0 +1 @@ +<%= render 'admin/communication/contents/write', about: @about %> \ No newline at end of file diff --git a/app/views/admin/communication/websites/menus/items/_treebranch.html.erb b/app/views/admin/communication/websites/menus/items/_treebranch.html.erb index 3f2213b5a8cfa5fa4998170a6ca136918eba35b0..5191148c45f16eb34fa5272f2d6576af5218a518 100644 --- a/app/views/admin/communication/websites/menus/items/_treebranch.html.erb +++ b/app/views/admin/communication/websites/menus/items/_treebranch.html.erb @@ -15,10 +15,15 @@ <div class="btn-group ms-auto" role="group"> <%= link_to t('show'), admin_communication_website_menu_item_path(website_id: item.website.id, menu_id: item.menu.id, id: item.id), - class: 'ps-3' %> + class: 'action ps-3' %> <%= link_to t('edit'), edit_admin_communication_website_menu_item_path(website_id: item.website.id, menu_id: item.menu.id, id: item.id), - class: 'ps-3' %> + class: 'action ps-3' %> + <%= link_to t('delete'), + admin_communication_website_menu_item_path(website_id: item.website.id, menu_id: item.menu.id, id: item.id), + method: :delete, + data: { confirm: t('please_confirm') }, + class: 'action text-danger ps-3' %> </div> </div> <ul class="list-unstyled treeview__children js-treeview-children <%= 'js-treeview-sortable-container' if can?(:reorder, item) %> ms-4" data-id="<%= item.id %>"> diff --git a/app/views/admin/communication/websites/pages/_treebranch.html.erb b/app/views/admin/communication/websites/pages/_treebranch.html.erb index 2a723e95f9d00da48f1d6da937611322d3c5ed65..aa1c88af2ddf460165cd5fb2b87a07317844abc6 100644 --- a/app/views/admin/communication/websites/pages/_treebranch.html.erb +++ b/app/views/admin/communication/websites/pages/_treebranch.html.erb @@ -18,7 +18,7 @@ <% end %> </div> <div class="btn-group"> - <%= link_to t('admin.communication.website.pages.show'), admin_communication_website_page_path(page) %> + <%= link_to t('admin.communication.website.pages.show'), admin_communication_website_page_path(page), class: 'action' %> </div> </div> <ul class="list-unstyled treeview__children js-treeview-children <%= 'js-treeview-sortable-container' if can?(:reorder, page) %> ms-4" data-id="<%= page.id %>"> diff --git a/app/views/admin/communication/websites/pages/show/_metadata.html.erb b/app/views/admin/communication/websites/pages/show/_metadata.html.erb index 0f58738714517bb4cf1859b792527c17b1740a9e..11f23bc1deabecc8cac8a5ed0344d8844598d576 100644 --- a/app/views/admin/communication/websites/pages/show/_metadata.html.erb +++ b/app/views/admin/communication/websites/pages/show/_metadata.html.erb @@ -14,27 +14,25 @@ <%= render 'admin/application/i18n/inline', about: @page %> - <% if @page.parent %> - <br> - Dans + <% if @page.parent && !@page.parent.is_home? %> + dans <%= link_to_if can?(:read, @page.parent), @page.parent, admin_communication_website_page_path( website_id: @website.id, id: @page.parent.id - ) %> + ) %>. <% end %> <% if @page.children.any? %> - <br> - <%= Communication::Website::Page.human_attribute_name('children') %> : + avec comme pages enfants : <%= raw @page.children.ordered.map { |child| link_to_if can?(:read, child), child, admin_communication_website_page_path( website_id: @website.id, id: child.id), class: "#{'draft' unless child.published?}" - }.join(', ') %> + }.join(', ') %>. <% end %> <% if @page.full_width %> diff --git a/app/views/admin/communication/websites/pages/tree.html.erb b/app/views/admin/communication/websites/pages/tree.html.erb index 1dfe951ea779c8ed6cef2281482c0cf699cb197d..f0561991e6cad894d89df80ffbaf40bc07e98acd 100644 --- a/app/views/admin/communication/websites/pages/tree.html.erb +++ b/app/views/admin/communication/websites/pages/tree.html.erb @@ -35,7 +35,7 @@ <span class="me-3 show-on-hover"><%= t("communication.website.pages.defaults.home.title") %></span> </div> <div class="btn-group"> - <%= link_to t('admin.communication.website.pages.show'), admin_communication_website_page_path(@homepage) %> + <%= link_to t('admin.communication.website.pages.show'), admin_communication_website_page_path(@homepage), class: 'action' %> </div> </div> <ul class="list-unstyled ms-4 treeview__children js-treeview <%= 'treeview--sortable js-treeview-sortable js-treeview-sortable-container' if can?(:reorder, @homepage) %>" diff --git a/app/views/admin/communication/websites/posts/_list.html.erb b/app/views/admin/communication/websites/posts/_list.html.erb index 8de554b6e4453990ff37542c1a4131977cf79906..46665f5ba46dd6381957b3e6cb05bd4a3fdcd89b 100644 --- a/app/views/admin/communication/websites/posts/_list.html.erb +++ b/app/views/admin/communication/websites/posts/_list.html.erb @@ -4,56 +4,60 @@ hide_category ||= false hide_buttons ||= false selectable ||= false %> -<% if selectable %> - <input type="hidden" name="ids[]" value=""> -<% end %> -<div class="table-responsive <%= 'table-selectable' if selectable %>"> - <table class="<%= table_classes %>"> - <thead> - <tr> - <% if selectable %> - <th class="border-0"> - <%= check_box_tag nil, nil, false, data: { batch_selectable_role: "select-all" } if selectable %> - </th> - <% end %> - <th class="ps-0" width="60%"><%= Communication::Website::Post.human_attribute_name('title') %></th> - <th class="ps-3"><%= Communication::Website::Post.human_attribute_name('meta') %></th> - <th><%= Communication::Website::Post.human_attribute_name('featured_image') %></th> - </tr> - </thead> - <tbody> - <% posts.each do |post| %> - <tr <% unless post.published? %>class="draft"<% end %>> +<% if posts.none? %> + <p><%= t('communication.website.posts.none') %></p> +<% else %> + <% if selectable %> + <input type="hidden" name="ids[]" value=""> + <% end %> + <div class="table-responsive <%= 'table-selectable' if selectable %>"> + <table class="<%= table_classes %>"> + <thead> + <tr> <% if selectable %> - <td class="border-0"><%= check_box_tag "ids[]", post.id, false, data: { batch_selectable_role: "select-single" } %></td> + <th class="border-0"> + <%= check_box_tag nil, nil, false, data: { batch_selectable_role: "select-all" } if selectable %> + </th> <% end %> - <td class="ps-0"> - <%= link_to post, - admin_communication_website_post_path(website_id: post.website.id, id: post.id), - class: "#{'draft' unless post.published?}" %> - </td> - <td class="ps-3 small"> - <% if post.published_at %> - <%= l post.published_at, format: :date_with_explicit_month %><br> - <% end %> - <% if !hide_author && post.author %> - <%= post.author %><br> - <% end %> - <% unless hide_category %> - <ul class="list-unstyled mb-0"> - <% post.categories.each do |category| %> - <li><%= category %></li> - <% end %> - </ul> - <% end %> - <% if post.pinned %> - <%= Communication::Website::Post.human_attribute_name('pinned') %> - <% end %> - </td> - <td><%= image_tag post.featured_image.representation(resize: '200x'), - width: 100 if post.featured_image.attached? && post.featured_image.representable? %></td> + <th class="ps-0" width="60%"><%= Communication::Website::Post.human_attribute_name('title') %></th> + <th class="ps-3"><%= Communication::Website::Post.human_attribute_name('meta') %></th> + <th><%= Communication::Website::Post.human_attribute_name('featured_image') %></th> </tr> - <% end %> - </tbody> - </table> -</div> + </thead> + <tbody> + <% posts.each do |post| %> + <tr <% unless post.published? %>class="draft"<% end %>> + <% if selectable %> + <td class="border-0"><%= check_box_tag "ids[]", post.id, false, data: { batch_selectable_role: "select-single" } %></td> + <% end %> + <td class="ps-0"> + <%= link_to post, + admin_communication_website_post_path(website_id: post.website.id, id: post.id), + class: "#{'draft' unless post.published?}" %> + </td> + <td class="ps-3 small"> + <% if post.published_at %> + <%= l post.published_at, format: :date_with_explicit_month %><br> + <% end %> + <% if !hide_author && post.author %> + <%= post.author %><br> + <% end %> + <% unless hide_category %> + <ul class="list-unstyled mb-0"> + <% post.categories.each do |category| %> + <li><%= category %></li> + <% end %> + </ul> + <% end %> + <% if post.pinned %> + <%= Communication::Website::Post.human_attribute_name('pinned') %> + <% end %> + </td> + <td><%= image_tag post.featured_image.representation(resize: '200x'), + width: 100 if post.featured_image.attached? && post.featured_image.representable? %></td> + </tr> + <% end %> + </tbody> + </table> + </div> +<% end %> \ No newline at end of file diff --git a/app/views/admin/communication/websites/show/_posts.html.erb b/app/views/admin/communication/websites/show/_posts.html.erb index e46152ab639c358ff2ea7317af1673bdb8ad33ab..ba64d41acb96ce2c7842a71f1d465466fe2f179b 100644 --- a/app/views/admin/communication/websites/show/_posts.html.erb +++ b/app/views/admin/communication/websites/show/_posts.html.erb @@ -6,7 +6,12 @@ action += link_to t('create'), action += link_to t('communication.website.posts.new_curation'), new_admin_communication_website_post_curation_path(website_id: @website.id), class: button_classes('ms-2 btn-light') if can?(:create, Communication::Website::Post) -subtitle = link_to t('communication.website.see_all', number: @all_posts.size), admin_communication_website_posts_path(website_id: @website) + +subtitle = '' +if @all_posts.any? + subtitle = link_to t('communication.website.see_all', number: @all_posts.size), + admin_communication_website_posts_path(website_id: @website) +end %> <%= osuny_panel t('communication.website.last_posts'), subtitle: subtitle, diff --git a/config/locales/communication/en.yml b/config/locales/communication/en.yml index 5e257a9a1e51231a79eda21598aac100697fccf6..41b488a04d17fb110619b46f8d10ceb7a1bea199 100644 --- a/config/locales/communication/en.yml +++ b/config/locales/communication/en.yml @@ -666,6 +666,19 @@ en: video_title: label: Video title placeholder: Enter video title + contents: + blocks: + quantity: + zero: No block + one: 1 block + other: "%{count} blocks" + modes: + write: + tab: Write content + description: In “Write content†mode, you can move blocks and headings anywhere you like, independently of each other. For example, you can move a heading higher up in the document without it taking its blocks with it. + structure: + tab: Organize structure + description: In “Organize structure†mode, you do not see the blocks, only the titles. When you move a title, all the blocks follow. This is the ideal mode for organising long documents. website: pages: as_list: See as a list @@ -782,6 +795,7 @@ en: title: Teachers posts: new_curation: New curation + none: No posts yet. published: Published successful_batch_update: Posts have been updated succesfully unpublished: Unpublished diff --git a/config/locales/communication/fr.yml b/config/locales/communication/fr.yml index 297faaea20b07d9169a2648745acc526739da14a..26797550fe7ac8b5f2ccf23727d6ba3184eb7246 100644 --- a/config/locales/communication/fr.yml +++ b/config/locales/communication/fr.yml @@ -663,6 +663,19 @@ fr: video_title: label: Titre de la vidéo placeholder: Entrer le titre de la vidéo + contents: + blocks: + quantity: + zero: Aucun bloc + one: 1 bloc + other: "%{count} blocs" + modes: + write: + tab: Écrire le contenu + description: Dans le mode “Écrire le contenuâ€, vous pouvez déplacer les blocs et les titres où vous voulez, indépendamment les uns des autres. Ainsi, vous pouvez déplacer un titre plus haut dans le document sans qu'il n'emporte ses blocs. + structure: + tab: Organiser le plan + description: Dans le mode “Organiser le planâ€, vous ne voyez pas les blocs mais seulement les titres. Lorsque vous déplacez un titre, tous les blocs suivent. C'est le mode idéal pour ranger les documents longs. website: pages: as_list: Voir en liste @@ -779,6 +792,7 @@ fr: title: Équipe pédagogique posts: new_curation: Nouvelle curation + none: Il n'y a pas encore d'actualités. published: Publiée successful_batch_update: Les actualités ont bien été mises à jour unpublished: Non publiée diff --git a/config/locales/en.yml b/config/locales/en.yml index df0d2e1554c5f0c31fe83fef230cfaccd6b453ce..fc5648c676bef67571aace35c37430cf4106b059 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -276,6 +276,7 @@ en: server_admin: Admin server sign_out: Log out metadata: Metadata + move: Move open: Open organize: Organize please_confirm: Are you sure? diff --git a/config/locales/fr.yml b/config/locales/fr.yml index b46a688831e8b05a28a17855ea1ca27bcbb26218..c7e4dc9de6d6ef583e18c46aaa69f95dc3a3c7af 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -276,6 +276,7 @@ fr: server_admin: Admin serveur sign_out: Déconnexion metadata: Informations + move: Déplacer open: Ouvrir organize: Organiser please_confirm: Est-ce que vous confirmez ? diff --git a/config/routes/admin/communication.rb b/config/routes/admin/communication.rb index 860d470eb45a7ebad8035a2b6a698943071d59cc..ce05293a096bf83634e0a433db3583aeeae6a4a3 100644 --- a/config/routes/admin/communication.rb +++ b/config/routes/admin/communication.rb @@ -67,6 +67,10 @@ namespace :communication do end end end + scope "/contents/:about_type/:about_id", as: :contents, controller: 'contents' do + get :write + get :structure + end resources :blocks, controller: 'blocks', except: [:index] do collection do resources :headings, controller: 'blocks/headings', except: [:index, :show] do