Merge branch 'master' into ai-sci-3369-activity-for-edited-image-annotation

This commit is contained in:
Anton Ignatov 2019-06-20 09:43:53 +02:00
commit df344f4d03
19 changed files with 117 additions and 75 deletions

View file

@ -452,16 +452,21 @@ function initRecentProtocols() {
// We use here ajax:success, because we want to check any change on this page
$(document).on('ajax:success', () => {
var steps = $('.step');
var protocolDescription = $('#protocol_description_view').html();
if (steps.length === 0 && protocolDescription.length === 0) {
recentProtocolContainer.css('display', '');
} else {
recentProtocolContainer.css('display', 'none');
}
updateRecentProtocolsStatus();
});
}
function updateRecentProtocolsStatus() {
var recentProtocolContainer = $('.my-module-recent-protocols');
var steps = $('.step');
var protocolDescription = $('#protocol_description_view').html();
if (steps.length === 0 && protocolDescription.length === 0) {
recentProtocolContainer.css('display', '');
} else {
recentProtocolContainer.css('display', 'none');
}
}
/**
* Initializes page
*/

View file

@ -504,10 +504,9 @@
$('#new-step-main-tab a')
.on('shown.bs.tab', function() {
$('#step_name').focus();
TinyMCE.init('#step_description_textarea');
}).on('hidden.bs.tab', function() {
tinyMCE.editors.step_description_textarea.remove();
});
TinyMCE.init('#step_description_textarea');
})
TinyMCE.init('#step_description_textarea');
});
@ -538,7 +537,7 @@
var nameValid = textValidator(ev, $nameInput, 1,
<%= Constants::NAME_MAX_LENGTH %>);
var $descrTextarea = $form.find("#step_description_textarea");
var $tinyMCEInput = TinyMCE.getContent();
var $tinyMCEInput = tinyMCE.editors.step_description_textarea.getContent();
var descriptionValid = textValidator(ev, $descrTextarea, 0,
<%= Constants::RICH_TEXT_MAX_LENGTH %>, false, $tinyMCEInput);
var tableNamesValidArray = [];
@ -579,7 +578,7 @@
animateSpinner(null, true);
var data = DragNDropSteps.appendFilesToForm(ev);
data.append('step[description]', TinyMCE.getContent());
data.append('step[description]', $tinyMCEInput);
$.ajax({
url: $form.attr('action'),
method: 'POST',
@ -614,6 +613,7 @@
FilePreviewModal.init();
$.initTooltips();
if (typeof refreshProtocolStatusBar === 'function') refreshProtocolStatusBar();
if (typeof updateRecentProtocolsStatus === 'function') updateRecentProtocolsStatus();
},
error: function(xhr) {
if (xhr.responseJSON['assets.file']) {

View file

@ -45,7 +45,7 @@ function initializeHandsonTable(el) {
formulas: true
});
el.handsontable("getInstance").loadData(data);
el.handsontable("getInstance").sort(3, order);
el.handsontable('getInstance').getPlugin('columnSorting').sort(3, order);
// "Hack" to disable user sorting rows by clicking on
// header elements

View file

@ -85,6 +85,7 @@ function initInlineEditing(title) {
if (inputString.disabled) {
saveAllEditFields();
editBlock.dataset.editMode = 1;
$editBlock.closest('.inline_scroll_block').scrollTop(editBlock.offsetTop);
inputString.disabled = false;
$inputString.removeClass('hidden');
$editBlock.find('.view-mode').addClass('hidden');

View file

@ -76,6 +76,7 @@ var Comments = (function() {
$el.find('#message').val('');
$el.find('.new-comment-button').removeClass('show');
newButton.disable = false;
$el.find('textarea').focus().blur();
})
.error((error) => {
errorField.html(error.responseJSON.errors.message);

View file

@ -43,3 +43,22 @@
.mce-top-part {
z-index: 5;
}
.mce-widget.mce-btn[aria-label="Restore last draft"] {
background: $brand-primary;
border-radius: 4px;
transition: $md-transaction;
i {
color: $color-white;
transition: $md-transaction;
}
&.mce-disabled {
background: transparent;
i {
color: inherit;
}
}
}

View file

@ -144,6 +144,21 @@
}
}
// Looks like PDF has some specail CSS rules, here is some hack
&.report {
display: block;
float: left;
width: 100%;
.avatar-placehodler {
float: left;
}
.content-placeholder {
float: left;
}
}
&[data-edit-mode="0"]:hover,
&[data-edit-mode="1"] {
.comment-right {
@ -224,13 +239,16 @@
.new-comment-button {
cursor: pointer;
font-size: 18px;
font-size: 14px;
line-height: 18px;
margin: 8px;
margin: 4px;
padding: 4px;
position: absolute;
right: -36px;
text-align: center;
top: 0;
transition: $md-transaction;
width: 26px;
&.show {
right: 0;

View file

@ -5,8 +5,11 @@
border: solid 1px;
border-color: $color-white;
border-radius: 3px;
float: left;
margin-bottom: 10px;
min-height: 100px;
padding: 3px;
width: 100%;
&:hover {
border-color: $color-gainsboro;

View file

@ -196,16 +196,7 @@ module ApplicationHelper
# No more dirty hack
def user_avatar_absolute_url(user, style)
begin
unless missing_avatar(user, style)
image = if user.avatar.options[:storage].to_sym == :s3
URI.parse(user.avatar.url(style)).open.to_a.join
else
File.open(user.avatar.path(style)).to_a.join
end
encoded_data = Base64.strict_encode64(image)
avatar_base64 = "data:#{user.avatar_content_type};base64,#{encoded_data}"
return avatar_base64
end
return user.avatar_base64(style) unless missing_avatar(user, style)
rescue StandardError => e
Rails.logger.error e.message
end

View file

@ -97,21 +97,8 @@ module ReportsHelper
end
# "Hack" to omit file preview URL because of WKHTML issues
def report_image_asset_url(asset, type = :asset, klass = nil)
prefix = ''
if ENV['PAPERCLIP_STORAGE'].present? &&
ENV['MAIL_SERVER_URL'].present? &&
ENV['PAPERCLIP_STORAGE'] == 'filesystem'
prefix = ENV['MAIL_SERVER_URL']
end
if !prefix.empty? &&
!prefix.include?('http://') &&
!prefix.include?('https://')
prefix = "http://#{prefix}"
end
size = type == :tiny_mce_asset ? :large : :medium
url = prefix + asset.url(size, timeout: Constants::URL_LONG_EXPIRE_TIME)
image_tag(url, class: klass)
def report_image_asset_url(asset, _type = :asset, klass = nil)
image_tag(asset.generate_base64(:medium), class: klass)
end
# "Hack" to load Glyphicons css directly from the CDN

View file

@ -493,6 +493,16 @@ class Asset < ApplicationRecord
!locked? && %r{^image/#{Regexp.union(Constants::WHITELISTED_IMAGE_TYPES_EDITABLE)}} =~ file.content_type
end
def generate_base64(style)
image = if file.options[:storage].to_sym == :s3
URI.parse(url(style)).open.to_a.join
else
File.open(file.path(style)).to_a.join
end
encoded_data = Base64.strict_encode64(image)
"data:#{file_content_type};base64,#{encoded_data}"
end
protected
# Checks if attachments is an image (in post processing imagemagick will

View file

@ -107,7 +107,7 @@ class TinyMceAsset < ApplicationRecord
asset.destroy if asset && !asset.saved
end
def self.update_old_tinymce(description, obj = nil)
def self.update_old_tinymce(description, obj = nil, import = false)
return description unless description
description.scan(/\[~tiny_mce_id:(\w+)\]/).flatten.each do |token|
@ -115,7 +115,8 @@ class TinyMceAsset < ApplicationRecord
new_format = "<img src=\"\" class=\"img-responsive\" data-mce-token=\"#{Base62.encode(token.to_i)}\"/>"
asset = find_by_id(token)
unless asset
# impor flag only for import from file cases, because we don't have image in DB
unless asset || import
# remove tag if asset deleted
description.sub!(old_format, '')
next

View file

@ -559,6 +559,22 @@ class User < ApplicationRecord
.map { |i| { name: escape_input(i[:full_name]), id: i[:id] } }
end
def avatar_base64(style)
unless avatar.present?
missing_link = File.open("#{Rails.root}/app/assets/images/#{style}/missing.png").to_a.join
return "data:image/png;base64,#{Base64.strict_encode64(missing_link)}"
end
avatar_uri = if avatar.options[:storage].to_sym == :s3
URI.parse(avatar.url(style)).open.to_a.join
else
File.open(avatar.path(style)).to_a.join
end
encoded_data = Base64.strict_encode64(avatar_uri)
"data:#{avatar_content_type};base64,#{encoded_data}"
end
protected
def confirmation_required?

View file

@ -145,7 +145,7 @@ module ProtocolsImporter
def populate_rte(object_json, object, team)
return populate_rte_legacy(object_json) unless object_json['descriptionAssets']
description = TinyMceAsset.update_old_tinymce(object_json['description'])
description = TinyMceAsset.update_old_tinymce(object_json['description'], nil, true)
object_json['descriptionAssets'].values.each do |tiny_mce_img_json|
tiny_mce_img = TinyMceAsset.new(
object: object,

View file

@ -18,7 +18,9 @@
<%= render partial: "my_modules/protocols/protocol_status_bar.html.erb" %>
</div>
<%= render partial: "my_modules/protocols/protocol_buttons.html.erb" %>
<%= render partial: "my_modules/recent_protocol_dropdown.html.erb", locals: {protocol: @my_module.protocol}%>
<% if can_manage_protocol_in_module?(@protocol) %>
<%= render partial: "my_modules/recent_protocol_dropdown.html.erb", locals: {protocol: @my_module.protocol}%>
<% end %>
</div>
<div class="row">

View file

@ -18,22 +18,13 @@
</div>
<div class="report-element-body">
<div class="row">
<div class="col-xs-12 comments-container">
<div class="col-xs-12 comments-container simple">
<% if comments.count == 0 %>
<em><%=t "projects.reports.elements.result_comments.no_comments" %></em>
<% else %>
<ul class="no-style comments-list">
<ul class="no-style content-comments">
<% comments.each do |comment| %>
<% comment_ts = comment.created_at %>
<li class="comment" data-ts="<%= comment_ts.to_i %>">
<span class="comment-prefix">
<em><%=t "projects.reports.elements.result_comments.comment_prefix", user: comment.user.full_name, date: l(comment_ts, format: :full_date), time: l(comment_ts, format: :time) %></em>
</span>
<span class="comment-message">
&nbsp;
<%= custom_auto_link(comment.message, team: current_team) %>
</span>
</li>
<%= render partial: 'shared/comments/item.html.erb', locals: { comment: comment, readonly: true, report: true } %>
<% end %>
</ul>
<% end %>

View file

@ -18,22 +18,13 @@
</div>
<div class="report-element-body">
<div class="row">
<div class="col-xs-12 comments-container">
<div class="col-xs-12 comments-container simple">
<% if comments.count == 0 %>
<em><%=t "projects.reports.elements.step_comments.no_comments" %></em>
<% else %>
<ul class="no-style comments-list">
<ul class="no-style content-comments">
<% comments.each do |comment| %>
<% comment_ts = comment.created_at %>
<li class="comment" data-ts="<%= comment_ts.to_i %>">
<span class="comment-prefix">
<em><%=t "projects.reports.elements.step_comments.comment_prefix", user: comment.user.full_name, date: l(comment_ts, format: :full_date), time: l(comment_ts, format: :time) %></em>
</span>
<span class="comment-message">
&nbsp;
<%= custom_auto_link(comment.message, team: current_team) %>
</span>
</li>
<%= render partial: 'shared/comments/item.html.erb', locals: { comment: comment, readonly: true, report: true } %>`
<% end %>
</ul>
<% end %>

View file

@ -1,6 +1,6 @@
<div class="comments-container" data-object-id = <%= object.id %>>
<% per_page = Constants::COMMENTS_SEARCH_LIMIT %>
<div class="content-comments">
<div class="content-comments inline_scroll_block">
<% if comments.size == per_page %>
<div class="comment-more text-center">
<a class="btn btn-default btn-more-comments-new"

View file

@ -1,6 +1,8 @@
<% user_comment = comment.user == current_user %>
<% report = false unless defined?(report) %>
<% readonly = false unless defined?(readonly) %>
<% edit_mode = (comment.user == current_user && !readonly) %>
<div
class="comment-container <%= user_comment ? 'comment-editable-field' : '' %>"
class="comment-container <%= edit_mode ? 'comment-editable-field' : '' %> <%= report ? 'report' : '' %>"
data-field-to-update="message"
data-params-group="comment"
data-path-to-update="<%= comment_action_url(comment) %>"
@ -10,15 +12,19 @@
error="false"
>
<div class="avatar-placehodler">
<span class='global-avatar-container'>
<%= image_tag avatar_path(comment.user, :icon_small), class: 'avatar' %>
<span class='global-avatar-container'>
<% if report %>
<%= image_tag comment.user.avatar_base64(:icon_small), class: 'avatar' %>
<% else %>
<%= image_tag avatar_path(comment.user, :icon_small), class: 'avatar' %>
<% end %>
</span>
</div>
<div class="content-placeholder">
<div class="comment-name"><%= comment.user.full_name %></div>
<div class="comment-right">
<div class="comment-datetime"><%= l(comment.created_at, format: :full) %></div>
<% if user_comment %>
<% if edit_mode %>
<div class="comment-actions">
<div class="edit-buttons">
<span class="save-button"><i class="fas fa-save"></i><%= t('general.save') %></span>
@ -39,7 +45,7 @@
</div>
<div class="comment-message">
<div class="view-mode"><%= custom_auto_link(comment.message, team: current_team, simple_format: true).html_safe %></div>
<% if user_comment %>
<% if edit_mode %>
<%= text_area_tag 'message', comment.message, disabled: true, class: 'smart-text-area hidden' %>
<% end %>
</div>