Skip to content

Commit

Permalink
Merge pull request #2008 from tf/duplicate-section
Browse files Browse the repository at this point in the history
Duplicating sections
  • Loading branch information
tf authored Sep 27, 2023
2 parents 5301373 + 67e5ec6 commit 66d1aea
Show file tree
Hide file tree
Showing 23 changed files with 621 additions and 40 deletions.
5 changes: 5 additions & 0 deletions app/assets/stylesheets/pageflow/editor/drop_down_button.scss
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@
@include icon-only-button;
}

> button.ellipsis_icon {
@include fa-ellipsis-v-icon;
width: 31px;
}

&.full_width {
width: 100%;

Expand Down
5 changes: 0 additions & 5 deletions app/assets/stylesheets/pageflow/editor/inputs/file_input.scss
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,6 @@
}

.drop_down_button {
button {
@include fa-ellipsis-v-icon;
width: 31px;
}

position: absolute;
bottom: 0;
left: 70px;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,21 @@ class SectionsController < ActionController::Base

def create
chapter = Chapter.all_for_revision(@entry.draft).find(params[:chapter_id])
section = chapter.sections.create(section_params)
section = chapter.create_section(section_params)

render partial: 'pageflow_scrolled/sections/section',
render partial: 'pageflow_scrolled/editor/sections/section_with_content_elements',
locals: {section: section},
status: :created
end

def duplicate
section = Section.all_for_revision(@entry.draft).find(params[:id])

render partial: 'pageflow_scrolled/editor/sections/section_with_content_elements',
locals: {section: section.chapter.duplicate_section(section)},
status: :created
end

def update
section = Section.all_for_revision(@entry.draft).find(params[:id])
section.update(section_params)
Expand Down
23 changes: 23 additions & 0 deletions entry_types/scrolled/app/models/pageflow_scrolled/chapter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,36 @@ class Chapter < Pageflow::ApplicationRecord
attr_accessor :revision # used on :create to lazily create storyline
before_validation :ensure_storyline, on: :create

def create_section(attributes = {})
shift_section_positions(from: attributes[:position])

section = sections.create!(attributes)
section.content_elements.create!(type_name: 'textBlock')

section
end

def duplicate_section(section)
shift_section_positions(from: section.position + 1)

section.duplicate do |new_section|
new_section.position = section.position + 1
end
end

def self.all_for_revision(revision)
joins(storyline: :revision)
.where(pageflow_scrolled_storylines: {revision_id: revision})
end

private

def shift_section_positions(from:)
sections
.where('position >= ?', from)
.update_all('position = position + 1')
end

def ensure_storyline
return if storyline.present?
unless Storyline.all_for_revision(revision).exists?
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
json.key_format!(camelize: :lower)

json.partial! 'pageflow_scrolled/sections/section', section: section

json.content_elements do
json.array!(section.content_elements) do |content_element|
json.partial! 'pageflow_scrolled/content_elements/content_element',
content_element: content_element
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
de:
pageflow_scrolled:
editor:
section_item:
duplicate: Duplizieren
insert_section_above: Abschnitt oberhalb einfügen
insert_section_below: Abschnitt unterhalb einfügen
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
en:
pageflow_scrolled:
editor:
section_item:
duplicate: Duplicate
insert_section_above: Insert section above
insert_section_below: Insert section below
4 changes: 4 additions & 0 deletions entry_types/scrolled/config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@
put :order
end

member do
post :duplicate
end

resources :content_elements do
collection do
put :batch
Expand Down
184 changes: 183 additions & 1 deletion entry_types/scrolled/package/spec/editor/models/Chapter-spec.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import 'pageflow-scrolled/editor';
import {ScrolledEntry} from 'editor/models/ScrolledEntry';
import {factories, setupGlobals} from 'pageflow/testHelpers';
import {normalizeSeed} from 'support';
import {useFakeXhr, normalizeSeed} from 'support';

describe('Chapter', () => {
let testContext;
Expand Down Expand Up @@ -32,4 +32,186 @@ describe('Chapter', () => {
expect(section.configuration.get('transition')).toEqual('beforeAfter');
});
});

describe('#insertSection', () => {
beforeEach(() => {
testContext.entry = factories.entry(ScrolledEntry, {}, {
entryTypeSeed: normalizeSeed({
chapters: [{id: 10}],
sections: [
{id: 100, chapterId: 10, position: 0},
{id: 101, chapterId: 10, position: 1}
]
})
});
});

setupGlobals({
entry: () => testContext.entry
});

it('re-indexes pages when inserting before other section', () => {
const {entry} = testContext;
const chapter = entry.chapters.first();

chapter.insertSection({before: chapter.sections.last()});

expect(chapter.sections.pluck('position')).toEqual([0, 1, 2]);
expect(chapter.sections.pluck('id')).toEqual([100, undefined, 101]);
});

it('re-indexes pages when inserting after other section', () => {
const {entry} = testContext;
const chapter = entry.chapters.first();

chapter.insertSection({after: chapter.sections.first()});

expect(chapter.sections.pluck('position')).toEqual([0, 1, 2]);
expect(chapter.sections.pluck('id')).toEqual([100, undefined, 101]);
});

describe('with sparse positions', () => {
beforeEach(() => {
testContext.entry = factories.entry(ScrolledEntry, {}, {
entryTypeSeed: normalizeSeed({
chapters: [{id: 10}],
sections: [
{id: 100, chapterId: 10, position: 7},
{id: 101, chapterId: 10, position: 8}
]
})
});
});

it('re-indexes pages when inserting after other section', () => {
const {entry} = testContext;
const chapter = entry.chapters.first();

chapter.insertSection({after: chapter.sections.first()});

expect(chapter.sections.pluck('position')).toEqual([7, 8, 9]);
expect(chapter.sections.pluck('id')).toEqual([100, undefined, 101]);
});
});
});

describe('#duplicateSection', () => {
beforeEach(() => {
testContext.entry = factories.entry(ScrolledEntry, {id: 1}, {
entryTypeSeed: normalizeSeed({
chapters: [{id: 10}],
sections: [
{id: 100, chapterId: 10, position: 0, configuration: {transition: 'scroll'}},
{id: 101, chapterId: 10, position: 1}
],
contentElements: [
{id: 1000, permaId: 1, sectionId: 101, position: 0, typeName: 'inlineImage'},
{id: 1001, permaId: 2, sectionId: 101, position: 1, typeName: 'textBlock'}
]
})
});
});

setupGlobals({
entry: () => testContext.entry
});

useFakeXhr(() => testContext);

it('re-indexes pages when inserting before other section', () => {
const {entry} = testContext;
const chapter = entry.chapters.first();

chapter.duplicateSection(chapter.sections.first());

expect(chapter.sections.pluck('position')).toEqual([0, 1, 2]);
expect(chapter.sections.pluck('id')).toEqual([100, undefined, 101]);
});

it('posts requests to duplicate action and adds content elements', () => {
const {entry, server, requests} = testContext;
const chapter = entry.chapters.first();

chapter.duplicateSection(chapter.sections.first());

expect(requests[0].method).toBe('POST');
expect(requests[0].url).toBe('/editor/entries/1/scrolled/sections/100/duplicate');

expect(chapter.sections.pluck('position')).toEqual([0, 1, 2])
expect(chapter.sections.pluck('id')).toEqual([100, undefined, 101])

server.respond(
'POST', '/editor/entries/1/scrolled/sections/100/duplicate',
[200, {'Content-Type': 'application/json'}, JSON.stringify({
id: 102,
configuration: {transition: 'scroll'},
contentElements: [
{
id: 1002,
permaId: 3,
sectionId: 102,
position: 0,
typeName: 'inlineImage',
configuration: {image: 5}
},
{
id: 1003,
permaId: 4,
sectionId: 102,
position: 0,
typeName: 'textBlock',
configuration: {value: 'Some text'}
},
]
})]
);

expect(requests.length).toEqual(1);
expect(chapter.sections.pluck('id')).toEqual([100, 102, 101]);
const section = chapter.sections.get(102);

expect(section.configuration.get('transition')).toEqual('scroll');
expect(section.contentElements.pluck('id')).toEqual([1002, 1003]);
expect(section.contentElements.pluck('typeName')).toEqual(['inlineImage', 'textBlock']);
expect(section.contentElements.first().configuration.get('image')).toEqual(5);
expect(section.contentElements.last().configuration.get('value')).toEqual('Some text');
});

it('does not use duplicate url on subsequent save', () => {
const {entry, server, requests} = testContext;
const chapter = entry.chapters.first();

const section = chapter.duplicateSection(chapter.sections.first());

server.respond(
'POST', '/editor/entries/1/scrolled/sections/100/duplicate',
[200, {'Content-Type': 'application/json'}, JSON.stringify({
id: 102,
configuration: {transition: 'scroll'},
contentElements: [
{
id: 1002,
permaId: 3,
sectionId: 102,
position: 0,
typeName: 'inlineImage',
configuration: {image: 5}
},
{
id: 1003,
permaId: 4,
sectionId: 102,
position: 0,
typeName: 'textBlock',
configuration: {value: 'Some text'}
},
]
})]
);
section.save();

expect(requests.length).toEqual(2);
expect(requests[1].url).toBe('/editor/entries/1/scrolled/sections/102');
});
});
});
Loading

0 comments on commit 66d1aea

Please sign in to comment.