').addClass('litebox_container');
+ this.$content = $('
').addClass('litebox_content');
+
+ // Bind close handlers
+ this.$wrapper.add(this.$closebutton).on('click', $.proxy(this.eventClose, this));
+ this.$container.click(function(e) { e.stopPropagation(); });
+
+ // Insert into DOM and show
+ this.$container.append(this.$closebutton, this.$content);
+ this.$wrapper.append(this.$container).appendTo(this.$body);
+ this.$wrapper.css('opacity'); // Force reflow
+ this.$wrapper.addClass('visible');
+
+ if(this.options.url) {
+ // Load remote content
+ this.$wrapper.addClass('litebox-busy');
+ $.ajax({
+ url: this.options.url,
+ cache: false,
+ context: this
+ }).done(function(data) {
+ this.insert(data);
+ }).fail(function() {
+ this.$wrapper.addClass('litebox-error');
+ }).always(function() {
+ this.$wrapper.removeClass('litebox-busy');
+ });
+ } else if(this.options.content) {
+ // Get local content
+ this.insert($(this.options.content).show());
+ } else {
+ console.log('LiteBox: No content has been defined');
+ }
+ }
+
+ // Close with Escape key
+ this.$doc.on('keyup.LiteBox', $.proxy(this.eventClose, this));
+ this.isopen = true;
+
+ return this;
+ },
+
+ insert: function(content) {
+ this.$content.html(content);
+ this.$container.addClass('visible');
+ this.$content.find(':text:not(:hidden,[readonly],[disabled]):first').focus();
+
+ // Close litebox if button[type=reset] pressed
+ this.$content.on('click', 'form :reset', $.proxy(this.eventClose, this));
+
+ // Include submit button value into serialization
+ this.$content.on('click', 'form :submit', function() {
+ var button = $(this);
+ button.after($('').attr({
+ type: 'hidden',
+ name: button.attr('name'),
+ value: button.val()
+ }));
+ });
+
+ // Submit an inner form via ajax
+ this.$content.on('submit.LiteBox', 'form', $.proxy(function(e) {
+ e.preventDefault();
+
+ var $form = $(e.currentTarget);
+ var form_method = $form.attr('method');
+ var form_action = $form.attr('action');
+ var multipart = $form.attr('enctype') === 'multipart/form-data';
+ var form_data = multipart ? new FormData($form[0]) : $form.serialize();
+ var $submit = $form.find(':submit').prop('disabled', true);
+
+ this.$content.addClass('ajax-busy');
+
+ $.ajax({
+ url: form_action,
+ method: form_method,
+ data: form_data,
+ cache: false,
+ context: this,
+ contentType: (multipart ? false : 'application/x-www-form-urlencoded; charset=UTF-8'),
+ processData: (multipart ? false : true)
+ }).done(function(data, textStatus, jqXHR) {
+ var status = jqXHR.status;
+ var location = jqXHR.getResponseHeader('location');
+ if(status === 201) {
+ if(location) {
+ var oldPath = window.location.href.split('#')[0];
+ var newPath = location.split('#')[0];
+ window.location.assign(location);
+
+ // Force page reload if location path not changed
+ if(newPath === oldPath) {
+ window.location.reload();
+ }
+ } else {
+ this.close();
+ }
+ } else {
+ this.$content.html(data);
+ }
+ }).fail(function(data) {
+ this.$content.html(data.responseText);
+ this.$content.addClass('ajax-error');
+ }).always(function() {
+ $submit.prop('disabled', false);
+ this.$content.removeClass('ajax-busy');
+ });
+ }, this));
+ },
+
+ close: function() {
+ if(!this.isopen || !this.$wrapper) return;
+
+ // Hide litebox and unbind key handler
+ this.$wrapper.removeClass('visible');
+ this.$doc.off('keyup.LiteBox');
+ this.isopen = false;
+
+ // Enable page scroll
+ if(this.options.noscroll) {
+ this.pageScroll(true);
+ }
+
+ // Remove litebox from DOM after all CSS transitions
+ if(this.options.disposable || this.options.url) {
+ var events = 'transitionend otransitionend oTransitionEnd webkitTransitionEnd msTransitionEnd';
+ this.$wrapper.one(events, $.proxy(this.destroy, this));
+ }
+
+ // Make sure to reset location hash
+ if(this.options.hash) {
+ window.location.replace('#');
+ }
+ },
+
+ eventClose: function(e) {
+ if(e.type === 'keyup' && e.keyCode !== 27) return;
+
+ e.preventDefault();
+ e.stopPropagation();
+
+ this.close();
+ },
+
+ destroy: function(e) {
+ this.$wrapper.remove();
+ this.$wrapper = null;
+ this.$container = null;
+ this.$content = null;
+ }
+ };
+
+ LiteBox.defaults = LiteBox.prototype.defaults;
+
+ $.fn.litebox = function(eventName) {
+ eventName = eventName || 'click';
+
+ return this.each(function() {
+ if(!this.litebox) {
+ var $elm = $(this);
+ var options = $.extend({ url: $elm.attr('href') }, $elm.data('litebox'));
+ if(options.hash === true) {
+ options.hash = options.url;
+ }
+ this.litebox = new LiteBox(options);
+ }
+
+ $(this).on(eventName, function(e) {
+ e.preventDefault();
+ if(this.litebox.options.hash) {
+ document.location.hash = this.litebox.options.hash;
+ } else {
+ this.litebox.open();
+ }
+ });
+ });
+ };
+
+ window.LiteBox = LiteBox;
+
+})(jQuery, window, document);
diff --git a/app/assets/stylesheets/components/buttons.scss b/app/assets/stylesheets/components/buttons.scss
index c15fb2857c..507874b89a 100644
--- a/app/assets/stylesheets/components/buttons.scss
+++ b/app/assets/stylesheets/components/buttons.scss
@@ -160,4 +160,4 @@ button:empty, .button:empty {
position: relative;
}
}
-}
\ No newline at end of file
+}
diff --git a/app/assets/stylesheets/sections/collection.scss b/app/assets/stylesheets/sections/collection.scss
index e6e8447df1..0d4e0ec014 100644
--- a/app/assets/stylesheets/sections/collection.scss
+++ b/app/assets/stylesheets/sections/collection.scss
@@ -147,7 +147,7 @@
display: block;
overflow: hidden;
text-overflow: ellipsis;
-
+
.userpic {
font-size: 26px;
margin-right: 6px;
@@ -306,7 +306,7 @@
.category-article dd p {
width: 33%;
- display: flex;
+ display: flex;
}
.category-article dd p a {
@@ -448,7 +448,7 @@
white-space: normal !important;
vertical-align: top;
}
- td:nth-child(1), th {
+ td:nth-child(1), th {
width: 30%;
}
td:nth-child(2) {
@@ -465,7 +465,6 @@
vertical-align: top;
}
select, .inline-btn, .select2 {
- margin-left: 1em;
display: inline-block;
&.select2-hidden-accessible {
@@ -493,6 +492,12 @@
}
}
+.page-settings {
+ .sidecol {
+ padding-top: 0.5em;
+ }
+}
+
.side-tabs {
$textColor: #322;
float: left;
@@ -571,7 +576,7 @@
padding-right: 1em;
}
}
-
+
&.expanded {
.user-label {
display: inline-block;
@@ -619,7 +624,7 @@
background-color: $bgColor;
border-radius: 16px;
padding: 1em;
-
+
text-align: center;
color: $bodyFgLight;
}
@@ -654,12 +659,12 @@
&_format {
flex: 1 1 auto;
padding-right: 15px;
-
+
h5 {
display: flex;
align-items: center;
margin: 0 0 0.25em 0;
-
+
input {
width: 19px;
height: 19px;
@@ -712,12 +717,12 @@
&_format {
flex: 1 1 auto;
padding-right: 15px;
-
+
h5 {
display: flex;
align-items: center;
margin: 0 0 0.25em 0;
-
+
input {
width: 19px;
height: 19px;
diff --git a/app/assets/stylesheets/sections/page.scss b/app/assets/stylesheets/sections/page.scss
index 3fad04984b..9db707e3bb 100644
--- a/app/assets/stylesheets/sections/page.scss
+++ b/app/assets/stylesheets/sections/page.scss
@@ -545,6 +545,7 @@
.page-image-preview {
text-align: center;
+ margin-bottom: 50px;
img {
height: auto;
max-width: 100%;
diff --git a/app/controllers/page_controller.rb b/app/controllers/page_controller.rb
index 270257d5fd..e30a242e95 100644
--- a/app/controllers/page_controller.rb
+++ b/app/controllers/page_controller.rb
@@ -3,63 +3,20 @@ class PageController < ApplicationController
require 'image_helper'
include ImageHelper
- protect_from_forgery :except => [:set_page_title]
- before_action :authorized?, :except => [:alto_xml]
+ protect_from_forgery except: [:set_page_title]
+ before_action :authorized?, except: [:alto_xml]
# no layout if xhr request
- layout Proc.new { |controller| controller.request.xhr? ? false : nil }, :only => [:new, :create]
+ layout Proc.new { |controller| controller.request.xhr? ? false : nil }, only: [:new, :create]
def authorized?
if user_signed_in?
- if @work
- redirect_to dashboard_path unless current_user.like_owner?(@work)
- end
+ redirect_to dashboard_path if @work && !current_user.like_owner?(@work)
else
redirect_to dashboard_path
end
end
- def alto_xml
- # Transkribus ALTO does not include an ID on the String element, but we need one for Annotorious
- # we need to read the alto file and iterate over every string element, adding an ID attribute
- raw_alto = @page.alto_xml
- doc = Nokogiri::XML(raw_alto)
-
- doc.search('String').each_with_index do |string, i|
- string['ID'] = "string_#{i}"
- end
-
- render :plain => doc.to_xml, :layout => false, :content_type => 'text/xml'
- end
-
- def delete
- @page.destroy
- flash[:notice] = t('.page_deleted')
- redirect_to work_pages_tab_path(:work_id => @work.id)
- end
-
- # image functions
- def rotate
- orientation = params[:orientation].to_i
- 0.upto(@page.shrink_factor) do |i|
- rotate_file(@page.scaled_image(i), orientation)
- end
- set_dimensions(@page)
- redirect_back fallback_location: @page
- end
-
-
- # reordering functions
- def reorder_page
- if(params[:direction]=='up')
- @page.move_higher
- else
- @page.move_lower
- end
- redirect_to work_pages_tab_path(:work_id => @work.id)
- end
-
- # new page functions
def new
@page = Page.new
@page.title = @work.suggest_next_page_title
@@ -67,82 +24,86 @@ def new
end
def create
- @page = Page.new(page_params)
- subaction = params[:subaction]
- @work.pages << @page
-
- if @page.save
- flash[:notice] = t('.page_created')
+ result = Page::Create.call(work: @work, page_params: page_params)
- if page_params[:base_image]
- process_uploaded_file(@page, page_params[:base_image])
- end
+ if result.success?
+ subaction = params[:subaction]
+ flash[:notice] = t('.page_created')
if subaction == 'save_and_new'
- ajax_redirect_to({ :controller => 'dashboard', :action => 'startproject', :anchor => 'create-work' })
+ ajax_redirect_to({ controller: 'dashboard', action: 'startproject', anchor: 'create-work' })
else
- ajax_redirect_to({ :controller => 'work', :action => 'pages_tab', :work_id => @work.id, :anchor => 'create-page' })
+ ajax_redirect_to({ controller: 'work', action: 'pages_tab', work_id: @work.id, anchor: 'create-page' })
end
else
- render :new
+ @page = result.page
+
+ render :new, status: :unprocessable_entity
end
end
+ def edit
+ # Edit route
+ end
+
def update
- page = Page.find(params[:id])
- attributes = page_params.to_h.except("base_image")
- if page_params[:status].blank?
- attributes['status'] = nil
- end
- page.update_columns(attributes) # bypass page version callbacks
- flash[:notice] = t('.page_updated')
- page.work.work_statistic.recalculate if page.work.work_statistic
-
- if params[:page][:base_image]
- process_uploaded_file(page, page_params[:base_image])
+ result = Page::Update.call(page: @page, page_params: page_params)
+
+ if request.xhr?
+ render json: {
+ success: result.success?,
+ errors: result.errors
+ }
+ elsif result.success?
+ flash[:notice] = t('.page_updated')
+ redirect_to collection_edit_page_path(@collection.owner, @collection, @work, @page)
+ else
+ render :edit, status: :unprocessable_entity
end
-
- redirect_back fallback_location: page
end
+ def destroy
+ result = Page::Destroy.call(page: @page)
- private
-
- def process_uploaded_file(page, image_file)
- # create a new filename
- filename = "#{Rails.root}/public/images/working/upload/#{page.id}.jpg"
+ flash[:notice] = t('.page_deleted')
+ redirect_to work_pages_tab_path(work_id: result.page.work_id)
+ end
- dirname = File.dirname(filename)
- unless Dir.exist? dirname
- FileUtils.mkdir_p(dirname)
- end
+ def rotate
+ result = Page::Rotate.call(page: @page, orientation: params[:orientation].to_i)
- FileUtils.mv(image_file.tempfile, filename)
- FileUtils.chmod("u=wr,go=r", filename)
- page.base_image = filename
- page.shrink_factor = 0
- set_dimensions(page)
- #reduce_by_one(page)
+ redirect_back fallback_location: result.page
end
- def reduce_by_one(page)
- page.shrink_factor = page.shrink_factor + 1
- shrink_file(page.scaled_image(0),
- page.scaled_image(page.shrink_factor),
- page.shrink_factor)
- page.save!
+ def reorder
+ Page::Reorder.call(page: @page, direction: params[:direction])
+
+ redirect_to work_pages_tab_path(work_id: @work.id)
end
- def set_dimensions(page)
- image = Magick::ImageList.new(page.base_image)
- page.base_width = image.columns
- page.base_height = image.rows
- image = nil
- page.save!
+ def alto_xml
+ # Transkribus ALTO does not include an ID on the String element, but we need one for Annotorious
+ # we need to read the alto file and iterate over every string element, adding an ID attribute
+ raw_alto = @page.alto_xml
+ doc = Nokogiri::XML(raw_alto)
+
+ doc.search('String').each_with_index do |string, i|
+ string['ID'] = "string_#{i}"
+ end
+
+ render :plain => doc.to_xml, :layout => false, :content_type => 'text/xml'
end
+ private
+
def page_params
- params.require(:page).permit(:page, :title, :base_image, :status, :translation_status)
+ params.require(:page).permit(
+ :page,
+ :title,
+ :base_image,
+ :status,
+ :translation_status
+ )
end
end
diff --git a/app/interactors/page/create.rb b/app/interactors/page/create.rb
new file mode 100644
index 0000000000..30655bf83a
--- /dev/null
+++ b/app/interactors/page/create.rb
@@ -0,0 +1,23 @@
+class Page::Create
+ include Page::Lib::Common
+ include Interactor
+
+ def initialize(work:, page_params:)
+ @work = work
+ @page_params = page_params
+
+ super
+ end
+
+ def call
+ ActiveRecord::Base.transaction do
+ @page = Page.new(@page_params)
+ @work.pages << @page
+
+ context.page = @page
+ process_uploaded_file(@page_params[:base_image]) if @page_params[:base_image]
+ end
+
+ context
+ end
+end
diff --git a/app/interactors/page/destroy.rb b/app/interactors/page/destroy.rb
new file mode 100644
index 0000000000..26c32cf00a
--- /dev/null
+++ b/app/interactors/page/destroy.rb
@@ -0,0 +1,15 @@
+class Page::Destroy
+ include Interactor
+
+ def initialize(page:)
+ @page = page
+
+ super
+ end
+
+ def call
+ @page.destroy
+
+ context
+ end
+end
diff --git a/app/interactors/page/lib/common.rb b/app/interactors/page/lib/common.rb
new file mode 100644
index 0000000000..c39a197350
--- /dev/null
+++ b/app/interactors/page/lib/common.rb
@@ -0,0 +1,32 @@
+module Page::Lib::Common
+
+ def process_uploaded_file(image_file)
+ unless Page::ACCEPTED_FILE_TYPES.include?(image_file.content_type)
+ error_msg = I18n.t('errors.unsupported_file_type')
+ @page.errors.add(:base_image, error_msg)
+ raise StandardError, error_msg
+ end
+
+ filename = "#{Rails.root}/public/images/working/upload/#{@page.id}.jpg"
+
+ dirname = File.dirname(filename)
+ FileUtils.mkdir_p(dirname) unless Dir.exist? dirname
+
+ FileUtils.mv(image_file.tempfile, filename)
+ FileUtils.chmod('u=wr,go=r', filename)
+ @page.base_image = filename
+ @page.shrink_factor = 0
+ assign_dimensions
+ rescue StandardError => e
+ context.errors = e.message
+ context.fail!
+ end
+
+ def assign_dimensions
+ image = Magick::ImageList.new(@page.base_image)
+ @page.base_width = image.columns
+ @page.base_height = image.rows
+ @page.save!
+ end
+
+end
diff --git a/app/interactors/page/reorder.rb b/app/interactors/page/reorder.rb
new file mode 100644
index 0000000000..643a7bff59
--- /dev/null
+++ b/app/interactors/page/reorder.rb
@@ -0,0 +1,16 @@
+class Page::Reorder
+ include Interactor
+
+ def initialize(page:, direction:)
+ @page = page
+ @direction = direction
+
+ super
+ end
+
+ def call
+ @direction == 'up' ? @page.move_higher : @page.move_lower
+
+ context
+ end
+end
diff --git a/app/interactors/page/rotate.rb b/app/interactors/page/rotate.rb
new file mode 100644
index 0000000000..a758a36058
--- /dev/null
+++ b/app/interactors/page/rotate.rb
@@ -0,0 +1,21 @@
+class Page::Rotate
+ include Page::Lib::Common
+ include ImageHelper
+ include Interactor
+
+ def initialize(page:, orientation:)
+ @page = page
+ @orientation = orientation
+
+ super
+ end
+
+ def call
+ 0.upto(@page.shrink_factor) do |i|
+ rotate_file(@page.scaled_image(i), @orientation)
+ end
+ assign_dimensions
+
+ context
+ end
+end
diff --git a/app/interactors/page/update.rb b/app/interactors/page/update.rb
new file mode 100644
index 0000000000..5e5cbc2b7e
--- /dev/null
+++ b/app/interactors/page/update.rb
@@ -0,0 +1,26 @@
+class Page::Update
+ include Page::Lib::Common
+ include Interactor
+
+ def initialize(page:, page_params:)
+ @page = page
+ @page_params = page_params
+
+ super
+ end
+
+ def call
+ ActiveRecord::Base.transaction do
+ attributes = @page_params.to_h.except(:base_image)
+ attributes['status'] = Page.statuses[:new] if @page_params[:status].blank?
+ attributes['translation_status'] = Page.translation_statuses[:new] if @page_params[:translation_status].blank?
+ @page.update_columns(attributes)
+
+ @page.work.work_statistic&.recalculate
+
+ process_uploaded_file(@page_params[:base_image]) if @page_params[:base_image]
+ end
+
+ context
+ end
+end
diff --git a/app/interactors/rake_interactor.rb b/app/interactors/rake_interactor.rb
index f6fcfd2e5d..5034c8e67c 100644
--- a/app/interactors/rake_interactor.rb
+++ b/app/interactors/rake_interactor.rb
@@ -23,8 +23,10 @@ def call
Rake::Task[@task_name].reenable
Rake::Task[@task_name].invoke(*@args.values)
rescue => e
+ # :nocov:
puts "#{e.class}: #{e.message}"
puts e.backtrace.join("\n")
+ # :nocov: end
ensure
$stdout = old_stdout
diff --git a/app/interactors/work/refresh_metadata.rb b/app/interactors/work/refresh_metadata.rb
index 82fa514406..ef66ef8914 100644
--- a/app/interactors/work/refresh_metadata.rb
+++ b/app/interactors/work/refresh_metadata.rb
@@ -18,9 +18,11 @@ def call
finalize
rescue => e
+ # :nocov:
@errors << "Error: #{e}"
context.errors = @errors
context.fail!
+ # :nocov: end
end
def finalize
@@ -37,8 +39,10 @@ def process_batches(works)
begin
refresh_metadata(work)
rescue
+ # :nocov:
@errors << "Failed to refresh metadata for #{work.slug}"
context.fail!
+ # :nocov: end
end
end
end
diff --git a/app/models/page.rb b/app/models/page.rb
index ecea6dbd58..e99d3f9574 100644
--- a/app/models/page.rb
+++ b/app/models/page.rb
@@ -89,6 +89,14 @@ class Page < ApplicationRecord
serialize :metadata, Hash
+ ACCEPTED_FILE_TYPES = [
+ 'image/jpeg',
+ 'image/png',
+ 'image/gif',
+ 'image/bmp',
+ 'image/tiff'
+ ].freeze
+
STATUS_VALUES = {
new: 'new',
blank: 'blank',
@@ -99,6 +107,7 @@ class Page < ApplicationRecord
translated: 'translated'
}.freeze
+
enum status: STATUS_VALUES, _prefix: :status
enum translation_status: STATUS_VALUES, _prefix: :translation_status
diff --git a/app/views/collection/edit.html.slim b/app/views/collection/edit.html.slim
index 7fc0ecabc0..f664360eb1 100644
--- a/app/views/collection/edit.html.slim
+++ b/app/views/collection/edit.html.slim
@@ -16,9 +16,9 @@
th
h3 =f.label :slug, t('.url')
p =t('.url_description')
- td
+ td
=f.text_field :slug, value: @collection.slug
- tr
+ tr
th =t('.current_url')
td
b#collection-url =collection_url(@collection.owner.slug,@collection.slug)
@@ -26,7 +26,7 @@
=svg_symbol '#icon-copy', class: 'icon'
tr
th =t('.transcriber_url')
- td
+ td
b#transcriber-url =collection_start_transcribing_url(@collection.owner.slug, @collection.slug)
a.clipboard-btn (data-clipboard-target='#transcriber-url' aria-label=t('.copy_url') title=t('.copy_url'))
=svg_symbol '#icon-copy', class: 'icon'
@@ -36,7 +36,7 @@
h3 =f.label :tags, t('.subject_tags')
td
=f.select(:tags, options_from_collection_for_select(Tag.where(canonical: true), :id, :ai_text, @collection.tags.pluck(:id)), {}, class: 'field-input', 'data-multi-select': true, size: 1, multiple: true)
- tr
+ tr
th
h3 =t('.collection_image')
p =t('.collection_image_description')
@@ -52,13 +52,13 @@
th
h3 =f.label :intro_block, t('.description')
p = t('.description_message')
- td =f.text_area :intro_block, rows: 6, value: @collection.intro_block
- tr: td
- tr
- th
+ td =f.text_area :intro_block, rows: 6, value: @collection.intro_block
+ tr: td
+ tr
+ th
h3 =t('.footer')
p =t('.footer_description')
- td
+ td
.footer-preview
==@collection.owner.footer_block
-if current_user == @collection.owner
diff --git a/app/views/page/_edit_tabs.html.slim b/app/views/page/_edit_tabs.html.slim
new file mode 100644
index 0000000000..350bd2154e
--- /dev/null
+++ b/app/views/page/_edit_tabs.html.slim
@@ -0,0 +1,22 @@
+-tabs = [{\
+ icon: '#icon-settings',
+ name: t('.general'),
+ selected: 1,
+ path: "#{main_app.collection_edit_page_path(@collection.owner, @collection, @work, @page)}",
+},{\
+ icon: '#icon-robot',
+ name: t('.htr'),
+ selected: 2,
+ path: "#",
+}]
+
+.side-tabs
+ -for tab in tabs
+ -if tab[:selected] == selected
+ a.active
+ =svg_symbol tab[:icon], class: 'icon'
+ =tab[:name]
+ -else
+ =link_to tab[:path]
+ =svg_symbol tab[:icon], class: 'icon'
+ =tab[:name]
diff --git a/app/views/page/_form.html.slim b/app/views/page/_form.html.slim
new file mode 100644
index 0000000000..5bccbf5acf
--- /dev/null
+++ b/app/views/page/_form.html.slim
@@ -0,0 +1,62 @@
+.page-settings.collection-settings-wrapper
+ p= t('.here_you_can_edit')
+ .columns
+ .maincol
+ =form_for(@page,
+ url: page_path(@page),
+ method: :put,
+ remote: true,
+ authenticity_token: true,
+ html: { multipart: true }) do |f|
+ .validation-wrapper(style="#{@page.errors.any? ? '' : 'display:none;'}") = render 'shared/validation_summary', errors: @page.errors
+ =f.submit t('.save_changes'), id: 'collection-settings-save', hidden: true
+ -direction = Rtl.rtl?(@collection.text_language) ? 'rtl' : 'ltr'
+ table.form.collection-settings lang="#{@collection.text_language}" dir=direction class=direction
+ tr
+ th
+ h3 = f.label :title, t('.page_title')
+ td.w100 =f.text_field :title, value: @page.title
+ tr
+ th
+ h3 = f.label :status, t('.page_status')
+ td.w100
+ -option_array = Page::MAIN_STATUSES.map {|stat| [t(".page_status_#{stat}"),stat]}
+ =f.select :status, options_for_select(option_array, @page.status), {}, { class: 'bs ms-0' }
+ -if @work.supports_translation
+ tr
+ th
+ h3 = f.label :translation_status, t('.page_translation_status')
+ td
+ -option_array = Page::TRANSLATION_STATUSES.map {|stat| [t(".page_status_#{stat}"),stat]}
+ =f.select :translation_status, options_for_select(option_array, @page.translation_status)
+ tr
+ th
+ h3 = f.label :base_image, t('.page_image')
+ td
+ .input-file
+ =f.file_field :base_image, tabindex: '-1', accept: 'image/*'
+ input(type="text" tabindex="-1" placeholder=t('.click_to_browse_a_file') aria-label=t('.click_to_browse_a_file') readonly)
+ button(type="button") #{t('.browse')}
+ .sidecol
+ h3 = t('.page_position', position: @page.position)
+ =time_tag @page.created_on
+ =t('.created', date: l(@page.created_on.localtime))
+
+ -if @page.base_image.present?
+ hr
+ .headline
+ h2.headline_title =t('.page_image')
+ .headline_aside
+ span.fgfaded = t('.dimensions', width: @page.base_width, height: @page.base_height).html_safe
+ .headline_aside
+ .button-stack
+ =link_to rotate_page_index_path(page_id: @page.id, orientation: 90), class: 'button outline', title: t('.rotate_clockwise'), method: :post do
+ =svg_symbol "#icon-rotate-cw", class: 'icon'
+ =link_to rotate_page_index_path(page_id: @page.id, orientation: 270), class: 'button outline', title: t('.rotate_counterclockwise'), method: :post do
+ =svg_symbol "#icon-rotate-ccw", class: 'icon'
+
+ .page-image-preview =image_tag("#{file_to_url(@page.canonical_facsimile_url)}?#{Time.now.to_i}")
+
+ .toolbar
+ .toolbar_group.w100
+ =link_to t('.delete'), page_path(@page), method: :delete, data: { confirm: t('.delete_confirm_message') }, class: 'button big'
diff --git a/app/views/page/edit.html.slim b/app/views/page/edit.html.slim
index 42dfb11a2c..98c531b475 100644
--- a/app/views/page/edit.html.slim
+++ b/app/views/page/edit.html.slim
@@ -1,55 +1,5 @@
-=render({ :partial => '/shared/page_tabs', :locals => { :selected => 4, :page_id => @page.id }})
-
-.page-settings.columns
- .maincol
- =form_for :page, url: page_update_path(:id => @page.id), :html => { :multipart => true } do |f|
- -direction = Rtl.rtl?(@collection.text_language) ? 'rtl' : 'ltr'
- table.form lang="#{@collection.text_language}" dir=direction class=direction
- tr.big
- th =f.label :title, t('.page_title')
- td.w100 =f.text_field :title, value: @page.title
- tr
- th =f.label :status, t('.page_status')
- td
- -option_array = Page::MAIN_STATUSES.map {|stat| [t(".page_status_#{stat}"),stat]}
- =f.select :status, options_for_select(option_array, @page.status)
- -if @work.supports_translation
- tr
- th =f.label :translation_status, t('.page_translation_status')
- td
- -option_array = Page::TRANSLATION_STATUSES.map {|stat| [t(".page_status_#{stat}"),stat]}
- =f.select :translation_status, options_for_select(option_array, @page.translation_status)
- -unless @page.base_image.blank?
- tr
- th =f.label :base_image, t('.page_image')
- td
- .input-file
- =f.file_field :base_image, tabindex: '-1', accept: 'image/*'
- input(type="text" tabindex="-1" placeholder=t('.click_to_browse_a_file') aria-label=t('.click_to_browse_a_file') readonly)
- button(type="button") #{t('.browse')}
- .toolbar
- .toolbar_group.w100
- =link_to({ :action => 'delete', :page_id => @page.id }, data: { :confirm => t('.delete_confirm_message') }, class: 'button')
- span =t('.delete_page')
- .toolbar_group =f.button t('.save_changes'), class: 'big'
-
- .sidecol
- big = t('.page_position', position: @page.position)
- =time_tag @page.created_on
- =t('.created', date: l(@page.created_on.localtime))
- p.small.fglight =t('.here_you_can_edit')
-
--if @page.base_image.present?
- hr
- .headline
- h2.headline_title =t('.page_image')
- .headline_aside
- span.fgfaded = t('.dimensions', width: @page.base_width, height: @page.base_height).html_safe
- .headline_aside
- .button-stack
- =link_to(page_rotate_path(:page_id => @page.id, :orientation => 90), class: 'button outline', title: t('.rotate_clockwise'))
- =svg_symbol "#icon-rotate-cw", class: 'icon'
- =link_to(page_rotate_path(:page_id => @page.id, :orientation => 270), class: 'button outline', title: t('.rotate_counterclockwise'))
- =svg_symbol "#icon-rotate-ccw", class: 'icon'
-
- .page-image-preview =image_tag("#{file_to_url(@page.canonical_facsimile_url)}?#{Time.now.to_i}")
+=javascript_include_tag "settings"
+=render({ partial: '/shared/page_tabs', locals: { selected: 4, page_id: @page.id } })
+.collection-meta-wrapper
+ =render({ partial: 'edit_tabs', locals: { selected: 1 }})
+ =render partial: 'form'
diff --git a/app/views/page/new.html.slim b/app/views/page/new.html.slim
index 2d0b755d74..d8f0fd5b54 100644
--- a/app/views/page/new.html.slim
+++ b/app/views/page/new.html.slim
@@ -2,7 +2,7 @@
h1 =t('.add_new_page')
p =t('.choose_a_title')
- =form_for(@page, { :url => { :action => 'create' }}) do |f|
+ =form_for @page, url: page_index_path, method: :post do |f|
=hidden_field_tag(:work_id, @page.work.id)
=validation_summary @page.errors
table.form
diff --git a/app/views/work/pages_tab.html.slim b/app/views/work/pages_tab.html.slim
index b83efdfad4..ebcdb8f081 100644
--- a/app/views/work/pages_tab.html.slim
+++ b/app/views/work/pages_tab.html.slim
@@ -3,7 +3,7 @@
.work-columns.columns
.work-columns_left= t('.pages_tab_description')
.work-columns_right
- =link_to t('.add_new_page'), page_new_path(work_id: @work.id), :data => { litebox: { hash: 'create-page' }}, class: 'button'
+ =link_to t('.add_new_page'), new_page_path(work_id: @work.id), data: { litebox: { hash: 'create-page' } }, class: 'button'
-if @work.pages.empty?
.nodata
@@ -24,7 +24,7 @@
td.nowrap.fgfaded
-if page.base_image.empty?
=svg_symbol '#icon-warning-sign', class: 'icon'
- ==t('.upload_page_image', upload: (link_to t('.upload'), { controller: 'page', action: 'edit', page_id: page.id }))
+ ==t('.upload_page_image', upload: (link_to t('.upload'), collection_edit_page_path(@collection.owner, @collection, @work, page.id)))
-else
=svg_symbol '#icon-check-sign', class: 'icon a50'
==t('.ready_to_transcribe', transcribe: (link_to t('.transcribe'), { controller: 'transcribe', action: 'display_page', page_id: page.id }))
@@ -32,14 +32,14 @@
-if @work.featured_page == page.id
b #{t('.featured_page')}
-else
- =link_to t('.make_featured_page'), work_update_featured_page_path(page_id: page.id)
+ =link_to t('.make_featured_page'), work_update_featured_page_path(page_id: page.id), method: :post
| |
- =link_to t('.settings'), page_edit_path(page_id: page.id)
+ =link_to t('.settings'), collection_edit_page_path(@collection.owner, @collection, @work, page.id)
| |
- =link_to t('.delete'), page_delete_path(page_id: page.id), data: { :confirm => t('.confirm_delete_page') }
+ =link_to t('.delete'), page_path(page), method: :delete, data: { confirm: t('.confirm_delete_page') }
td.nowrap
.work-page-position
- =link_to(page_reorder_page_path(direction: 'up', page_id: page.id), title: t('.move_up'), 'aria-label' => t('.move_up'))
+ =link_to reorder_page_index_path(direction: 'up', page_id: page.id), method: :post, title: t('.move_up'), aria: { label: t('.move_up') } do
=svg_symbol '#icon-arrow-top', class: 'icon', title: 'Move up'
- =link_to({ controller: 'page', action: 'reorder_page', direction: 'down', page_id: page.id }, title: t('.move_down'), 'aria-label' => t('.move_down'))
+ =link_to reorder_page_index_path(direction: 'down', page_id: page.id), method: :post, title: t('.move_down'), aria: { label: t('.move_down') } do
=svg_symbol '#icon-arrow-bottom', class: 'icon', title: 'Move down'
diff --git a/config/locales/activerecord/activerecord-de.yml b/config/locales/activerecord/activerecord-de.yml
index c66a73ecb5..ebcde4efe8 100644
--- a/config/locales/activerecord/activerecord-de.yml
+++ b/config/locales/activerecord/activerecord-de.yml
@@ -9,6 +9,8 @@ de:
document_set:
slug: URL
title: Titel
+ page:
+ base_image: Seitenbild
work:
slug: URL
title: Titel
diff --git a/config/locales/activerecord/activerecord-en.yml b/config/locales/activerecord/activerecord-en.yml
index 85d2039083..b0a3d0b2ff 100644
--- a/config/locales/activerecord/activerecord-en.yml
+++ b/config/locales/activerecord/activerecord-en.yml
@@ -9,6 +9,8 @@ en:
document_set:
slug: URL
title: Title
+ page:
+ base_image: Page image
work:
slug: URL
title: Title
diff --git a/config/locales/activerecord/activerecord-es.yml b/config/locales/activerecord/activerecord-es.yml
index e6c185cdc2..a6af5797fc 100644
--- a/config/locales/activerecord/activerecord-es.yml
+++ b/config/locales/activerecord/activerecord-es.yml
@@ -9,6 +9,8 @@ es:
document_set:
slug: URL
title: Título
+ page:
+ base_image: Imagen de la página
work:
slug: URL
title: Título
diff --git a/config/locales/activerecord/activerecord-fr.yml b/config/locales/activerecord/activerecord-fr.yml
index c22fbcea94..1b1ef76e58 100644
--- a/config/locales/activerecord/activerecord-fr.yml
+++ b/config/locales/activerecord/activerecord-fr.yml
@@ -9,6 +9,8 @@ fr:
document_set:
slug: URL
title: Titre
+ page:
+ base_image: Image de la page
work:
slug: URL
title: Titre
diff --git a/config/locales/activerecord/activerecord-pt.yml b/config/locales/activerecord/activerecord-pt.yml
index b2ab02bc86..f997ec1727 100644
--- a/config/locales/activerecord/activerecord-pt.yml
+++ b/config/locales/activerecord/activerecord-pt.yml
@@ -9,6 +9,8 @@ pt:
document_set:
slug: URL
title: Titulo
+ page:
+ base_image: Imagem da página
work:
slug: URL
title: Titulo
diff --git a/config/locales/collection/collection-de.yml b/config/locales/collection/collection-de.yml
index a870347fee..5e66e60ce6 100644
--- a/config/locales/collection/collection-de.yml
+++ b/config/locales/collection/collection-de.yml
@@ -94,7 +94,6 @@ de:
del_description: Markiert Text, der durch Löschen oder Durchstreichen entfernt wurde.
Empfohlen
del_label: Streichung
description: FromThePage kann Auszeichnungen in Transkripten für TEI-XML oder HTML unterstützen. Wir empfehlen, nicht mehr als sechs Buttons auszuwählen, die im Transkriptionseditor angezeigt werden. Überlegen Sie, ob andere Systeme diese Art von Mark-up verwenden können; wenn nur plain text unterstützt wird, sollten Projekte die Buchdruck-Konventionen anstelle von Mark-up verwenden.
- documentation: Dokumentation
expan_description: Kennzeichnet erweiterte Abkürzungen mit Originalformen im orig-Attribut (Alternative Form des abbr-Tags).
expan_label: Erweiterung
fig_description: Kennzeichnet eine Abbildung oder eine horizontale Linie.
diff --git a/config/locales/collection/collection-en.yml b/config/locales/collection/collection-en.yml
index 7931e71ac5..6aecbcb3c0 100644
--- a/config/locales/collection/collection-en.yml
+++ b/config/locales/collection/collection-en.yml
@@ -94,7 +94,6 @@ en:
del_description: Marks text that has been removed by erasure or strike-through.
Recommended
del_label: Deletion
description: FromThePage can support mark-up within transcripts in either TEI-XML or HTML forms. We recommend configuring no more than six buttons to appear on the transcription editor. Consider whether other systems will be able to use this kind of mark-up; if only plaintext is supported, projects should use letterpress conventions instead of mark-up.
- documentation: Documentation
expan_description: Marks expanded abbreviations with original forms in the orig attribute. (Alternate form of abbr tag.)
expan_label: Expansion
fig_description: Indicates a figure or a horizontal line.
diff --git a/config/locales/collection/collection-es.yml b/config/locales/collection/collection-es.yml
index 80c207e96e..bc11cd08b3 100644
--- a/config/locales/collection/collection-es.yml
+++ b/config/locales/collection/collection-es.yml
@@ -94,7 +94,6 @@ es:
del_description: Marca el texto que ha sido eliminado por borrado o tachado.
Recomendado
del_label: Supresión
description: FromThePage puede admitir el marcado dentro de las transcripciones en formularios TEI-XML o HTML. Recomendamos configurar no más de seis botones para que aparezcan en el editor de transcripción. Considere si otros sistemas podrán usar este tipo de margen; si solo se admite texto sin formato, los proyectos deben usar convenciones tipográficas en lugar de marcado.
- documentation: Documentación
expan_description: Marca abreviaturas expandidas con formas originales en el atributo orig. (Forma alternativa de etiqueta abbr.)
expan_label: Expansión
fig_description: Indica una figura o una línea horizontal.
diff --git a/config/locales/collection/collection-fr.yml b/config/locales/collection/collection-fr.yml
index 1999f7ba07..0907451479 100644
--- a/config/locales/collection/collection-fr.yml
+++ b/config/locales/collection/collection-fr.yml
@@ -94,7 +94,6 @@ fr:
del_description: Marque le texte qui a été supprimé par effacement ou barré.
Recommandé
del_label: Effacement
description: FromThePage peut prendre en charge le balisage dans les transcriptions dans les formulaires TEI-XML ou HTML. Nous vous recommandons de ne pas configurer plus de six boutons à afficher sur l'éditeur de transcription. Demandez-vous si d'autres systèmes pourront utiliser ce type de majoration ; si seul le texte brut est pris en charge, les projets doivent utiliser les conventions typographiques au lieu du balisage.
- documentation: Documentation
expan_description: Marque les abréviations développées avec des formes originales dans l'attribut orig. (Forme alternative de la balise abbr.)
expan_label: Expansion
fig_description: Indique un chiffre ou une ligne horizontale.
diff --git a/config/locales/collection/collection-pt.yml b/config/locales/collection/collection-pt.yml
index 01167d8f29..94f94de4de 100644
--- a/config/locales/collection/collection-pt.yml
+++ b/config/locales/collection/collection-pt.yml
@@ -94,7 +94,6 @@ pt:
del_description: Marca o texto que foi removido por apagamento ou tachado.
Recomendado
del_label: Eliminação
description: FromThePage pode suportar marcação em transcrições em formulários TEI-XML ou HTML. Recomendamos configurar no máximo seis botões para aparecer no editor de transcrição. Considere se outros sistemas poderão usar esse tipo de marcação; se apenas texto simples for suportado, os projetos devem usar convenções de tipografia em vez de marcação.
- documentation: Documentação
expan_description: Marca abreviações expandidas com formas originais no atributo orig. (Forma alternativa de tag abbr.)
expan_label: Expansão
fig_description: Indica uma figura ou uma linha horizontal.
diff --git a/config/locales/errors/errors-de.yml b/config/locales/errors/errors-de.yml
index ae4c8ee645..0f997a25dc 100644
--- a/config/locales/errors/errors-de.yml
+++ b/config/locales/errors/errors-de.yml
@@ -1,4 +1,6 @@
---
de:
errors:
+ error: Da ist etwas schiefgelaufen
html_syntax_error: ungültige html-syntax
+ unsupported_file_type: nicht unterstützter Dateityp
diff --git a/config/locales/errors/errors-en.yml b/config/locales/errors/errors-en.yml
index 8288588128..a7fd1be0cc 100644
--- a/config/locales/errors/errors-en.yml
+++ b/config/locales/errors/errors-en.yml
@@ -1,4 +1,6 @@
---
en:
errors:
+ error: Something went wrong
html_syntax_error: invalid html syntax
+ unsupported_file_type: unsupported file type
diff --git a/config/locales/errors/errors-es.yml b/config/locales/errors/errors-es.yml
index 3dcb2cd1f4..1c16c393b2 100644
--- a/config/locales/errors/errors-es.yml
+++ b/config/locales/errors/errors-es.yml
@@ -1,4 +1,6 @@
---
es:
errors:
+ error: Algo salió mal
html_syntax_error: sintaxis html inválida
+ unsupported_file_type: tipo de archivo no compatible
diff --git a/config/locales/errors/errors-fr.yml b/config/locales/errors/errors-fr.yml
index d6bf0665af..f4b0332a9d 100644
--- a/config/locales/errors/errors-fr.yml
+++ b/config/locales/errors/errors-fr.yml
@@ -1,4 +1,6 @@
---
fr:
errors:
+ error: Quelque chose s'est mal passé
html_syntax_error: syntaxe html invalide
+ unsupported_file_type: type de fichier non pris en charge
diff --git a/config/locales/errors/errors-pt.yml b/config/locales/errors/errors-pt.yml
index 11a64c1a5a..ffd31e83c9 100644
--- a/config/locales/errors/errors-pt.yml
+++ b/config/locales/errors/errors-pt.yml
@@ -1,4 +1,6 @@
---
pt:
errors:
+ error: Algo deu errado
html_syntax_error: sintaxe html inválida
+ unsupported_file_type: tipo de arquivo não suportado
diff --git a/config/locales/page/page-de.yml b/config/locales/page/page-de.yml
index e5accae259..634d3a2d17 100644
--- a/config/locales/page/page-de.yml
+++ b/config/locales/page/page-de.yml
@@ -3,23 +3,28 @@ de:
page:
create:
page_created: Seite erfolgreich erstellt
- delete:
+ destroy:
page_deleted: Seite wurde gelöscht
edit:
+ status: 'Status:'
+ edit_tabs:
+ general: Allgemein
+ htr: HTR
+ form:
browse: Durchsuchen
click_to_browse_a_file: Klicken Sie hier, um eine Datei zu durchsuchen...
created: "%{date} erstellt"
+ delete: Seite löschen
delete_confirm_message: Möchten Sie diese Seite wirklich löschen? Nach dem Löschen können Sie sie nicht wiederherstellen!
- delete_page: Seite löschen
dimensions: 'Maße: %{width} × %{height}'
here_you_can_edit: Hier können Sie den Seitentitel bearbeiten und ein neues Bild hochladen. Wenn Sie die Transkription oder den Übersetzungstext bearbeiten möchten, wechseln Sie bitte oberhalb auf die entsprechende Registerkarte.
page_image: Faksimile
page_position: 'Seitenposition: %{position}'
page_status: Seitenstatus
- page_status_: Nicht angefangen
page_status_blank: Leere Seite
page_status_incomplete: Unvollständig
page_status_indexed: Indexiert
+ page_status_new: Nicht angefangen
page_status_review: Überprüfung erforderlich
page_status_transcribed: Vollständig
page_status_translated: Übersetzt
@@ -28,7 +33,6 @@ de:
rotate_clockwise: Im Uhrzeigersinn drehen
rotate_counterclockwise: Gegen den Uhrzeigersinn drehen
save_changes: Änderungen speichern
- status: 'Status:'
new:
add_new_page: Neue Seite hinzufügen
browse: Durchsuchen
diff --git a/config/locales/page/page-en.yml b/config/locales/page/page-en.yml
index eb3da2313e..77206ff486 100644
--- a/config/locales/page/page-en.yml
+++ b/config/locales/page/page-en.yml
@@ -3,23 +3,28 @@ en:
page:
create:
page_created: Page created successfully
- delete:
+ destroy:
page_deleted: Page has been deleted
edit:
+ status: 'Status: '
+ edit_tabs:
+ general: General
+ htr: HTR
+ form:
browse: Browse
click_to_browse_a_file: Click to browse a file...
created: Created %{date}
+ delete: Delete Page
delete_confirm_message: Are you sure you want to delete this page? After deleting you won't be able to recover it!
- delete_page: Delete Page
dimensions: 'Dimensions: %{width}×%{height}'
here_you_can_edit: Here you can edit the page title and upload a new image. If you want to edit page transcription or translation text please switch to the appropriate tab above.
page_image: Page Image
page_position: 'Page Position: %{position}'
page_status: Page Status
- page_status_: Not Started
page_status_blank: Blank Page
page_status_incomplete: Incomplete
page_status_indexed: Indexed
+ page_status_new: Not Started
page_status_review: Needs Review
page_status_transcribed: Complete
page_status_translated: Translated
@@ -28,7 +33,6 @@ en:
rotate_clockwise: Rotate Clockwise
rotate_counterclockwise: Rotate Counterclockwise
save_changes: Save Changes
- status: 'Status: '
new:
add_new_page: Add New Page
browse: Browse
diff --git a/config/locales/page/page-es.yml b/config/locales/page/page-es.yml
index bab022bbb2..7a6fabfd5f 100644
--- a/config/locales/page/page-es.yml
+++ b/config/locales/page/page-es.yml
@@ -3,23 +3,28 @@ es:
page:
create:
page_created: Página creada con suceso
- delete:
+ destroy:
page_deleted: La página ha sido eliminada
edit:
+ status: 'Estado:'
+ edit_tabs:
+ general: General
+ htr: HTR
+ form:
browse: Navegar
click_to_browse_a_file: Haz clic para consultar un archivo...
created: Creado %{date}
+ delete: Eliminar Página
delete_confirm_message: "¿De verdad deseas eliminar esta colección? ¡Después de eliminarla no podrá ser recuperada!"
- delete_page: Eliminar Página
dimensions: 'Dimensiones: %{width}×%{height}'
here_you_can_edit: Aquí puedes editar el título de la página y subir una nueva imagen. Para editar la transcripción de la página o el texto de traducción, cambia a la pestaña correspondiente arriba.
page_image: Imagen de la Página
page_position: 'Posición de Página: %{position}'
page_status: Estado de la página
- page_status_: No empezado
page_status_blank: Página en blanco
page_status_incomplete: Incompleto
page_status_indexed: Indexado
+ page_status_new: No empezado
page_status_review: Revisión de necesidades
page_status_transcribed: Completo
page_status_translated: Traducido
@@ -28,7 +33,6 @@ es:
rotate_clockwise: Girar en Sentido Horario
rotate_counterclockwise: Girar Hacia la Izquierda
save_changes: Guardar Cambios
- status: 'Estado:'
new:
add_new_page: Añadir Nueva Página
browse: Navegar
diff --git a/config/locales/page/page-fr.yml b/config/locales/page/page-fr.yml
index 723cd8b594..a593f41ed0 100644
--- a/config/locales/page/page-fr.yml
+++ b/config/locales/page/page-fr.yml
@@ -3,23 +3,28 @@ fr:
page:
create:
page_created: Page créée avec succès
- delete:
+ destroy:
page_deleted: La page a été supprimée
edit:
+ status: 'Statut:'
+ edit_tabs:
+ general: Général
+ htr: HTR
+ form:
browse: Parcourir
click_to_browse_a_file: Cliquer pour parcourir un fichier...
created: Créée le %{date}
+ delete: Supprimer la page
delete_confirm_message: Voulez-vous vraiment supprimer cette page ? Après la suppression, vous ne pourrez pas le récupérer !
- delete_page: Supprimer la page
dimensions: 'Dimensions : %{width}×%{height}'
here_you_can_edit: Ici, vous pouvez modifier le titre de la page et téléverser une nouvelle image. Si vous souhaitez modifier la transcription de la page ou le texte de traduction, veuillez passer à l'onglet approprié ci-dessus.
page_image: Image de la page
page_position: 'Position de la page : %{position}'
page_status: Statut de la page
- page_status_: Non-trancrite
page_status_blank: Page vierge
page_status_incomplete: Incomplet
page_status_indexed: Indexé
+ page_status_new: Non-trancrite
page_status_review: À besoin d'une révision
page_status_transcribed: Complet
page_status_translated: Traduit
@@ -28,7 +33,6 @@ fr:
rotate_clockwise: Tourner dans le sens horaire
rotate_counterclockwise: Tourner dans le sens antihoraire
save_changes: Sauvegarder les modifications
- status: 'Statut:'
new:
add_new_page: Ajouter une nouvelle page
browse: Parcourir
diff --git a/config/locales/page/page-pt.yml b/config/locales/page/page-pt.yml
index a371a747a2..c40c9fac68 100644
--- a/config/locales/page/page-pt.yml
+++ b/config/locales/page/page-pt.yml
@@ -3,23 +3,28 @@ pt:
page:
create:
page_created: Esta página foi criada com sucesso
- delete:
+ destroy:
page_deleted: Esta página foi eliminada
edit:
+ status: 'Status:'
+ edit_tabs:
+ general: Em geral
+ htr: HTR
+ form:
browse: Navegar
click_to_browse_a_file: Clique para navegar num arquivo...
created: Criada %{date}
+ delete: Apagar Página
delete_confirm_message: Tem certeza que deseja apagar esta página? Depois de apagar não pode ser recuperada!
- delete_page: Apagar Página
dimensions: 'Dimensões: %{width}×%{height}'
here_you_can_edit: Aqui você pode editar o título da página e subir uma nova imagem. Se quiser editar a transcrição da página ou o texto da tradução, por favor vá para a aba apropriada acima.
page_image: Imagem da Página
page_position: 'Posição da Página: %{position}'
page_status: Status da página
- page_status_: não foi iniciado
page_status_blank: Página em branco
page_status_incomplete: Incompleto
page_status_indexed: Indexado
+ page_status_new: não foi iniciado
page_status_review: Precisa de revisão
page_status_transcribed: Completo
page_status_translated: Traduzido
@@ -28,7 +33,6 @@ pt:
rotate_clockwise: Girar Sentido Horário
rotate_counterclockwise: Girar Sentido Anti-Horário
save_changes: Salvar Alterações
- status: 'Status:'
new:
add_new_page: Adicionar Página Nova
browse: Navegar
diff --git a/config/routes.rb b/config/routes.rb
index 72a5392f14..69235cd8c5 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -132,7 +132,7 @@
scope 'work', as: 'work' do
get 'delete', to: 'work#delete'
- get 'update_featured_page', to: 'work#update_featured_page'
+ post 'update_featured_page', to: 'work#update_featured_page'
get 'pages_tab', to: 'work#pages_tab'
get 'edit', to: 'work#edit'
get ':collection_id/:work_id/edit_scribes', to: 'work#edit_scribes', as: 'edit_scribes'
@@ -144,14 +144,9 @@
get 'document_sets_select', to: 'work#document_sets_select'
end
- scope 'page', as: 'page' do
- get 'new', to: 'page#new'
- get 'delete', to: 'page#delete'
- get 'reorder_page', to: 'page#reorder_page'
- get 'edit', to: 'page#edit'
- get 'rotate', to: 'page#rotate'
- post 'update', to: 'page#update'
- post 'create', to: 'page#create'
+ resources :page, except: [:index, :show, :edit], param: :page_id do
+ post :reorder, on: :collection
+ post :rotate, on: :collection
end
scope 'article', as: 'article' do
diff --git a/spec/factories/page.rb b/spec/factories/page.rb
index 95ae27b6ee..f0a31b41dd 100644
--- a/spec/factories/page.rb
+++ b/spec/factories/page.rb
@@ -12,6 +12,12 @@
end
factory :transcribed_page, :traits => [:transcribed]
factory :page_with_links, :traits => [:with_links]
+
+ trait :with_image do
+ base_image { Rails.root.join('test_data/images/pages/sanskrit.jpg') }
+ base_width { 1581 }
+ base_height { 570 }
+ end
end
end
diff --git a/spec/interactors/page/create_spec.rb b/spec/interactors/page/create_spec.rb
new file mode 100644
index 0000000000..ee831cce55
--- /dev/null
+++ b/spec/interactors/page/create_spec.rb
@@ -0,0 +1,60 @@
+require 'spec_helper'
+
+describe Page::Create do
+ let(:owner) { User.first }
+ let(:collection) { create(:collection, owner_user_id: owner.id) }
+ let(:work) { create(:work, collection: collection) }
+
+ let(:page_params) { { title: 'New page' } }
+
+ let(:result) do
+ described_class.call(work: work, page_params: page_params)
+ end
+
+ it 'creates new page' do
+ expect(result.success?).to be_truthy
+ expect(result.page).to have_attributes(
+ title: 'New page',
+ base_image: '',
+ work_id: work.id
+ )
+ end
+
+ context 'with valid image' do
+ let(:file_path) { Rails.root.join('test_data/images/pages/sanskrit.jpg') }
+ let(:file_type) { 'image/jpeg' }
+ let(:page_params) do
+ {
+ title: 'New page',
+ base_image: Rack::Test::UploadedFile.new(file_path, file_type)
+ }
+ end
+
+ it 'creates new page' do
+ expect(result.success?).to be_truthy
+ expect(result.page).to have_attributes(
+ title: 'New page',
+ base_image: Rails.root.join("public/images/working/upload/#{result.page.id}.jpg").to_s,
+ work_id: work.id
+ )
+ end
+ end
+
+ context 'with invalid image' do
+ let(:file_path) { Rails.root.join('test_data/transcripts/sanskrit.txt') }
+ let(:file_type) { 'text/plain' }
+ let(:page_params) do
+ {
+ title: 'New page',
+ base_image: Rack::Test::UploadedFile.new(file_path, file_type)
+ }
+ end
+
+ it 'fails to create new page' do
+ expect(result).to be_a_failure
+
+ expect(result.page.persisted?).to be_falsey
+ expect(result.errors).to eq('unsupported file type')
+ end
+ end
+end
diff --git a/spec/interactors/page/destroy_spec.rb b/spec/interactors/page/destroy_spec.rb
new file mode 100644
index 0000000000..836b79ceac
--- /dev/null
+++ b/spec/interactors/page/destroy_spec.rb
@@ -0,0 +1,17 @@
+require 'spec_helper'
+
+describe Page::Destroy do
+ let(:owner) { User.first }
+ let(:collection) { create(:collection, owner_user_id: owner.id) }
+ let(:work) { create(:work, collection: collection) }
+ let!(:page) { create(:page, :with_image, work: work, status: :new) }
+
+ let(:result) do
+ described_class.call(page: page)
+ end
+
+ it 'deletes page' do
+ expect(result.success?).to be_truthy
+ expect(result.page.destroyed?).to be_truthy
+ end
+end
diff --git a/spec/interactors/page/reorder_spec.rb b/spec/interactors/page/reorder_spec.rb
new file mode 100644
index 0000000000..9110f4d4db
--- /dev/null
+++ b/spec/interactors/page/reorder_spec.rb
@@ -0,0 +1,39 @@
+require 'spec_helper'
+
+describe Page::Reorder do
+ let(:owner) { User.first }
+ let(:collection) { create(:collection, owner_user_id: owner.id) }
+ let(:work) { create(:work, collection: collection) }
+ let!(:page_1) { create(:page, :with_image, work: work, position: 1) }
+ let!(:page_2) { create(:page, :with_image, work: work, position: 2) }
+ let!(:page_3) { create(:page, :with_image, work: work, position: 3) }
+ let(:direction) {}
+
+ let(:result) do
+ described_class.call(page: page_2, direction: direction)
+ end
+
+ context 'it moves up' do
+ let(:direction) { 'up' }
+
+ it 'reorders pages' do
+ expect(result.success?).to be_truthy
+
+ expect(page_2.reload.position).to eq(1)
+ expect(page_1.reload.position).to eq(2)
+ expect(page_3.reload.position).to eq(3)
+ end
+ end
+
+ context 'it moves down' do
+ let(:direction) { 'down' }
+
+ it 'reorders pages' do
+ expect(result.success?).to be_truthy
+
+ expect(page_1.reload.position).to eq(1)
+ expect(page_3.reload.position).to eq(2)
+ expect(page_2.reload.position).to eq(3)
+ end
+ end
+end
diff --git a/spec/interactors/page/rotate_spec.rb b/spec/interactors/page/rotate_spec.rb
new file mode 100644
index 0000000000..3971504d6d
--- /dev/null
+++ b/spec/interactors/page/rotate_spec.rb
@@ -0,0 +1,50 @@
+require 'spec_helper'
+
+describe Page::Rotate do
+ let(:owner) { User.first }
+ let(:collection) { create(:collection, owner_user_id: owner.id) }
+ let(:work) { create(:work, collection: collection) }
+ let!(:page) { create(:page, :with_image, work: work, position: 1) }
+ let(:original_base_width) { 1581 }
+ let(:original_base_height) { 570 }
+ let(:orientation) { 0 }
+
+ let(:result) do
+ described_class.call(page: page, orientation: orientation)
+ end
+
+ it 'no changes' do
+ expect(result.success?).to be_truthy
+
+ expect(page.reload).to have_attributes(
+ base_width: original_base_width,
+ base_height: original_base_height
+ )
+ end
+
+ context '90 degrees' do
+ let(:orientation) { 90 }
+
+ it 'rotates image' do
+ expect(result.success?).to be_truthy
+
+ expect(page.reload).to have_attributes(
+ base_width: original_base_height,
+ base_height: original_base_width
+ )
+ end
+ end
+
+ context '270 degrees' do
+ let(:orientation) { 270 }
+
+ it 'rotates image' do
+ expect(result.success?).to be_truthy
+
+ expect(page.reload).to have_attributes(
+ base_width: original_base_width,
+ base_height: original_base_height
+ )
+ end
+ end
+end
diff --git a/spec/interactors/page/update_spec.rb b/spec/interactors/page/update_spec.rb
new file mode 100644
index 0000000000..9b240d7969
--- /dev/null
+++ b/spec/interactors/page/update_spec.rb
@@ -0,0 +1,63 @@
+require 'spec_helper'
+
+describe Page::Update do
+ let(:owner) { User.first }
+ let(:collection) { create(:collection, owner_user_id: owner.id) }
+ let(:work) { create(:work, collection: collection) }
+ let(:work_statistic) { create(:work_statistic, work: work) }
+ let!(:page) { create(:page, :with_image, title: 'Original title', work: work, status: :blank) }
+ let(:page_params) { { title: 'Updated title', status: :new, translation_status: :new } }
+
+ let(:result) do
+ described_class.call(page: page, page_params: page_params)
+ end
+
+ it 'updates page' do
+ expect(result.success?).to be_truthy
+ expect(result.page).to have_attributes(
+ title: 'Updated title',
+ work_id: work.id,
+ status: 'new',
+ translation_status: 'new'
+ )
+ end
+
+ context 'with valid image' do
+ let(:file_path) { Rails.root.join('test_data/images/pages/sanskrit.jpg') }
+ let(:file_type) { 'image/jpeg' }
+ let(:page_params) do
+ {
+ title: 'Updated title',
+ base_image: Rack::Test::UploadedFile.new(file_path, file_type)
+ }
+ end
+
+ it 'updates page' do
+ expect(result.success?).to be_truthy
+ expect(result.page).to have_attributes(
+ title: 'Updated title',
+ base_image: Rails.root.join("public/images/working/upload/#{result.page.id}.jpg").to_s,
+ work_id: work.id,
+ status: 'new',
+ translation_status: 'new'
+ )
+ end
+ end
+
+ context 'with invalid image' do
+ let(:file_path) { Rails.root.join('test_data/transcripts/sanskrit.txt') }
+ let(:file_type) { 'text/plain' }
+ let(:page_params) do
+ {
+ title: 'New page',
+ base_image: Rack::Test::UploadedFile.new(file_path, file_type)
+ }
+ end
+
+ it 'fails to create new page' do
+ expect(result).to be_a_failure
+
+ expect(result.errors).to eq('unsupported file type')
+ end
+ end
+end
diff --git a/spec/interactors/work/refresh_metadata_spec.rb b/spec/interactors/work/refresh_metadata_spec.rb
index 4076072a2d..6d65fbf48f 100644
--- a/spec/interactors/work/refresh_metadata_spec.rb
+++ b/spec/interactors/work/refresh_metadata_spec.rb
@@ -15,9 +15,10 @@
let(:sc_manifest) { ScManifest.manifest_for_v3_hash(v3_hash) }
let(:work) { create(:work, collection: collection, sc_manifest: sc_manifest) }
+ let(:work_no_manifest) { create(:work, collection: collection) }
let(:result) do
- described_class.new(work_ids: [work.id]).call
+ described_class.new(work_ids: [work.id, work_no_manifest.id]).call
end
context 'when original metadata is blank' do
diff --git a/spec/requests/page_controller_spec.rb b/spec/requests/page_controller_spec.rb
new file mode 100644
index 0000000000..689e9753c8
--- /dev/null
+++ b/spec/requests/page_controller_spec.rb
@@ -0,0 +1,253 @@
+require 'spec_helper'
+
+describe PageController do
+ let(:owner) { User.first }
+ let(:collection) { create(:collection, owner_user_id: owner.id) }
+ let(:work) { create(:work, collection: collection) }
+ let!(:page) { create(:page, :with_image, work: work, status: :new) }
+
+ describe '#new' do
+ let(:action_path) { new_page_path(work_id: work.id) }
+
+ let(:subject) { get action_path }
+
+ it 'renders status and template' do
+ login_as owner
+ subject
+
+ expect(response).to have_http_status(:ok)
+ expect(response).to render_template(:new)
+ end
+ end
+
+ describe '#create' do
+ let(:action_path) { page_index_path }
+
+ let(:file_path) { Rails.root.join('test_data/images/pages/sanskrit.jpg') }
+ let(:file_type) { 'image/jpeg' }
+ let(:page_params) do
+ {
+ title: 'Page title',
+ base_image: Rack::Test::UploadedFile.new(file_path, file_type)
+ }
+ end
+ let(:subaction) { '' }
+ let(:params) do
+ { work_id: work.id, page: page_params, subaction: subaction }
+ end
+
+ let(:subject) { post action_path, params: params }
+
+ context 'correct params' do
+ it 'redirects' do
+ login_as owner
+ subject
+
+ expect(response).to have_http_status(:redirect)
+ expect(response).to redirect_to(
+ work_pages_tab_path(work_id: work.id, anchor: 'create-page')
+ )
+ end
+
+ context 'with subaction' do
+ let(:subaction) { 'save_and_new' }
+
+ it 'redirects' do
+ login_as owner
+ subject
+
+ expect(response).to have_http_status(:redirect)
+ expect(response).to redirect_to(
+ dashboard_startproject_path(anchor: 'create-work')
+ )
+ end
+ end
+ end
+
+ context 'incorrect params' do
+ let(:file_path) { Rails.root.join('test_data/transcripts/sanskrit.txt') }
+ let(:file_type) { 'text/plain' }
+
+ it 'renders status and template' do
+ login_as owner
+ subject
+
+ expect(response).to have_http_status(:unprocessable_entity)
+ expect(response).to render_template(:new)
+ end
+ end
+ end
+
+ describe '#edit' do
+ let(:action_path) do
+ collection_edit_page_path(owner, collection, work, page.id)
+ end
+
+ let(:subject) { get action_path }
+
+ context 'user not logged in' do
+ it 'redirects' do
+ subject
+
+ expect(response).to have_http_status(:redirect)
+ expect(response).to redirect_to(dashboard_path)
+ end
+ end
+
+ context 'user not owner' do
+ let(:unique_id) { Time.current.to_i }
+ let(:user) do
+ create(
+ :user,
+ login: "user_#{unique_id}",
+ email: "user_#{unique_id}@sample.com"
+ )
+ end
+
+ it 'redirects' do
+ login_as user
+ subject
+
+ expect(response).to have_http_status(:redirect)
+ expect(response).to redirect_to(dashboard_path)
+ end
+ end
+
+ context 'user is owner' do
+ it 'renders status and template' do
+ login_as owner
+ subject
+
+ expect(response).to have_http_status(:ok)
+ expect(response).to render_template(:edit)
+ end
+ end
+ end
+
+ describe '#update' do
+ let(:action_path) { page_path(page) }
+
+ let(:file_path) { Rails.root.join('test_data/images/pages/sanskrit.jpg') }
+ let(:file_type) { 'image/jpeg' }
+ let(:params) do
+ {
+ page: {
+ title: 'Page title',
+ base_image: Rack::Test::UploadedFile.new(file_path, file_type)
+ }
+ }
+ end
+
+ let(:subject) { put action_path, params: params }
+
+ context 'correct params' do
+ it 'redirects' do
+ login_as owner
+ subject
+
+ expect(response).to have_http_status(:redirect)
+ expect(response).to redirect_to(
+ collection_edit_page_path(owner, collection, work, page)
+ )
+ end
+
+ context 'as xhr' do
+ let(:headers) { { 'HTTP_X_REQUESTED_WITH' => 'XMLHttpRequest' } }
+ let(:subject) { put action_path, params: params, headers: headers }
+
+ it 'renders json' do
+ login_as owner
+ subject
+
+ expect(response.content_type).to eq('application/json; charset=utf-8')
+ expect(JSON.parse(response.body)['success']).to be_truthy
+ end
+ end
+ end
+
+ context 'incorrect params' do
+ let(:file_path) { Rails.root.join('test_data/transcripts/sanskrit.txt') }
+ let(:file_type) { 'text/plain' }
+
+ it 'renders status and template' do
+ login_as owner
+ subject
+
+ expect(response).to have_http_status(:unprocessable_entity)
+ expect(response).to render_template(:edit)
+ end
+
+ context 'as xhr' do
+ let(:headers) { { 'HTTP_X_REQUESTED_WITH' => 'XMLHttpRequest' } }
+ let(:subject) { put action_path, params: params, headers: headers }
+
+ it 'renders json' do
+ login_as owner
+ subject
+
+ expect(response.content_type).to eq('application/json; charset=utf-8')
+ expect(JSON.parse(response.body)['success']).to be_falsey
+ expect(JSON.parse(response.body)['errors']).to eq(
+ 'unsupported file type'
+ )
+ end
+ end
+ end
+ end
+
+ describe '#destroy' do
+ let(:action_path) { page_path(page) }
+
+ let(:subject) { delete action_path }
+
+ it 'redirects' do
+ login_as owner
+ subject
+
+ expect(response).to have_http_status(:redirect)
+ expect(response).to redirect_to(work_pages_tab_path(work_id: work.id))
+ end
+ end
+
+ describe '#rotate' do
+ let(:action_path) { rotate_page_index_path }
+ let(:params) { { page_id: page.id, orientation: 90 } }
+
+ let(:subject) { post action_path, params: params }
+
+ it 'redirects' do
+ login_as owner
+ subject
+
+ expect(response).to have_http_status(:redirect)
+ expect(response).to redirect_to(page)
+ end
+
+ context 'no orientation param' do
+ let(:params) { { page_id: page.id } }
+
+ it 'redirects' do
+ login_as owner
+ subject
+
+ expect(response).to have_http_status(:redirect)
+ expect(response).to redirect_to(page)
+ end
+ end
+ end
+
+ describe '#reorder' do
+ let(:action_path) { reorder_page_index_path }
+ let(:params) { { page_id: page.id, direction: 'up' } }
+
+ let(:subject) { post action_path, params: params }
+
+ it 'redirects' do
+ login_as owner
+ subject
+
+ expect(response).to have_http_status(:redirect)
+ expect(response).to redirect_to(work_pages_tab_path(work_id: work.id))
+ end
+ end
+end
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index 579f7c6a6c..7254f1972e 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -20,6 +20,9 @@
# option on the command line or in ~/.rspec, .rspec or `.rspec-local`.
Dir[Rails.root.join("spec/support/**/*.rb")].each { |f| require f }
+# Require lib files
+Dir[Rails.root.join('lib/**/*.rb')].each { |f| require f }
+
# Checks for pending migrations before tests are run.
# If you are not using ActiveRecord, you can remove this line.
#ActiveRecord::Migration.maintain_test_schema!