mirror of
https://github.com/scinote-eln/scinote-web.git
synced 2024-12-25 01:03:18 +08:00
Add rich text editor to task and protocol description [SCI-3062][SCI-3071]
This commit is contained in:
parent
645930b8d7
commit
a822227383
17 changed files with 356 additions and 141 deletions
2
Gemfile
2
Gemfile
|
@ -90,7 +90,7 @@ gem 'rufus-scheduler', '~> 3.5'
|
|||
gem 'discard', '~> 1.0'
|
||||
|
||||
gem 'ruby-graphviz', '~> 1.2' # Graphviz for rails
|
||||
gem 'tinymce-rails', '~> 4.7.13' # Rich text editor - SEE BELOW
|
||||
gem 'tinymce-rails', '~> 4.9.3' # Rich text editor - SEE BELOW
|
||||
# Any time you update tinymce-rails Gem, also update the cache_suffix parameter
|
||||
# in sitewide/tiny_mce.js - to prevent browsers from loading old, cached .js
|
||||
# TinyMCE files which might cause errors
|
||||
|
|
|
@ -526,7 +526,7 @@ GEM
|
|||
thread_safe (0.3.6)
|
||||
tilt (2.0.8)
|
||||
timecop (0.9.1)
|
||||
tinymce-rails (4.7.13)
|
||||
tinymce-rails (4.9.3)
|
||||
railties (>= 3.1.1)
|
||||
turbolinks (5.1.1)
|
||||
turbolinks-source (~> 5.1)
|
||||
|
@ -656,7 +656,7 @@ DEPENDENCIES
|
|||
spinjs-rails
|
||||
starscope
|
||||
timecop
|
||||
tinymce-rails (~> 4.7.13)
|
||||
tinymce-rails (~> 4.9.3)
|
||||
turbolinks (~> 5.1.1)
|
||||
tzinfo-data
|
||||
uglifier (>= 1.3.0)
|
||||
|
|
|
@ -266,8 +266,11 @@ var HelperModule = (function(){
|
|||
$('.modal').off().modal('hide');
|
||||
});
|
||||
|
||||
/* Fix .selectpicker (bootstrap-select) to work with Turbolinks 5.x */
|
||||
$(document).on('turbolinks:load', function() {
|
||||
/* Fix .selectpicker (bootstrap-select) to work with Turbolinks 5.x */
|
||||
$(window).trigger('load.bs.select.data-api');
|
||||
|
||||
/* Clean up TinyMCE */
|
||||
tinymce.remove();
|
||||
});
|
||||
})();
|
||||
|
|
|
@ -10,6 +10,8 @@ var selectedRow = null;
|
|||
*/
|
||||
function init() {
|
||||
bindEditDueDateAjax();
|
||||
initEditMyModuleDescription();
|
||||
initEditProtocolDescription();
|
||||
initEditDescription();
|
||||
initCopyToRepository();
|
||||
initLinkUpdate();
|
||||
|
@ -19,6 +21,18 @@ function init() {
|
|||
setupAssetsLoading();
|
||||
}
|
||||
|
||||
function initEditMyModuleDescription() {
|
||||
$('#my_module_description_textarea').on('click', function(){
|
||||
TinyMCE.init('#my_module_description_textarea');
|
||||
});
|
||||
}
|
||||
|
||||
function initEditProtocolDescription() {
|
||||
$('#protocol_description_textarea').on('click', function(){
|
||||
TinyMCE.init('#protocol_description_textarea');
|
||||
});
|
||||
}
|
||||
|
||||
// Initialize edit description modal window
|
||||
function initEditDescription() {
|
||||
var editDescriptionModal = $("#manage-module-description-modal");
|
||||
|
|
204
app/assets/javascripts/sitewide/tiny_mce.js
vendored
Normal file
204
app/assets/javascripts/sitewide/tiny_mce.js
vendored
Normal file
|
@ -0,0 +1,204 @@
|
|||
/* global _ hljs tinyMCE SmartAnnotation */
|
||||
|
||||
var TinyMCE = (function() {
|
||||
'use strict';
|
||||
|
||||
function initHighlightjs() {
|
||||
$('[class*=language]').each(function(i, block) {
|
||||
hljs.highlightBlock(block);
|
||||
});
|
||||
}
|
||||
|
||||
function initHighlightjsIframe(iframe) {
|
||||
$('[class*=language]', iframe).each(function(i, block) {
|
||||
hljs.highlightBlock(block);
|
||||
});
|
||||
}
|
||||
|
||||
// returns a public API for TinyMCE editor
|
||||
return Object.freeze({
|
||||
init: function(selector) {
|
||||
if (typeof tinyMCE !== 'undefined') {
|
||||
tinyMCE.init({
|
||||
cache_suffix: '?v=4.9.3', // This suffix should be changed any time library is updated
|
||||
selector: selector,
|
||||
menubar: 'file edit view insert format',
|
||||
toolbar: 'undo redo restoredraft | insert | styleselect | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link | forecolor backcolor | customimageuploader | codesample',
|
||||
plugins: 'autosave autoresize customimageuploader link advlist codesample autolink lists charmap hr anchor searchreplace wordcount visualblocks visualchars insertdatetime nonbreaking save directionality paste textcolor colorpicker textpattern',
|
||||
codesample_languages: [
|
||||
{ text: 'R', value: 'r' },
|
||||
{ text: 'MATLAB', value: 'matlab' },
|
||||
{ text: 'Python', value: 'python' },
|
||||
{ text: 'JSON', value: 'javascript' },
|
||||
{ text: 'HTML/XML', value: 'markup' },
|
||||
{ text: 'JavaScript', value: 'javascript' },
|
||||
{ text: 'CSS', value: 'css' },
|
||||
{ text: 'PHP', value: 'php' },
|
||||
{ text: 'Ruby', value: 'ruby' },
|
||||
{ text: 'Java', value: 'java' },
|
||||
{ text: 'C', value: 'c' },
|
||||
{ text: 'C#', value: 'csharp' },
|
||||
{ text: 'C++', value: 'cpp' }
|
||||
],
|
||||
browser_spellcheck: true,
|
||||
branding: false,
|
||||
fixed_toolbar_container: '#mytoolbar',
|
||||
autosave_interval: '15s',
|
||||
autosave_retention: '1440m',
|
||||
removed_menuitems: 'newdocument',
|
||||
object_resizing: false,
|
||||
elementpath: false,
|
||||
forced_root_block: false,
|
||||
default_link_target: '_blank',
|
||||
target_list: [
|
||||
{ title: 'New page', value: '_blank' },
|
||||
{ title: 'Same page', value: '_self' }
|
||||
],
|
||||
style_formats: [
|
||||
{
|
||||
title: 'Headers',
|
||||
items: [
|
||||
{ title: 'Header 1', format: 'h1' },
|
||||
{ title: 'Header 2', format: 'h2' },
|
||||
{ title: 'Header 3', format: 'h3' },
|
||||
{ title: 'Header 4', format: 'h4' },
|
||||
{ title: 'Header 5', format: 'h5' },
|
||||
{ title: 'Header 6', format: 'h6' }
|
||||
]
|
||||
},
|
||||
{
|
||||
title: 'Inline',
|
||||
items: [
|
||||
{ title: 'Bold', icon: 'bold', format: 'bold' },
|
||||
{ title: 'Italic', icon: 'italic', format: 'italic' },
|
||||
{ title: 'Underline', icon: 'underline', format: 'underline' },
|
||||
{ title: 'Strikethrough', icon: 'strikethrough', format: 'strikethrough' },
|
||||
{ title: 'Superscript', icon: 'superscript', format: 'superscript' },
|
||||
{ title: 'Subscript', icon: 'subscript', format: 'subscript' },
|
||||
{ title: 'Code', icon: 'code', format: 'code' }
|
||||
]
|
||||
},
|
||||
{
|
||||
title: 'Blocks',
|
||||
items: [
|
||||
{ title: 'Paragraph', format: 'p' },
|
||||
{ title: 'Blockquote', format: 'blockquote' }
|
||||
]
|
||||
},
|
||||
{
|
||||
title: 'Alignment',
|
||||
items: [
|
||||
{ title: 'Left', icon: 'alignleft', format: 'alignleft' },
|
||||
{ title: 'Center', icon: 'aligncenter', format: 'aligncenter' },
|
||||
{ title: 'Right', icon: 'alignright', format: 'alignright' },
|
||||
{ title: 'Justify', icon: 'alignjustify', format: 'alignjustify' }
|
||||
]
|
||||
}
|
||||
],
|
||||
init_instance_callback: function(editor) {
|
||||
SmartAnnotation.init($(editor.contentDocument.activeElement));
|
||||
initHighlightjsIframe($(this.iframeElement).contents());
|
||||
},
|
||||
setup: function(editor) {
|
||||
editor.on('keydown', function(e) {
|
||||
if (e.keyCode === 13 && $(editor.contentDocument.activeElement).atwho('isSelecting')) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
editor.on('NodeChange', function(e) {
|
||||
var node = e.element;
|
||||
setTimeout(function() {
|
||||
if ($(node).is('pre') && !editor.isHidden()) {
|
||||
initHighlightjsIframe($(editor.iframeElement).contents());
|
||||
}
|
||||
}, 200);
|
||||
});
|
||||
|
||||
editor.on('init', function() {
|
||||
var editorForm = $(editor.getContainer()).closest('form');
|
||||
var menuBar = editorForm.find('.mce-menubar.mce-toolbar.mce-first .mce-flow-layout');
|
||||
|
||||
// Init saved status label
|
||||
if (editor.getContent() !== '') {
|
||||
editorForm.find('.tinymce-status-badge').removeClass('hidden');
|
||||
}
|
||||
|
||||
// Init Save button
|
||||
editorForm
|
||||
.find('.tinymce-save-button')
|
||||
.clone()
|
||||
.appendTo(menuBar)
|
||||
.on('click', function(event) {
|
||||
event.preventDefault();
|
||||
editorForm.clearFormErrors();
|
||||
editor.setProgressState(1);
|
||||
editor.save();
|
||||
editorForm.submit();
|
||||
});
|
||||
|
||||
// After save action
|
||||
editorForm
|
||||
.on('ajax:success', function() {
|
||||
editor.save();
|
||||
editor.setProgressState(0);
|
||||
editorForm.find('.tinymce-status-badge').removeClass('hidden');
|
||||
$(editor.getContainer())
|
||||
.find('.tinymce-save-button').addClass('hidden');
|
||||
}).on('ajax:error', function(ev, data) {
|
||||
var model = editor.getElement().dataset.objectType;
|
||||
$(this).renderFormErrors(model, data.responseJSON);
|
||||
editor.setProgressState(0);
|
||||
});
|
||||
|
||||
// Init Cancel button
|
||||
editorForm
|
||||
.find('.tinymce-cancel-button')
|
||||
.clone()
|
||||
.appendTo(menuBar)
|
||||
.on('click', function(event) {
|
||||
event.preventDefault();
|
||||
if (editor.isDirty()) {
|
||||
editor.setContent($(selector).val());
|
||||
}
|
||||
editor.remove();
|
||||
})
|
||||
.removeClass('hidden');
|
||||
});
|
||||
|
||||
editor.on('Dirty', function() {
|
||||
var editorForm = $(editor.getContainer()).closest('form');
|
||||
editorForm.find('.tinymce-status-badge').addClass('hidden');
|
||||
$(editor.getContainer())
|
||||
.find('.tinymce-save-button').removeClass('hidden');
|
||||
});
|
||||
|
||||
editor.on('remove', function() {
|
||||
var menuBar = $(editor.getContainer()).find('.mce-menubar.mce-toolbar.mce-first .mce-flow-layout');
|
||||
menuBar.find('.tinymce-save-button').remove();
|
||||
menuBar.find('.tinymce-cancel-button').remove();
|
||||
});
|
||||
},
|
||||
codesample_content_css: $(selector).data('highlightjs-path')
|
||||
});
|
||||
}
|
||||
},
|
||||
destroyAll: function() {
|
||||
_.each(tinyMCE.editors, function(editor) {
|
||||
if (editor) {
|
||||
editor.destroy();
|
||||
initHighlightjs();
|
||||
}
|
||||
});
|
||||
},
|
||||
refresh: function() {
|
||||
this.destroyAll();
|
||||
this.init();
|
||||
},
|
||||
getContent: function() {
|
||||
return tinyMCE.editors[0].getContent();
|
||||
},
|
||||
highlight: initHighlightjs
|
||||
});
|
||||
}());
|
|
@ -1,108 +0,0 @@
|
|||
var TinyMCE = (function() {
|
||||
'use strict';
|
||||
|
||||
function initHighlightjs() {
|
||||
$('[class*=language]').each(function(i, block) {
|
||||
hljs.highlightBlock(block);
|
||||
});
|
||||
}
|
||||
|
||||
function initHighlightjsIframe(iframe) {
|
||||
$('[class*=language]', iframe).each(function(i, block) {
|
||||
hljs.highlightBlock(block);
|
||||
});
|
||||
}
|
||||
|
||||
// returns a public API for TinyMCE editor
|
||||
return Object.freeze({
|
||||
init : function() {
|
||||
if (typeof tinyMCE != 'undefined') {
|
||||
tinyMCE.init({
|
||||
cache_suffix: '?v=4.7.13', // This suffix should be changed any time library is updated
|
||||
selector: 'textarea.tinymce',
|
||||
toolbar: ["undo redo | insert | styleselect | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link | forecolor backcolor | customimageuploader | codesample"],
|
||||
plugins: "autoresize,customimageuploader,link,advlist,codesample,autolink,lists,charmap,hr,anchor,searchreplace,wordcount,visualblocks,visualchars,insertdatetime,nonbreaking,save,contextmenu,directionality,paste,textcolor,colorpicker,textpattern",
|
||||
codesample_languages: [{"text":"R","value":"r"},{"text":"MATLAB","value":"matlab"},{"text":"Python","value":"python"},{"text":"JSON","value":"javascript"},{"text":"HTML/XML","value":"markup"},{"text":"JavaScript","value":"javascript"},{"text":"CSS","value":"css"},{"text":"PHP","value":"php"},{"text":"Ruby","value":"ruby"},{"text":"Java","value":"java"},{"text":"C","value":"c"},{"text":"C#","value":"csharp"},{"text":"C++","value":"cpp"}],
|
||||
removed_menuitems: 'newdocument',
|
||||
object_resizing: false,
|
||||
elementpath: false,
|
||||
forced_root_block: false,
|
||||
default_link_target: '_blank',
|
||||
target_list: [
|
||||
{title: 'New page', value: '_blank'},
|
||||
{title: 'Same page', value: '_self'}
|
||||
],
|
||||
style_formats: [
|
||||
{title: 'Headers', items: [
|
||||
{title: 'Header 1', format: 'h1'},
|
||||
{title: 'Header 2', format: 'h2'},
|
||||
{title: 'Header 3', format: 'h3'},
|
||||
{title: 'Header 4', format: 'h4'},
|
||||
{title: 'Header 5', format: 'h5'},
|
||||
{title: 'Header 6', format: 'h6'}
|
||||
]},
|
||||
{title: 'Inline', items: [
|
||||
{title: 'Bold', icon: 'bold', format: 'bold'},
|
||||
{title: 'Italic', icon: 'italic', format: 'italic'},
|
||||
{title: 'Underline', icon: 'underline', format: 'underline'},
|
||||
{title: 'Strikethrough', icon: 'strikethrough', format: 'strikethrough'},
|
||||
{title: 'Superscript', icon: 'superscript', format: 'superscript'},
|
||||
{title: 'Subscript', icon: 'subscript', format: 'subscript'},
|
||||
{title: 'Code', icon: 'code', format: 'code'}
|
||||
]},
|
||||
{title: 'Blocks', items: [
|
||||
{title: 'Paragraph', format: 'p'},
|
||||
{title: 'Blockquote', format: 'blockquote'}
|
||||
]},
|
||||
{title: 'Alignment', items: [
|
||||
{title: 'Left', icon: 'alignleft', format: 'alignleft'},
|
||||
{title: 'Center', icon: 'aligncenter', format: 'aligncenter'},
|
||||
{title: 'Right', icon: 'alignright', format: 'alignright'},
|
||||
{title: 'Justify', icon: 'alignjustify', format: 'alignjustify'}
|
||||
]}
|
||||
],
|
||||
init_instance_callback: function(editor) {
|
||||
SmartAnnotation.init($(editor.contentDocument.activeElement));
|
||||
initHighlightjsIframe($(this.iframeElement).contents());
|
||||
},
|
||||
setup: function(editor) {
|
||||
editor.on('keydown', function(e) {
|
||||
if(e.keyCode == 13 && $(editor.contentDocument.activeElement).atwho('isSelecting')) {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
editor.on('NodeChange', function(e) {
|
||||
var node = e.element;
|
||||
var editor = this;
|
||||
setTimeout(function() {
|
||||
if($(node).is('pre') && !editor.isHidden()){
|
||||
initHighlightjsIframe($(editor.iframeElement).contents());
|
||||
}
|
||||
}, 200);
|
||||
|
||||
});
|
||||
},
|
||||
codesample_content_css: '<%= asset_path('highlightjs-github-theme') %>'
|
||||
});
|
||||
}
|
||||
},
|
||||
destroyAll: function() {
|
||||
_.each(tinymce.editors, function(editor) {
|
||||
if(editor) {
|
||||
editor.destroy();
|
||||
initHighlightjs();
|
||||
}
|
||||
});
|
||||
},
|
||||
refresh: function() {
|
||||
this.destroyAll();
|
||||
this.init();
|
||||
},
|
||||
getContent: function() {
|
||||
return tinymce.editors[0].getContent();
|
||||
},
|
||||
highlight: initHighlightjs
|
||||
});
|
||||
|
||||
})();
|
|
@ -2,7 +2,20 @@
|
|||
// They will automatically be included in application.css.
|
||||
// You can use Sass (SCSS) here: http://sass-lang.com/
|
||||
|
||||
@import 'constants';
|
||||
@import "constants";
|
||||
|
||||
.tinymce-textarea {
|
||||
border-color: $color-white;
|
||||
|
||||
&:hover {
|
||||
border-color: $color-alto;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.protocol-description-content {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
// Protocols index page
|
||||
.task-due-date,
|
||||
|
|
21
app/assets/stylesheets/tiny_mce.scss
Normal file
21
app/assets/stylesheets/tiny_mce.scss
Normal file
|
@ -0,0 +1,21 @@
|
|||
@import "constants";
|
||||
|
||||
.tinymce-save-button,
|
||||
.tinymce-cancel-button {
|
||||
cursor: pointer;
|
||||
|
||||
.fas {
|
||||
font-family: "Font Awesome 5 Free";
|
||||
font-weight: 900;
|
||||
margin-top: 3px;
|
||||
}
|
||||
}
|
||||
|
||||
.tinymce-status-badge {
|
||||
color: $color-silver-chalice;
|
||||
margin-top: -20px;
|
||||
}
|
||||
|
||||
.tinymce-placeholder-text {
|
||||
color: $color-silver-chalice;
|
||||
}
|
|
@ -15,7 +15,7 @@ class MyModulesController < ApplicationController
|
|||
assign_repository_records unassign_repository_records
|
||||
unassign_repository_records_modal
|
||||
assign_repository_records_modal
|
||||
repositories_dropdown)
|
||||
repositories_dropdown update_protocol_description)
|
||||
before_action :load_vars_nested, only: %i(new create)
|
||||
before_action :load_repository, only: %i(assign_repository_records
|
||||
unassign_repository_records
|
||||
|
@ -25,7 +25,8 @@ class MyModulesController < ApplicationController
|
|||
before_action :load_projects_tree, only: %i(protocols results activities
|
||||
samples repository archive)
|
||||
before_action :check_manage_permissions_archive, only: %i(update destroy)
|
||||
before_action :check_manage_permissions, only: %i(description due_date)
|
||||
before_action :check_manage_permissions,
|
||||
only: %i(description due_date update_protocol_description)
|
||||
before_action :check_view_permissions, only:
|
||||
%i(show activities activities_tab protocols results samples samples_index
|
||||
archive repositories_dropdown)
|
||||
|
@ -254,6 +255,20 @@ class MyModulesController < ApplicationController
|
|||
end
|
||||
end
|
||||
|
||||
def update_protocol_description
|
||||
protocol = @my_module.protocol
|
||||
return render_404 unless protocol
|
||||
respond_to do |format|
|
||||
format.json do
|
||||
if protocol.update(description: params.require(:protocol)[:description])
|
||||
render json: { data: protocol }
|
||||
else
|
||||
render json: protocol.errors, status: :unprocessable_entity
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def protocols
|
||||
@protocol = @my_module.protocol
|
||||
current_team_switch(@protocol.team)
|
||||
|
|
|
@ -270,7 +270,7 @@ module BootstrapFormHelper
|
|||
|
||||
# Returns <textarea> helper tag for tinyMCE editor
|
||||
def tiny_mce_editor(name, options = {})
|
||||
options.merge!(class: 'tinymce', cols: 120, rows: 15)
|
||||
options.merge!(class: 'tinymce-textarea', cols: 120, rows: 10)
|
||||
text_area(name, options)
|
||||
end
|
||||
end
|
||||
|
|
12
app/views/my_modules/_description_form.html.erb
Normal file
12
app/views/my_modules/_description_form.html.erb
Normal file
|
@ -0,0 +1,12 @@
|
|||
<%= bootstrap_form_for @my_module, url: my_module_path(@my_module, format: :json), remote: :true do |f| %>
|
||||
<%= render partial: 'shared/tiny_mce_extra_buttons.html.erb' %>
|
||||
<%= f.tiny_mce_editor(:description,
|
||||
id: :my_module_description_textarea,
|
||||
hide_label: true,
|
||||
value: sanitize_input(@my_module.description),
|
||||
placeholder: t('my_modules.module_header.empty_description_edit_label'),
|
||||
data: {
|
||||
object_type: 'my_module',
|
||||
object_id: @my_module.id,
|
||||
highlightjs_path: asset_path('highlightjs-github-theme') } ) %>
|
||||
<% end %>
|
|
@ -63,32 +63,20 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div class="badge-icon">
|
||||
<% if can_manage_module?(@my_module) %>
|
||||
<%= link_to description_my_module_path(@my_module, format: :json), remote: true, class: "description-link", style: "color: inherit" do %>
|
||||
<span class="fas fa-info-circle"></span>
|
||||
<% end %>
|
||||
<% else %>
|
||||
<span class="fas fa-info-circle"></span>
|
||||
<% end %>
|
||||
</div>
|
||||
<div class="well well-sm">
|
||||
<% if can_manage_module?(@my_module) %>
|
||||
<%= link_to description_my_module_path(@my_module, format: :json), remote: true, class: "description-label description-link description-refresh", style: "color: inherit" do %>
|
||||
<% if @my_module.description.present? and not @my_module.description.empty? %>
|
||||
<%= @my_module.description %>
|
||||
<% else %>
|
||||
<em><%=t "my_modules.module_header.no_description" %></em>
|
||||
<% end %>
|
||||
<% end %>
|
||||
<% else %>
|
||||
<% if @my_module.description.present? and not @my_module.description.empty? %>
|
||||
<%= @my_module.description %>
|
||||
<% else %>
|
||||
<em><%=t "my_modules.module_header.no_description" %></em>
|
||||
<% end %>
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
<h4>
|
||||
<%= t('my_modules.module_header.description_label') %>
|
||||
</h4>
|
||||
<div class="my-module-description-content">
|
||||
<% if can_manage_module?(@my_module) %>
|
||||
<%= render partial: "description_form" %>
|
||||
<% elsif @my_module.description.present? %>
|
||||
<%= sanitize_input(@my_module.description) %>
|
||||
<% else %>
|
||||
<%= t('my_modules.module_header.no_description') %>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -16,6 +16,10 @@
|
|||
<div class="content-pane">
|
||||
<%= render partial: "module_header" %>
|
||||
|
||||
<h2>
|
||||
<%= t('Protocol') %>
|
||||
</h2>
|
||||
|
||||
<div>
|
||||
<div data-role="protocol-status-bar" style="display: inline;">
|
||||
<%= render partial: "my_modules/protocols/protocol_status_bar.html.erb" %>
|
||||
|
@ -24,6 +28,20 @@
|
|||
<%= render partial: "my_modules/state_buttons.html.erb" %>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
<div class="protocol-description-content">
|
||||
<% if can_manage_module?(@my_module) %>
|
||||
<%= render partial: "my_modules/protocols/protocol_description_form" %>
|
||||
<% elsif @my_module.protocol.description.present? %>
|
||||
<%= sanitize_input(@my_module.protocol.description) %>
|
||||
<% else %>
|
||||
<%= t('my_modules.protocols.protocol_status_bar.no_description') %>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div data-role="steps-container">
|
||||
<%= render partial: "protocols/steps.html.erb" %>
|
||||
</div>
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
<%= bootstrap_form_for @my_module.protocol, url: update_protocol_description_my_module_path(@my_module, format: :json), remote: :true do |f| %>
|
||||
<%= render partial: 'shared/tiny_mce_extra_buttons.html.erb' %>
|
||||
<%= f.tiny_mce_editor(:description,
|
||||
id: :protocol_description_textarea,
|
||||
hide_label: true,
|
||||
value: sanitize_input(@my_module.protocol.description),
|
||||
placeholder: t('my_modules.protocols.protocol_status_bar.empty_description_edit_label'),
|
||||
data: {
|
||||
object_type: 'protocol',
|
||||
object_id: @my_module.protocol.id,
|
||||
highlightjs_path: asset_path('highlightjs-github-theme') } ) %>
|
||||
<% end %>
|
16
app/views/shared/_tiny_mce_extra_buttons.html.erb
Normal file
16
app/views/shared/_tiny_mce_extra_buttons.html.erb
Normal file
|
@ -0,0 +1,16 @@
|
|||
<div class="hidden tinymce-cancel-button mce-widget mce-btn mce-menubtn mce-flow-layout-item mce-btn-has-text pull-right" tabindex="-1">
|
||||
<button type="button" tabindex="-1">
|
||||
<span class="fas fa-times"></span>
|
||||
<span class="mce-txt"><%= t('general.cancel') %></span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="hidden tinymce-save-button mce-widget mce-btn mce-menubtn mce-flow-layout-item mce-btn-has-text mce-last pull-right" tabindex="-1">
|
||||
<button type="button" tabindex="-1" >
|
||||
<span class="fas fa-check"></span>
|
||||
<span class="mce-txt"><%= t('general.save') %></span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="hidden tinymce-status-badge pull-right">
|
||||
<i class="fas fa-check-circle"></i>
|
||||
<span><%= t('tiny_mce.saved_label') %></span>
|
||||
</div>
|
|
@ -600,6 +600,8 @@ en:
|
|||
no_tags: "click here to add Task Tags (optional)"
|
||||
manage_tags: Manage tags
|
||||
no_description: "No description"
|
||||
description_label: "Description"
|
||||
empty_description_edit_label: "Click here to enter Task Description (optional)"
|
||||
protocols:
|
||||
head_title: "%{project} | %{module} | Protocols"
|
||||
protocol_status_bar:
|
||||
|
@ -611,6 +613,7 @@ en:
|
|||
added_by_tooltip: "Added at %{ts}"
|
||||
private_protocol_desc: "The parent protocol is private. Only its author can manage it."
|
||||
no_description: "no description"
|
||||
empty_description_edit_label: "Click here to enter Protocol Description (optional)"
|
||||
keywords: "Keywords"
|
||||
no_keywords: "no keywords"
|
||||
btns:
|
||||
|
@ -1971,6 +1974,7 @@ en:
|
|||
insert_btn: 'Insert'
|
||||
error_message: 'You must choose a file'
|
||||
server_not_respond: "Didn't get a response from the server"
|
||||
saved_label: "Saved"
|
||||
general:
|
||||
save: "Save"
|
||||
update: "Update"
|
||||
|
|
|
@ -363,6 +363,9 @@ Rails.application.routes.draw do
|
|||
get 'activities'
|
||||
get 'activities_tab' # Activities in tab view for single module
|
||||
get 'due_date'
|
||||
patch 'protocol_description',
|
||||
to: 'my_modules#update_protocol_description',
|
||||
as: 'update_protocol_description'
|
||||
get 'protocols' # Protocols view for single module
|
||||
get 'results' # Results view for single module
|
||||
# get 'samples' # Samples view for single module
|
||||
|
|
Loading…
Reference in a new issue