From cc5d8550b12384f6d51c4a4ab603c87b9e9bb429 Mon Sep 17 00:00:00 2001 From: Oleksii Kriuchykhin Date: Fri, 30 Mar 2018 11:50:28 +0200 Subject: [PATCH] Refactor file preview modal [SCI-2217] --- app/assets/javascripts/assets.js | 27 +- .../javascripts/sitewide/file_preview.js | 58 + .../javascripts/sitewide/image_preview.js | 48 - app/assets/stylesheets/application.scss | 1 - app/assets/stylesheets/themes/scinote.scss | 36 +- app/controllers/assets_controller.rb | 52 +- .../protocol_linked_children_datatable.rb | 2 +- app/helpers/file_icons_helper.rb | 20 + app/helpers/wopi_helper.rb | 75 - app/javascript/packs/fontawesome.scss | 4 + app/javascript/packs/styles.scss | 2 - .../components/NotificationImage.jsx | 4 +- .../components/NotificationsDropdown.jsx | 2 +- .../Navigation/components/TeamSwitch.jsx | 2 +- .../src/components/Navigation/index.jsx | 2 +- app/javascript/src/components/Spinner.jsx | 2 +- .../SettingsPage/scenes/preferences/index.jsx | 2 +- app/views/layouts/application.html.erb | 1 + .../_result_user_generated.html.erb | 2 +- app/views/my_modules/protocols.html.erb | 2 +- app/views/my_modules/results.html.erb | 2 +- app/views/protocols/edit.html.erb | 2 +- app/views/protocols/index.html.erb | 2 +- .../_protocol_preview_modal_body.html.erb | 4 +- .../elements/_experiment_element.html.erb | 2 +- .../_my_module_repository_element.html.erb | 4 +- .../_repository_row_info_modal.html.erb | 2 +- app/views/results/_result_asset.html.erb | 34 - app/views/samples/_info_sample_modal.html.erb | 2 +- app/views/search/index.html.erb | 2 +- .../search/results/_repositories.html.erb | 2 +- app/views/shared/_asset_link.html.erb | 21 + app/views/shared/_file_preview_icon.html.erb | 4 + ....html.erb => _file_preview_modal.html.erb} | 11 +- .../shared/_file_wopi_controlls.html.erb | 16 + app/views/shared/_left_menu_bar.html.erb | 2 +- app/views/steps/_form_assets.html.erb | 41 +- app/views/steps/_step.html.erb | 45 +- app/views/steps/_wopi_controlls.html.erb | 24 - config/initializers/extends.rb | 4 + config/locales/en.yml | 2 +- config/routes.rb | 6 +- package-lock.json | 808 +- package.json | 2 +- yarn.lock | 7509 ----------------- 45 files changed, 1048 insertions(+), 7849 deletions(-) create mode 100644 app/assets/javascripts/sitewide/file_preview.js delete mode 100644 app/assets/javascripts/sitewide/image_preview.js delete mode 100644 app/helpers/wopi_helper.rb create mode 100644 app/javascript/packs/fontawesome.scss delete mode 100644 app/views/results/_result_asset.html.erb create mode 100644 app/views/shared/_asset_link.html.erb create mode 100644 app/views/shared/_file_preview_icon.html.erb rename app/views/shared/{_image_preview_modal.html.erb => _file_preview_modal.html.erb} (57%) create mode 100644 app/views/shared/_file_wopi_controlls.html.erb delete mode 100644 app/views/steps/_wopi_controlls.html.erb delete mode 100644 yarn.lock diff --git a/app/assets/javascripts/assets.js b/app/assets/javascripts/assets.js index 5d5d23eb1..3ff983bfb 100644 --- a/app/assets/javascripts/assets.js +++ b/app/assets/javascripts/assets.js @@ -25,29 +25,22 @@ function setupAssetsLoading() { $el.next().hide(); $el.html(""); - if (data.type === "image") { + if (data.type === 'image') { $el.html( - "" + - "

" + + "href='" + data['download-url'] + "' data-preview-url='" + + data['preview-url'] + "'>" + + "

" + data.filename + '

' ); - } else if (data.type === 'wopi') { - if (data['wopi-edit']) { - wopiBtns = data['wopi-file-name'] + - data['wopi-view'] + - data['wopi-edit']; - } else { - wopiBtns = data['wopi-file-name'] + - data['wopi-view']; - } - $el.html(wopiBtns); } else { $el.html( - "

" + - data.filename + "

" + "

" + + data.filename + '

' ); } animateSpinner(null, false); diff --git a/app/assets/javascripts/sitewide/file_preview.js b/app/assets/javascripts/sitewide/file_preview.js new file mode 100644 index 000000000..c87d52565 --- /dev/null +++ b/app/assets/javascripts/sitewide/file_preview.js @@ -0,0 +1,58 @@ +(function(global) { + 'use strict'; + + global.initPreviewModal = function initPreviewModal() { + var name; + var url; + var downloadUrl; + $('.file-preview-link').off(); + $('.file-preview-link').click(function(e) { + e.preventDefault(); + name = $(this).find('p').text(); + url = $(this).data('preview-url'); + downloadUrl = $(this).attr('href'); + openPreviewModal(name, url, downloadUrl); + }); + } + + function openPreviewModal(name, url, downloadUrl) { + var modal = $('#filePreviewModal'); + $.ajax({ + url: url, + type: 'GET', + dataType: 'json', + success: function(data) { + modal.find('.file-preview-container').empty(); + modal.find('.file-wopi-controls').empty(); + if (data.hasOwnProperty('wopi-controls')) { + modal.find('.file-wopi-controls').html(data['wopi-controls']); + } + var link = modal.find('.file-download-link'); + link.attr('href', downloadUrl); + link.attr('data-no-turbolink', true); + link.attr('data-status', 'asset-present'); + if (data['type'] === 'image') { + modal.find('.file-preview-container') + .append($('') + .attr('src', data['large-preview-url']) + .attr('alt', name) + .click(function(ev) { + ev.stopPropagation(); + }) + ); + } else { + modal.find('.file-preview-container').html(data['preview-icon']); + } + modal.find('.file-name').text(name); + modal.find('.modal-body').click(function() { + modal.modal('hide'); + }); + modal.modal(); + $('.modal-backdrop').last().css('z-index', modal.css('z-index') - 1); + }, + error: function(ev) { + // TODO + } + }); + } +})(window); diff --git a/app/assets/javascripts/sitewide/image_preview.js b/app/assets/javascripts/sitewide/image_preview.js deleted file mode 100644 index 06bfb80ad..000000000 --- a/app/assets/javascripts/sitewide/image_preview.js +++ /dev/null @@ -1,48 +0,0 @@ -(function(global) { - 'use strict'; - - global.initPreviewModal = function initPreviewModal() { - var name, url, downloadUrl, description; - $('.image-preview-link').off(); - $('.image-preview-link').click(function(e) { - e.preventDefault(); - name = $(this).find('p').text(); - url = $(this).find('img').data('preview-url'); - downloadUrl = $(this).attr('href'); - description = $(this).data('description'); - openPreviewModal(name, url, downloadUrl, description); - }); - } - - function openPreviewModal(name, url, downloadUrl, description) { - var modal = $('#imagePreviewModal'); - $.ajax({ - url: url, - type: 'GET', - dataType: 'json', - success: function(data) { - modal.find('.modal-body img').remove(); - modal.find('.image-name').text(name); - var link = modal.find('.image-download-link'); - link.attr('href', downloadUrl); - link.attr('data-no-turbolink', true); - link.attr('data-status', 'asset-present'); - modal.find('.modal-body').append($('') - .attr('src', data['large-preview-url']) - .attr('alt', name) - .click(function(ev) { - ev.stopPropagation(); - })); - modal.find('.modal-footer .image-description').text(description); - modal.find('.modal-body').click(function() { - modal.modal('hide'); - }); - modal.modal(); - $('.modal-backdrop').last().css('z-index', modal.css('z-index') - 1); - }, - error: function(ev) { - // TODO - } - }); - } -})(window); diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss index eeb5db641..f052a9c5c 100644 --- a/app/assets/stylesheets/application.scss +++ b/app/assets/stylesheets/application.scss @@ -18,5 +18,4 @@ @import "handsontable.full.min"; @import "ajax-bootstrap-select.min"; @import "extend/bootstrap"; -@import "font-awesome"; @import "themes/scinote"; diff --git a/app/assets/stylesheets/themes/scinote.scss b/app/assets/stylesheets/themes/scinote.scss index 39ae3b334..b0f7854c2 100644 --- a/app/assets/stylesheets/themes/scinote.scss +++ b/app/assets/stylesheets/themes/scinote.scss @@ -1278,7 +1278,7 @@ table.dataTable { } // Image preview modal -.modal-image-preview { +.modal-file-preview { background: transparent; font-size: 16px; padding-right: 0 !important; @@ -1292,6 +1292,14 @@ table.dataTable { float: right; } + .file-wopi-controls { + display: inline-block; + + .btn { + margin: 0 15px; + } + } + .modal-dialog { height: 100%; margin: 0; @@ -1309,6 +1317,24 @@ table.dataTable { width: auto; } + .file-preview-container { + align-items: center; + background-color: $color-white; + color: $color-dark-gray; + display: -moz-flex; + display: -webkit-flex; + display: flex; + height: 100%; + justify-content: center; + text-align: center; + width: 60%; + + .file-name { + color: $color-black; + margin: 30px 0; + } + } + img { height: auto; max-width: 100%; @@ -1323,6 +1349,11 @@ table.dataTable { background: $color-black; border: 0; height: 60px; + text-align: center; + + .file-name { + float: left; + } } .modal-body { @@ -1333,6 +1364,7 @@ table.dataTable { height: calc(100% - 120px); justify-content: center; overflow: hidden; + padding: 0; } .modal-footer { @@ -1345,7 +1377,7 @@ table.dataTable { width: 100%; } - .image-download-link { + .file-download-link { color: $color-white; display: inline-block; float: right; diff --git a/app/controllers/assets_controller.rb b/app/controllers/assets_controller.rb index f95b58d81..5b7f768f4 100644 --- a/app/controllers/assets_controller.rb +++ b/app/controllers/assets_controller.rb @@ -7,7 +7,6 @@ class AssetsController < ApplicationController include ActionView::Context include InputSanitizeHelper include FileIconsHelper - include WopiHelper before_action :load_vars before_action :check_read_permission, except: :file_present @@ -31,32 +30,55 @@ class AssetsController < ApplicationController render json: { 'asset-id' => @asset.id, 'image-tag-url' => @asset.url(:medium), - 'preview-url' => large_image_url_asset_path(@asset), + 'preview-url' => asset_file_preview_path(@asset), 'filename' => truncate(@asset.file_file_name, length: Constants::FILENAME_TRUNCATION_LENGTH), 'download-url' => download_asset_path(@asset), - 'type' => asset_data_type(@asset), - 'wopi-file-name' => wopi_asset_file_name(@asset, true), - 'wopi-edit' => (wopi_asset_edit_button(@asset) if wopi_file?(@asset)), - 'wopi-view' => (wopi_asset_view_button(@asset) if wopi_file?(@asset)) + 'type' => asset_data_type(@asset) }, status: 200 end end end end - def large_image_url + def file_preview + response_json = { + 'type' => (@asset.is_image? ? 'image' : 'file'), + + 'filename' => truncate(@asset.file_file_name, + length: + Constants::FILENAME_TRUNCATION_LENGTH), + 'download-url' => download_asset_path(@asset) + } + + if @asset.is_image? + response_json['large-preview-url'] = @asset.url(:large) + else + response_json['preview-icon'] = render_to_string( + partial: 'shared/file_preview_icon.html.erb', + locals: { asset: @asset } + ) + end + + if wopi_file?(@asset) + can_edit = + if @assoc.class == Step + can_manage_protocol_in_module?(@protocol) || + can_manage_protocol_in_repository?(@protocol) + elsif @assoc.class == Result + can_manage_module?(@my_module) + elsif @assoc.class == RepositoryCell + # TBD + end + response_json['wopi-controls'] = render_to_string( + partial: 'shared/file_wopi_controlls.html.erb', + locals: { asset: @asset, can_edit: can_edit } + ) + end respond_to do |format| format.json do - render json: { - 'large-preview-url' => @asset.url(:large), - 'filename' => truncate(@asset.file_file_name, - length: - Constants::FILENAME_TRUNCATION_LENGTH), - 'download-url' => download_asset_path(@asset), - 'type' => (@asset.is_image? ? 'image' : 'file') - } + render json: response_json end end end diff --git a/app/datatables/protocol_linked_children_datatable.rb b/app/datatables/protocol_linked_children_datatable.rb index 131526c99..eb7bccbf1 100644 --- a/app/datatables/protocol_linked_children_datatable.rb +++ b/app/datatables/protocol_linked_children_datatable.rb @@ -61,7 +61,7 @@ class ProtocolLinkedChildrenDatatable < CustomDatatable locals: { project: record.my_module.experiment.project } ) res += '' - res += "
  •  " + res += "
  •  " res += @controller.render_to_string( partial: 'search/results/partials/experiment_text.html.erb', locals: { experiment: record.my_module.experiment } diff --git a/app/helpers/file_icons_helper.rb b/app/helpers/file_icons_helper.rb index 877248220..8c12947e2 100644 --- a/app/helpers/file_icons_helper.rb +++ b/app/helpers/file_icons_helper.rb @@ -4,6 +4,26 @@ module FileIconsHelper %w(csv ods xls xlsb xlsm xlsx odp pot potm potx pps ppsm ppsx ppt pptm pptx doc docm docx dot dotm dotx odt rtf).include?(file_ext) end + # For showing next to file + def file_fa_icon_class(asset) + file_ext = asset.file_file_name.split('.').last + if %w(doc docm docx dot dotm dotx odt rtf).include?(file_ext) + fa_class = 'fa-file-word' + elsif %w(csv ods xls xlsb xlsm xlsx).include?(file_ext) + fa_class = 'fa-file-excel' + elsif %w(odp pot potm potx pps ppsm ppsx ppt pptm pptx).include?(file_ext) + fa_class = 'fa-file-powerpoint' + end + + # Now check for custom mappings or possible overrides + if Extends::FILE_ICON_MAPPINGS[file_ext] + fa_class = Extends::FILE_FA_ICON_MAPPINGS[file_ext] + end + + fa_class = 'fa-file' if fa_class.blank? + fa_class + end + # For showing next to file def file_extension_icon(asset) file_ext = asset.file_file_name.split('.').last diff --git a/app/helpers/wopi_helper.rb b/app/helpers/wopi_helper.rb deleted file mode 100644 index 98cb1a906..000000000 --- a/app/helpers/wopi_helper.rb +++ /dev/null @@ -1,75 +0,0 @@ -module WopiHelper - def wopi_result_view_file_button(result) - if can_read_experiment?(result.my_module.experiment) && - result.asset.can_perform_action('view') - link_to view_asset_url(id: result.asset), - class: 'btn btn-default btn-sm', - target: '_blank', - style: 'display: inline-block' do - "#{file_application_icon( - result.asset - )} #{wopi_button_text(result.asset, 'view')}".html_safe - end - end - end - - def wopi_result_edit_file_button(result) - if can_manage_module?(result.my_module) && - result.asset.can_perform_action('edit') - link_to edit_asset_url(id: result.asset), - class: 'btn btn-default btn-sm', - target: '_blank', - style: 'display: inline-block' do - "#{file_application_icon( - result.asset - )} #{wopi_button_text(result.asset, 'edit')}".html_safe - end - end - end - - def wopi_asset_view_button(asset) - if asset.can_perform_action('view') - link_to view_asset_url(id: asset), - class: 'btn btn-default btn-sm', - target: '_blank', - style: 'display: inline-block' do - "#{file_application_icon(asset)} #{wopi_button_text(asset, 'view')}" - .html_safe - end - end - end - - def wopi_asset_edit_button(asset) - if asset.can_perform_action('edit') - link_to edit_asset_url(id: asset), - class: 'btn btn-default btn-sm', - target: '_blank', - style: 'display: inline-block' do - "#{file_application_icon( - asset - )} #{wopi_button_text(asset, 'edit')}".html_safe - end - end - end - - def wopi_asset_file_name(asset, link = false) - html = '

    ' - html += "#{file_extension_icon(asset)} " - if link - html += link_to download_asset_path(asset), - data: { no_turbolink: true, - id: true, - status: 'asset-present' } do - truncate( - asset.file_file_name, - length: Constants::FILENAME_TRUNCATION_LENGTH - ) - end - else - html += truncate(asset.file_file_name, - length: Constants::FILENAME_TRUNCATION_LENGTH) - end - html += ' 

    ' - sanitize_input(html, %w(img a)) - end -end diff --git a/app/javascript/packs/fontawesome.scss b/app/javascript/packs/fontawesome.scss new file mode 100644 index 000000000..5c64e04bf --- /dev/null +++ b/app/javascript/packs/fontawesome.scss @@ -0,0 +1,4 @@ + $fa-font-path: "~@fortawesome/fontawesome-free-webfonts/webfonts/"; + +@import "~@fortawesome/fontawesome-free-webfonts/scss/fontawesome"; +@import "~@fortawesome/fontawesome-free-webfonts/scss/fa-regular"; diff --git a/app/javascript/packs/styles.scss b/app/javascript/packs/styles.scss index 61e30dc72..5e2943feb 100644 --- a/app/javascript/packs/styles.scss +++ b/app/javascript/packs/styles.scss @@ -1,8 +1,6 @@ -$fa-font-path: "~font-awesome/fonts/"; $icon-font-path: "~bootstrap-sass/assets/fonts/bootstrap/"; @import "~bootstrap-sass/assets/stylesheets/bootstrap"; -@import "~font-awesome/scss/font-awesome"; @import "~react-bootstrap-table/dist/react-bootstrap-table.min"; @import "react-tagsinput/react-tagsinput.css"; @import "react-bootstrap-timezone-picker/dist/react-bootstrap-timezone-picker.min.css"; diff --git a/app/javascript/src/components/Navigation/components/NotificationImage.jsx b/app/javascript/src/components/Navigation/components/NotificationImage.jsx index f6975e3c9..bcc04459c 100644 --- a/app/javascript/src/components/Navigation/components/NotificationImage.jsx +++ b/app/javascript/src/components/Navigation/components/NotificationImage.jsx @@ -25,12 +25,12 @@ const NotificationImage = ({className, type, avatar}: Props) => { ), deliver: ( - + ), assignment: ( - + ) } diff --git a/app/javascript/src/components/Navigation/components/NotificationsDropdown.jsx b/app/javascript/src/components/Navigation/components/NotificationsDropdown.jsx index 201717506..2aa7cbcc0 100644 --- a/app/javascript/src/components/Navigation/components/NotificationsDropdown.jsx +++ b/app/javascript/src/components/Navigation/components/NotificationsDropdown.jsx @@ -141,7 +141,7 @@ class NotificationsDropdown extends Component { this.dropdown = el; }} > -   +   diff --git a/app/javascript/src/components/Navigation/components/TeamSwitch.jsx b/app/javascript/src/components/Navigation/components/TeamSwitch.jsx index 88ccc0f72..ed7ae772d 100644 --- a/app/javascript/src/components/Navigation/components/TeamSwitch.jsx +++ b/app/javascript/src/components/Navigation/components/TeamSwitch.jsx @@ -80,7 +80,7 @@ class TeamSwitch extends Component { onClick={this.setTeams} title={ -  {this.props.current_team.name} +  {this.props.current_team.name} } id="team-switch" diff --git a/app/javascript/src/components/Navigation/index.jsx b/app/javascript/src/components/Navigation/index.jsx index 6fec9dacb..249d1a1e0 100644 --- a/app/javascript/src/components/Navigation/index.jsx +++ b/app/javascript/src/components/Navigation/index.jsx @@ -107,7 +107,7 @@ class Navigation extends Component {