mirror of
https://github.com/scinote-eln/scinote-web.git
synced 2024-12-29 11:45:18 +08:00
Add print feature to protocols [SCI-6028] (#3700)
* Add print feature to protocols [SCI-6028] * Close tab after closing print dialog [SCI-6028] * CSS linter fixes [SCI-6028]
This commit is contained in:
parent
16b3ee3d94
commit
9937d1d913
12 changed files with 380 additions and 1 deletions
|
@ -45,6 +45,7 @@
|
|||
//= require activestorage
|
||||
//= require global_activities/side_pane
|
||||
//= require protocols/header
|
||||
//= require protocols/print
|
||||
//= require marvinjslauncher
|
||||
//= require jstree.min
|
||||
//= require_tree ./repositories/renderers
|
||||
|
@ -56,7 +57,6 @@
|
|||
//= require sidebar
|
||||
//= require turbolinks
|
||||
|
||||
|
||||
// Initialize links for submitting forms. This is useful for submitting
|
||||
// forms with clicking on links outside form in cases when other than
|
||||
// GET method is used.
|
||||
|
|
3
app/assets/javascripts/protocols/print.js
Normal file
3
app/assets/javascripts/protocols/print.js
Normal file
|
@ -0,0 +1,3 @@
|
|||
$(document).on('submit', '#print-protocol-form', function() {
|
||||
$('#print-protocol-modal').modal('hide');
|
||||
});
|
191
app/assets/stylesheets/print_protocol.scss
Normal file
191
app/assets/stylesheets/print_protocol.scss
Normal file
|
@ -0,0 +1,191 @@
|
|||
@import "shared_styles/constants/*";
|
||||
@import "constants";
|
||||
|
||||
@page {
|
||||
size: A4;
|
||||
margin: 8mm;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: Lato, "Open Sans", Arial, Helvetica, sans-serif;
|
||||
font-size: 16px;
|
||||
-webkit-print-color-adjust: exact;
|
||||
print-color-adjust: exact;
|
||||
}
|
||||
|
||||
.print-protocol-header {
|
||||
font-size: .8em;
|
||||
|
||||
img {
|
||||
height: .8em;
|
||||
}
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 1.5em;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 1.3em;
|
||||
|
||||
.fa-check-circle {
|
||||
color: $brand-success;
|
||||
font-size: 1.3em;
|
||||
}
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
hr {
|
||||
background-color: $color-alto;
|
||||
border-width: 0;
|
||||
height: 1px;
|
||||
}
|
||||
|
||||
.print-step {
|
||||
margin: 5em 0;
|
||||
}
|
||||
|
||||
.step-check-circle {
|
||||
border-radius: 50%;
|
||||
border: .15em solid $color-alto;
|
||||
color: $color-white;
|
||||
display: inline-block;
|
||||
height: 1.1em;
|
||||
text-align: center;
|
||||
vertical-align: text-bottom;
|
||||
width: 1.1em;
|
||||
|
||||
&.checked {
|
||||
background-color: $brand-success;
|
||||
border-color: $brand-success;
|
||||
}
|
||||
}
|
||||
|
||||
.print-checklist-item {
|
||||
margin-bottom: 1em;
|
||||
|
||||
span {
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
}
|
||||
}
|
||||
|
||||
.checklist-checkbox {
|
||||
border: .15em solid $color-alto;
|
||||
border-radius: .2em;
|
||||
display: inline-block;
|
||||
height: 1em;
|
||||
text-align: center;
|
||||
width: 1em;
|
||||
|
||||
&.checked {
|
||||
background-color: $brand-primary;
|
||||
border-color: $brand-primary;
|
||||
color: $color-white;
|
||||
font-size: 1em;
|
||||
}
|
||||
}
|
||||
|
||||
.print-table {
|
||||
border-collapse: collapse;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
|
||||
&,
|
||||
td,
|
||||
th {
|
||||
border: 1px solid $color-silver-chalice;
|
||||
}
|
||||
|
||||
th {
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
th,
|
||||
td:first-child {
|
||||
background: $color-concrete;
|
||||
}
|
||||
|
||||
td {
|
||||
padding: .15em .3em;
|
||||
}
|
||||
}
|
||||
|
||||
.print-asset {
|
||||
margin: 1em;
|
||||
|
||||
p {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
&.thumbnail {
|
||||
float: left;
|
||||
padding: 1em;
|
||||
}
|
||||
|
||||
&.thumbnail,
|
||||
&.list {
|
||||
border: 1px solid $color-silver-chalice;
|
||||
}
|
||||
|
||||
&.list {
|
||||
padding: .5em 1em;
|
||||
}
|
||||
|
||||
&.inline {
|
||||
margin: 5em 0;
|
||||
text-align: center;
|
||||
|
||||
img {
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.print-thumbnails {
|
||||
clear: both;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.print-asset-icon {
|
||||
display: inline-block;
|
||||
font-size: $font-size-h2;
|
||||
text-align: center;
|
||||
width: 24px;
|
||||
|
||||
.fa-file-pdf {
|
||||
color: $pdf-color;
|
||||
}
|
||||
|
||||
.fa-image {
|
||||
color: $brand-primary;
|
||||
}
|
||||
}
|
||||
|
||||
.print-comments {
|
||||
margin-bottom: 5em;
|
||||
}
|
||||
|
||||
.print-comment-container {
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
.print-comment-header {
|
||||
.user-avatar {
|
||||
float: left;
|
||||
margin-right: 1em;
|
||||
}
|
||||
|
||||
.user-name {
|
||||
color: $color-silver-chalice;
|
||||
}
|
||||
}
|
||||
|
||||
.print-comment-footer {
|
||||
color: $color-silver-chalice;
|
||||
font-size: .8em;
|
||||
text-align: right;
|
||||
}
|
|
@ -8,6 +8,7 @@
|
|||
display: inline-block;
|
||||
height: var(--sci-checkbox-size);
|
||||
position: relative;
|
||||
vertical-align: middle;
|
||||
width: var(--sci-checkbox-size);
|
||||
}
|
||||
|
||||
|
|
|
@ -11,6 +11,8 @@ class ProtocolsController < ApplicationController
|
|||
include TeamsHelper
|
||||
include CommentHelper
|
||||
|
||||
layout 'protocols/print', only: :print
|
||||
|
||||
before_action :check_create_permissions, only: %i(
|
||||
create_new_modal
|
||||
create
|
||||
|
@ -108,6 +110,11 @@ class ProtocolsController < ApplicationController
|
|||
end
|
||||
end
|
||||
|
||||
def print
|
||||
@protocol = Protocol.find(params[:id])
|
||||
render_403 && return unless @protocol.my_module.blank? || can_read_protocol_in_module?(@protocol)
|
||||
end
|
||||
|
||||
def linked_children
|
||||
respond_to do |format|
|
||||
format.json do
|
||||
|
|
14
app/views/layouts/protocols/print.html.erb
Normal file
14
app/views/layouts/protocols/print.html.erb
Normal file
|
@ -0,0 +1,14 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title><%= t("protocols.print.title") %></title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
|
||||
<%= stylesheet_link_tag 'print_protocol', media: 'print, screen' %>
|
||||
<body>
|
||||
<%= yield %>
|
||||
<script>
|
||||
window.print();
|
||||
window.onfocus=function(){ window.close(); }
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -121,6 +121,7 @@
|
|||
<span><%=t "protocols.steps.new_step" %></span>
|
||||
</a>
|
||||
<% end %>
|
||||
<%= render partial: "my_modules/protocols/print_protocol_button", locals: { protocol: @protocol } %>
|
||||
<%= render partial: "my_modules/protocols/protocol_options_dropdown" %>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
<a href="#" class="btn btn-default" data-toggle="modal" data-target="#print-protocol-modal">
|
||||
<span class="fas fa-print" aria-hidden="true"></span>
|
||||
<span><%=t "protocols.print.button" %></span>
|
||||
</a>
|
||||
|
||||
<div class="modal"
|
||||
id="print-protocol-modal"
|
||||
tabindex="-1"
|
||||
role="dialog"
|
||||
aria-labelledby="print-protocol-modal-label">
|
||||
<%= bootstrap_form_tag({ url: print_protocol_path(protocol), method: :get, html: { class: 'print-protocol-form', id: "print-protocol-form", target: '_blank' } }) do %>
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||
<h4 class="modal-title" id="print-protocol-modal-label"><%= t("protocols.print.modal.title") %></h5>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p><%= t("protocols.print.modal.content") %></p>
|
||||
<div class="sci-checkbox-container">
|
||||
<%= check_box_tag :include_comments, 1, true, { class: "sci-checkbox" } %>
|
||||
<span class="sci-checkbox-label"></span>
|
||||
</div>
|
||||
<small><%= t("protocols.print.modal.include_comments") %></small>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<div class="pull-right">
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal"><%=t "general.cancel" %></button>
|
||||
<input type="submit" value="<%= t("protocols.print.button") %>", class="btn btn-primary">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
115
app/views/protocols/print.html.erb
Normal file
115
app/views/protocols/print.html.erb
Normal file
|
@ -0,0 +1,115 @@
|
|||
<p class="print-protocol-header">
|
||||
<span><%= t('.header.printed_from') %></span>
|
||||
<span class="print-protocol-header__logo">
|
||||
<%= image_tag 'logo.png' %>
|
||||
</span>
|
||||
<span><%= t('.header.print_info', datetime: l(DateTime.current, format: :full), full_name: current_user.full_name) %></span>
|
||||
</p>
|
||||
|
||||
<h1><%= @protocol.name || @protocol.my_module.name %></h1>
|
||||
<div><%= @protocol.description.html_safe %></div>
|
||||
<% @protocol.steps.order(position: :asc).each do |step| %>
|
||||
<div class="print-step">
|
||||
<h2>
|
||||
<div class="step-check-circle <%= 'checked' if step.completed_on %>">
|
||||
<% if step.completed_on %>✓<% end %>
|
||||
</div>
|
||||
<%= step.position + 1 %>. <%= step.name %>
|
||||
</h2>
|
||||
<div><%= step.description.html_safe %></div>
|
||||
|
||||
<% step.checklists.each do |checklist| %>
|
||||
<div class="print-checklist">
|
||||
<h3><%= checklist.name %></h3>
|
||||
<% checklist.checklist_items.order(position: :asc).each do |checklist_item| %>
|
||||
<div class="print-checklist-item">
|
||||
<span class="checklist-checkbox <%= 'checked' if checklist_item.checked %>">
|
||||
<% if checklist_item.checked %>
|
||||
✓
|
||||
<% end %>
|
||||
</span>
|
||||
<span><%= checklist_item.text %></span>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<% step.tables.each do |table| %>
|
||||
<% table_data = JSON.parse(table.contents)["data"] %>
|
||||
<h3><%= table.name %></h3>
|
||||
<table class="print-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th></th>
|
||||
<% col = "A" %>
|
||||
<% table_data[0].length.times do %>
|
||||
<th><%= col %></th>
|
||||
<% col.succ! %>
|
||||
<% end %>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% table_data.each_with_index do |tr, row| %>
|
||||
<tr>
|
||||
<td><%= row + 1 %></td>
|
||||
<% tr.each do |td| %>
|
||||
<td><%= td %></td>
|
||||
<% end %>
|
||||
</tr>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
||||
<% end %>
|
||||
<% step.assets.where(view_mode: "inline").each do |asset| %>
|
||||
<div class="print-asset inline">
|
||||
<div class="print-asset-image">
|
||||
<%= image_tag asset.blob.url %>
|
||||
<p><%= asset.blob.filename %></p>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
<% step.assets.where(view_mode: "list").each do |asset| %>
|
||||
<div class="print-asset list">
|
||||
<span class="print-asset-icon"><%= file_extension_icon_html(asset) %></span>
|
||||
<span><%= asset.blob.filename %></span>
|
||||
</div>
|
||||
<% end %>
|
||||
<div class="print-thumbnails">
|
||||
<% step.assets.where(view_mode: "thumbnail").each do |asset| %>
|
||||
<div class="print-asset thumbnail">
|
||||
<div class="print-asset-image">
|
||||
<%= image_tag asset.blob.representation(resize_to_limit: Constants::MEDIUM_PIC_FORMAT).processed %>
|
||||
<p><%= asset.blob.filename %></p>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<% if params[:include_comments] && step.comments.present? %>
|
||||
<div class="print-comments">
|
||||
<h3><%= t('Comments') %>:</h3>
|
||||
<% step.step_comments.each do |comment| %>
|
||||
<div class="print-comment-container">
|
||||
<div class="print-comment-header">
|
||||
<%= image_tag avatar_path(comment.user, :icon_small), class: 'user-avatar' %>
|
||||
<div class="user-name">
|
||||
<%= comment.user.full_name %>
|
||||
</div>
|
||||
</div>
|
||||
<div class="print-comment-body">
|
||||
<div class="comment-message">
|
||||
<%= comment.message %>
|
||||
</div>
|
||||
<div class="print-comment-footer">
|
||||
<div class="print-comment-create-date">
|
||||
<%= I18n.l(comment.created_at, format: :full) %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
<hr>
|
||||
<% end %>
|
|
@ -69,6 +69,7 @@ Rails.application.config.assets.precompile += %w(datatables.css)
|
|||
Rails.application.config.assets.precompile += %w(my_modules.js)
|
||||
Rails.application.config.assets.precompile += %w(Sortable.min.js)
|
||||
Rails.application.config.assets.precompile += %w(reports_pdf.css)
|
||||
Rails.application.config.assets.precompile += %w(print_protocol.css)
|
||||
Rails.application.config.assets.precompile += %w(jszip.min.js)
|
||||
Rails.application.config.assets.precompile += %w(comments.js)
|
||||
Rails.application.config.assets.precompile += %w(projects/show.js)
|
||||
|
|
|
@ -2002,6 +2002,16 @@ en:
|
|||
unchangable_error_message: "Predefined roles can not be changed!"
|
||||
|
||||
protocols:
|
||||
print:
|
||||
title: "Print protocol"
|
||||
button: "Print"
|
||||
modal:
|
||||
title: "Print protocol"
|
||||
content: "Select what to include in the printed version of this protocol."
|
||||
include_comments: "Include comments when printing"
|
||||
header:
|
||||
printed_from: "Printed from"
|
||||
print_info: "on %{datetime} by %{full_name}"
|
||||
protocols_io_import:
|
||||
title_too_long: "... Text is too long so we had to cut it off."
|
||||
too_long: "... <span class='label label-warning'>Text is too long so we had to cut it off.</span>"
|
||||
|
|
|
@ -492,6 +492,7 @@ Rails.application.routes.draw do
|
|||
resources :protocols, only: [:index, :edit, :create] do
|
||||
resources :steps, only: [:new, :create]
|
||||
member do
|
||||
get 'print', to: 'protocols#print'
|
||||
get 'linked_children', to: 'protocols#linked_children'
|
||||
post 'linked_children_datatable',
|
||||
to: 'protocols#linked_children_datatable'
|
||||
|
|
Loading…
Reference in a new issue