From db0f9d542c68d23b56417eea8fe46c4e081f4fde Mon Sep 17 00:00:00 2001 From: Anita Graham Date: Sat, 16 Jan 2021 17:16:52 +0800 Subject: [PATCH 1/4] Basic changes for image presenter . ensure markup is identical for each view as far as possible . Use css-grid to prevent image title/file name overwriting icons . Add locale markers to images in grid view --- .../refinery/components/_tooltips.scss | 2 +- .../stylesheets/refinery/global/_colours.scss | 8 +- .../refinery/sections/_layout.scss | 1946 ++++++++++------- .../helpers/refinery/translation_helper.rb | 36 +- .../system/refinery/admin/xhr_paging_spec.rb | 2 +- .../admin/images/collection_presenter.rb | 53 + .../refinery/admin/images/image_presenter.rb | 117 + .../refinery/admin/images/_grid_view.html.erb | 16 - .../refinery/admin/images/_images.html.erb | 9 +- .../admin/images/_list_view_image.html.erb | 30 - images/config/locales/en.yml | 2 +- images/config/locales/fr.yml | 2 +- .../shared_contexts/admin_images_tab.rb | 13 +- .../support/shared_examples/image_deleter.rb | 19 +- .../support/shared_examples/image_indexer.rb | 72 +- .../spec/system/refinery/admin/images_spec.rb | 4 +- 16 files changed, 1427 insertions(+), 904 deletions(-) create mode 100644 images/app/presenters/refinery/admin/images/collection_presenter.rb create mode 100644 images/app/presenters/refinery/admin/images/image_presenter.rb delete mode 100644 images/app/views/refinery/admin/images/_grid_view.html.erb delete mode 100644 images/app/views/refinery/admin/images/_list_view_image.html.erb diff --git a/core/app/assets/stylesheets/refinery/components/_tooltips.scss b/core/app/assets/stylesheets/refinery/components/_tooltips.scss index dccba02636..dc8be7a7af 100644 --- a/core/app/assets/stylesheets/refinery/components/_tooltips.scss +++ b/core/app/assets/stylesheets/refinery/components/_tooltips.scss @@ -9,7 +9,7 @@ background: #22a7f2; border: 1px solid #1b82bd; word-wrap:break-word; - position: relative; + //position: relative; color: white; * { color: white; diff --git a/core/app/assets/stylesheets/refinery/global/_colours.scss b/core/app/assets/stylesheets/refinery/global/_colours.scss index e7eb7dc36b..c8bb6f04d4 100644 --- a/core/app/assets/stylesheets/refinery/global/_colours.scss +++ b/core/app/assets/stylesheets/refinery/global/_colours.scss @@ -16,6 +16,12 @@ $icon_add_colour: $icon_default_colour; $action_background_colour: lighten($icon_locale_colour,10%); $action_border_colour: $icon_locale_colour; +$menu-background: #e9e9e9; +$menu-color: #0770ad; +$admin-blue: #28A9F4; +$admin-blue-light: lighten($admin-blue, 20%); +$lowlight: #a3a093; +$highlight: black; // $icon_preview_colour: #7f00ff; // violet // $icon_edit_colour: #007fff; // azure -// $icon_add_colour: #7fff00; // chartreuse \ No newline at end of file +// $icon_add_colour: #7fff00; // chartreuse diff --git a/core/app/assets/stylesheets/refinery/sections/_layout.scss b/core/app/assets/stylesheets/refinery/sections/_layout.scss index 70ef789ddd..61ba4d875f 100644 --- a/core/app/assets/stylesheets/refinery/sections/_layout.scss +++ b/core/app/assets/stylesheets/refinery/sections/_layout.scss @@ -1,709 +1,846 @@ -$admin_width: 1080px; -$menu_width: 120px; -$standard_rounding: 0px; +$admin_width : 1080px; +$menu_width : 120px; +$standard_rounding : 0px; p { - font-size: 14px; - line-height: 18px; + font-size : 14px; + line-height : 18px; } + html { - height: 100%; + height : 100%; } + body { - height: 100%; - margin: -52px 0; - padding: 52px 0 0; - box-sizing: border-box; - font-family: Arial, sans-serif; - line-height: 1.5em; - color: #41403C; - background: rgb(217, 217, 217); + height : 100%; + margin : -52px 0; + padding : 52px 0 0; + box-sizing : border-box; + font-family : Arial, sans-serif; + line-height : 1.5em; + color : #41403C; + background : rgb(217, 217, 217); } + acronym { - cursor: help; + cursor : help; } + label[for] { - cursor: pointer; + cursor : pointer; } + #admin_container, #login_container { - font-size: 13px; - margin: 0px auto 15px auto; - text-align: left; - position: relative; - margin-top: 15px; + font-size : 13px; + margin : 0px auto 15px auto; + text-align : left; + position : relative; + margin-top : 15px; @include rounded($standard_rounding); + a { - color: #41403C; - text-decoration: none; + color : #41403C; + text-decoration : none; } + #menu { a:hover { - border-bottom: 0px; + border-bottom : 0px; } } + .hidden { - display: none; + display : none; } } + #login_container { - background: white; - width: 620px; + background : white; + width : 620px; } + #admin_container { - width: $admin_width; - margin: -5px auto 0px auto; - height: 100%; + width : $admin_width; + margin : -5px auto 0px auto; + height : 100%; @include faux_columns_2($menu_width, transparent, white); } + #page_container { - background-color: white; - padding: 1.5em 1em; - position: relative; - float: left; - width: $admin_width - $menu_width; + background-color : white; + padding : 1.5em 1em; + position : relative; + float : left; + width : $admin_width - $menu_width; @include box-sizing(border-box); @include right-rounded($standard_rounding); } + #content .field, #content .form-actions { - position: relative; + position : relative; } + input.widest, textarea.widest { - width: 99%; + width : 99%; } + select.widest { - max-width: 99%; + max-width : 99%; } + #records { - float: left; - width: 67.7%; + float : left; + width : 67.7%; } + #actions { - float: right; - width: 30%; - padding-left: 15px; - padding-top: 0px; + float : right; + width : 30%; + padding-left : 15px; + padding-top : 0px; + ul { - margin: 0px 0px 18px 0px; - padding: 0; - list-style: none; + margin : 0px 0px 18px 0px; + padding : 0; + list-style : none; + &#current_locale { - margin-top: 30px; + margin-top : 30px; } } + li { - margin-bottom: 10px; - background-color: $action-background-colour; - border: 1px solid $action-border-colour; - padding: 9px; - display: block; + margin-bottom : 10px; + background-color : $action-background-colour; + border : 1px solid $action-border-colour; + padding : 9px; + display : block; + &:empty { - display: none + display : none } } } + #sort-status { - padding: 5px 5px 5px 0px; + padding : 5px 5px 5px 0px; } + hr { - border: 0; - border-top: 1px solid #484743; + border : 0; + border-top : 1px solid #484743; } .errorExplanation { - background-color: #FFB1B1; - padding: 0px 5px 5px 30px; - font-weight: bold; - margin-top: 5px; - margin-bottom: 5px; - border: 1px solid red; + background-color : #FFB1B1; + padding : 0px 5px 5px 30px; + font-weight : bold; + margin-top : 5px; + margin-bottom : 5px; + border : 1px solid red; + h2 { - color: red; - text-transform: none; - display: none; + color : red; + text-transform : none; + display : none; } + p { - font-weight: normal; + font-weight : normal; } } + .fieldWithErrors input, .fieldWithErrors textarea { - border: 1px solid red !important; - background-color: #FFECF0 !important; + border : 1px solid red !important; + background-color : #FFECF0 !important; } + .fieldWithErrors iframe, .fieldWithErrors .visual_editor_box { - border-color: red !important; + border-color : red !important; } + #message, .flash { - padding: 8px 8px 8px 30px; - margin-bottom: 15px; - position: relative; + padding : 8px 8px 8px 30px; + margin-bottom : 15px; + position : relative; } + .flash_notice, .flash_message { - border: 1px solid #00A017; - color: #00A017; + border : 1px solid #00A017; + color : #00A017; @include icon('check-circle', green) } + .flash_notice, .flash_notice * { - color: #00A017; + color : #00A017; } + .flash_error, .flash_alert { - border: 1px solid #A00027; - color: #A00027; + border : 1px solid #A00027; + color : #A00027; @include icon('question-circle', red) } + .flash.flash_notice #flash_close, .flash.flash_error #flash_close, .flash.flash_alert #flash_close { - text-transform: lowercase; + text-transform : lowercase; @include icon('times-circle', $icon_done_colour, 1.2em) } + .flash.flash_message { - background: #E0F5E0; - padding: 9px; - position: relative; - margin-bottom: 32px; + background : #E0F5E0; + padding : 9px; + position : relative; + margin-bottom : 32px; + h2 { - margin-top: 12px; + margin-top : 12px; } } + .flash.flash_message.flash_message, .flash_message * { - color: #262719; - font-size: 14px; + color : #262719; + font-size : 14px; } + .flash a, .flash a:hover { - color: #e20003; - border-bottom-color: #e20003; + color : #e20003; + border-bottom-color : #e20003; } + .flash.flash_error a, .flash.flash_error a:hover, .flash.flash_alert a, .flash.flash_alert a:hover { - display: none; + display : none; } + noscript .flash.flash_error a, noscript .flash.flash_error a:hover, noscript .flash.flash_alert a, noscript .flash.flash_alert a:hover { - display: inline; - font-weight: bold; + display : inline; + font-weight : bold; } + .flash #flash_close { - background: none; - border: none; - color: #41403C; - cursor: pointer; - float: right; - font-size: 1em; - margin-top: 3px; + background : none; + border : none; + color : #41403C; + cursor : pointer; + float : right; + font-size : 1em; + margin-top : 3px; } + #content .visual_editor_box a, #content .ui-tabs a { - border-bottom: 0px none; + border-bottom : 0px none; } + .index #content, .splash #content { - background-color: white; - background-repeat: repeat-y; + background-color : white; + background-repeat : repeat-y; } + #content { - padding: 0px; - background-color: white; + padding : 0px; + background-color : white; + a { - border-bottom: 1px dotted #727272; + border-bottom : 1px dotted #727272; + &.locale { - border-bottom: 0; - display:inline; + border-bottom : 0; + display : inline; } } + h1 { - font-size: 18px; - font-weight: lighter; - text-align: center; - border-bottom: 1px solid #99998B; - padding-bottom: 10px; + font-size : 18px; + font-weight : lighter; + text-align : center; + border-bottom : 1px solid #99998B; + padding-bottom : 10px; } + h2 { - font-size: 18px; - color:#41403c; - margin-bottom: 15px; - margin-top: 10px; - font-weight: bold; + font-size : 18px; + color : #41403c; + margin-bottom : 15px; + margin-top : 10px; + font-weight : bold; } + form.edit_image { - width: 30%; - float: right; - margin-top: 3em + width : 30%; + float : right; + margin-top : 3em } + #existing_image { - float: left; - width: 60%; + float : left; + width : 60%; #original-image { img { - max-width: 100%; + max-width : 100%; } } #crops { - margin-top: 2em; + margin-top : 2em; ul { - list-style: none; - margin: 0; - padding: 0; + list-style : none; + margin : 0; + padding : 0; li { - float: left; - margin-right: 1em; - margin-bottom: 1em; - + float : left; + margin-right : 1em; + margin-bottom : 1em; + img { - display: block; + display : block; } a.delete_icon { - display: block; - float: right; + display : block; + float : right; } } } } } + .actions { a { - display: block; - float: right; - margin: 3px 3px; - line-height: inherit; - border-bottom: 0px none; + display : block; + float : right; + margin : 3px 3px; + line-height : inherit; + border-bottom : 0px none; } } } + .less-important { - color: #727272; + color : #727272; } + header, footer, nav { - display: block; + display : block; } + #page_container .login #page h1 { - margin: 0; - padding: 5px; - font-size: 20px; - line-height:22px + margin : 0; + padding : 5px; + font-size : 20px; + line-height : 22px } + #login_container { #page_container { - background: transparent; - width: 100%; + background : transparent; + width : 100%; + div.remember_me label, label.inline { - display: inline; + display : inline; } + div.actions { - margin-top: 12px; + margin-top : 12px; } + div.remember_me { - width: 300px; - float: left; + width : 300px; + float : left; } + div.forgot_password { - float: right; - width: 250px; + float : right; + width : 250px; } } + header { - background: #eaeaea; - height: auto; - float: none; - width: 100%; + background : #eaeaea; + height : auto; + float : none; + width : 100%; @include top-rounded($standard_rounding); + h1 { - color: #41403c; - vertical-align: middle; - text-align: center; - font-weight: bold; - font-size: 18px; - padding-bottom: 15px; - line-height: 30px; - padding-top: 15px; + color : #41403c; + vertical-align : middle; + text-align : center; + font-weight : bold; + font-size : 18px; + padding-bottom : 15px; + line-height : 30px; + padding-top : 15px; } } + label { - margin-top: 0px; + margin-top : 0px; } + label, a { - font-size: 14px; + font-size : 14px; } + .field { - margin-bottom: 20px; + margin-bottom : 20px; + &.remember_me, &.forgot_password { - margin-bottom: 0px; - margin-top: 0px; + margin-bottom : 0px; + margin-top : 0px; } + &.forgot_password { - text-align: right; + text-align : right; } + &.remember_me label { - margin-top: 20px; + margin-top : 20px; } } + #flash_container, .errorExplanation { - margin-bottom: 12px; + margin-bottom : 12px; } + /* Works in Firefox, Safari, Chrome, IE8+ */ input.larger { - background: image_url('refinery/text_field_background.png') repeat-x white; - height: 31px; + background : image_url('refinery/text_field_background.png') repeat-x white; + height : 31px; } + input.larger:focus { - background-position: 0px -41px; + background-position : 0px -41px; } + .fieldWithErrors input.larger { - background-position: 0px -82px; - border: 1px solid red; + background-position : 0px -82px; + border : 1px solid red; } } + div.field.checkbox_access { - margin-top: 20px; + margin-top : 20px; + ul.checkboxes li { - margin-top: 3px; + margin-top : 3px; } + .label_with_help a { - font-weight: normal; + font-weight : normal; } } + #menu { - display: block; - margin: 45px 0px 0px 0px; - padding: 0px; - position: absolute; - background: transparent; + display : block; + margin : 45px 0px 0px 0px; + padding : 0px; + position : absolute; + background : transparent; } + header { - float: left; - margin-bottom: 0px; - width: $menu_width; + float : left; + margin-bottom : 0px; + width : $menu_width; + a, a:hover { - border-bottom: 0px none; + border-bottom : 0px none; } + #logo { - position: absolute; - right: 20px; - top: 25px; + position : absolute; + right : 20px; + top : 25px; } + h1, h1 a { - color: white; - font-size: 20px; - font-weight: normal; - margin-bottom: 0; - padding-bottom: 4px; - margin-top: 0; + color : white; + font-size : 20px; + font-weight : normal; + margin-bottom : 0; + padding-bottom : 4px; + margin-top : 0; } + p { - color: white; - font-size: 90%; - padding: 0; - margin: 0; + color : white; + font-size : 90%; + padding : 0; + margin : 0; } } + #menu { - display: block; - position: relative; + display : block; + position : relative; + &.ui-sortable a { - cursor: move; + cursor : move; } + &.ui-sortable-disabled a { - cursor: pointer; + cursor : pointer; } + a { @include box-sizing(border-box); - display: block; - padding: 8px 16px; - font-size: 14px; - background-color: rgba(233, 233, 233, 1); - margin-bottom: 1px; - color: rgba(7, 112, 173, 1); - font-weight: normal; - position: relative; + display : block; + padding : 8px 16px; + font-size : 14px; + background-color : rgba(233, 233, 233, 1); + margin-bottom : 1px; + color : rgba(7, 112, 173, 1); + font-weight : normal; + position : relative; + &.active, &:hover, &:focus { - background-color: rgba(37, 169, 244, 1); - color: white; + background-color : rgba(37, 169, 244, 1); + color : white; } + &.active { - margin-left: -0.5em; - font-weight: bold; + margin-left : -0.5em; + font-weight : bold; } } a#menu_reorder, a#menu_reorder_done { - height: 14px; - width: 14px; - margin-bottom: 0; - padding: 6px; - cursor: pointer; - vertical-align: middle; - text-align: center; - float: right; + height : 14px; + width : 14px; + margin-bottom : 0; + padding : 6px; + cursor : pointer; + vertical-align : middle; + text-align : center; + float : right; @include box-sizing(content-box); } + a#menu_reorder_done { - background: white; + background : white; } } pre { - margin: 0; - padding: 0; + margin : 0; + padding : 0; } + .preview { - color: #A3A093; + color : #A3A093; } + #site_link { - display: block; - color: #C2C2B3; - float: left; + display : block; + color : #C2C2B3; + float : left; } + #site_link:hover { - text-decoration: underline; + text-decoration : underline; } + .filter { - float: right; + float : right; } + #records { > ul, > #recent_activity > ul, > #recent_inquiries > ul, .pagination_container > ul, .pagination_frame > ul { - margin-left: 0; - margin-top: 0; - padding-left: 0; + margin-left : 0; + margin-top : 0; + padding-left : 0; } + > ul li, > #recent_activity > ul li, > #recent_inquiries > ul li, .pagination_container > ul li, .pagination_frame > ul { - list-style: none; - padding: 0px 5px; - vertical-align: top; - margin-bottom: 2px; - line-height: 35px; - position: relative; + list-style : none; + padding : 0px 5px; + vertical-align : top; + margin-bottom : 2px; + line-height : 35px; + position : relative; } + > #recent_activity > ul li, > #recent_inquiries > ul li { - max-height: 35px; + max-height : 35px; } } + #recent_activity li a, #recent_inquiries li a { - overflow: hidden; - white-space: nowrap; - -o-text-overflow: ellipsis; - -ms-text-overflow: ellipsis; - text-overflow: ellipsis; + overflow : hidden; + white-space : nowrap; + -o-text-overflow : ellipsis; + -ms-text-overflow : ellipsis; + text-overflow : ellipsis; } + #content #records { > ul li .actions a, .pagination_container > ul li .actions a { - line-height: 29px; + line-height : 29px; } } + #records { ul { &.clickable { li { - padding: 0px; - margin-bottom: 0px; + padding : 0px; + margin-bottom : 0px; a { - padding: 0px 5px; - vertical-align: top; - margin-bottom: 2px; - line-height: 35px; - display: block; - border-bottom: 0px none; + padding : 0px 5px; + vertical-align : top; + margin-bottom : 2px; + line-height : 35px; + display : block; + border-bottom : 0px none; } } } } + .left-column { - float: left; - width: 65%; + float : left; + width : 65%; + img { - vertical-align: bottom; - margin-top: 1px; - margin-right: 5px; + vertical-align : bottom; + margin-top : 1px; + margin-right : 5px; } } + .right-column { - float: right; - width: 34%; - text-align: right; + float : right; + width : 34%; + text-align : right; } + .on { - background-color: #EAEAEA; + background-color : #EAEAEA; } + + .off, .on-hover { - background-color: white; + background-color : white; } + ul.empty { - display: none; + display : none; } + ul#sortable_list, ul.sortable_list { - margin-top: 6px; + margin-top : 6px; } + > #recent_activity, > #recent_inquiries { - float: left; - width: 48%; + float : left; + width : 48%; } + > #recent_inquiries { - margin-left: 21px; + margin-left : 21px; } } + #records.one_list > #recent_activity, #records.one_list > #recent_inquiries { - width: 100%; + width : 100%; } + #pagination ul a:hover, #pagination .on { - background: image_url('refinery/hover-gradient.jpg') repeat-x bottom #D4D4C6; + background : image_url('refinery/hover-gradient.jpg') repeat-x bottom #D4D4C6; } + #records.tree ul li ul, .tree ul li ul { - padding: 0; + padding : 0; } + #records.tree ul li, .tree ul li { - margin: 0px; - padding: 4px 0 0 40px; - background: image_url('refinery/branch.gif') no-repeat 15px 0px; + margin : 0px; + padding : 4px 0 0 40px; + background : image_url('refinery/branch.gif') no-repeat 15px 0px; } + #records.tree li.record ul { - margin-left: 0; + margin-left : 0; } + #records.tree .on-hover, #pagination ul.tree a:hover, #pagination .tree .on { - background: image_url('refinery/branch.gif') no-repeat 15px 0px; + background : image_url('refinery/branch.gif') no-repeat 15px 0px; } + #records.tree ul li.branch_start, .tree ul li.branch_start { - background-image: image_url('refinery/branch-start.gif'); + background-image : image_url('refinery/branch-start.gif'); } + #records.tree ul li.branch_end, .tree ul li.branch_end { - background-image: image_url('refinery/branch-end.gif'); + background-image : image_url('refinery/branch-end.gif'); } + #records.tree li { - line-height: 25px; + line-height : 25px; } + #records.tree li span.spacing, .tree li span.spacing { - display: none; + display : none; } + #records.tree ul li > div:hover, .tree ul li > div:hover { - background-color: #EAEAEA; + background-color : #EAEAEA; } + #sortable_list.reordering > li, .sortable_list.reordering > li { - cursor: move; + cursor : move; } + #records h2, #actions h2 { - margin-top: 0px; + margin-top : 0px; } + .pagination { - background-color: #C9DAE2; - padding: 5px 5px 4px 5px; - margin: 10px 0px; + background-color : #C9DAE2; + padding : 5px 5px 4px 5px; + margin : 10px 0px; + em { - font-weight: bold; - font-style: normal; - padding: 0px 6px; + font-weight : bold; + font-style : normal; + padding : 0px 6px; } } + .pagination { .disabled { - color: #A8B9C1; + color : #A8B9C1; } - a, #content a, .current, .disabled, em { - padding: 7px; - line-height: 20px; - border-bottom: 0px none; + + a, #content a, .current, .disabled, em { + padding : 7px; + line-height : 20px; + border-bottom : 0px none; } + .current, a:hover, em { - background: #A8B9C1; + background : #A8B9C1; } } + textarea { - line-height: 20px; - padding: 5px; + line-height : 20px; + padding : 5px; } + .field-couple { - margin-bottom: 20px; + margin-bottom : 20px; } + .submit { - border: inherit; - width: auto; - height: 25px; + border : inherit; + width : auto; + height : 25px; } + label, .label_with_help { - margin-bottom: 5px; - font-weight: bold; - margin-top: 20px; - display: block; + margin-bottom : 5px; + font-weight : bold; + margin-top : 20px; + display : block; } + label.input_label { - font-size: inherit; - margin-bottom: inherit; - display: inline; - font-weight: normal; - margin-top: inherit; + font-size : inherit; + margin-bottom : inherit; + display : inline; + font-weight : normal; + margin-top : inherit; } + small label { - font-size: inherit; - font-weight: inherit; - display: inherit; + font-size : inherit; + font-weight : inherit; + display : inherit; } + label.stripped { - float: none; - display: inline; - font-weight: normal; - font-size: 1em; - margin: 0px; - padding: 0px; + float : none; + display : inline; + font-weight : normal; + font-size : 1em; + margin : 0px; + padding : 0px; } + #body_field { - float: left; - width: 60%; + float : left; + width : 60%; } + .no_side_body { - width: 72% !important; + width : 72% !important; } + #side_body_field { - float: left; - width: 38%; - margin-left: 18px; + float : left; + width : 38%; + margin-left : 18px; } + #body_field textarea, #side_body_field textarea { - width: 99%; + width : 99%; } + .record .title span { - line-height: 30px; + line-height : 30px; } #records.files .record .title, #dialog_main #resource_file_area .pages_list ul li a.page_link { - display:inline-block; - padding-left:24px; - min-height:16px; - background-repeat:no-repeat; - background-position:left; + display : inline-block; + padding-left : 24px; + min-height : 16px; + background-repeat : no-repeat; + background-position : left; @include icon('file-o', blue) } -#dialog_main #resource_file_area .pages_list ul li a.page_link{ - background-position:5px center; - display:block; + +#dialog_main #resource_file_area .pages_list ul li a.page_link { + background-position : 5px center; + display : block; } + #records.files .record .title.pdf, #dialog_main #resource_file_area .pages_list ul li a.page_link.pdf { @include icon('file-pdf-o') } + #records.files .record .title.jpg, #records.files .record .title.gif, #records.files .record .title.jpeg, @@ -720,854 +857,1095 @@ label.stripped { #records.files .record .title.doc, #records.files .record .title.pages, #records.files .record .title.docx, #dialog_main #resource_file_area .pages_list ul li a.page_link.doc, #dialog_main #resource_file_area .pages_list ul li a.page_link.docx, #dialog_main #resource_file_area .pages_list ul li a.page_link.pages { @include icon('file-word-o'); } + #records.files .record .title.ppt, #records.files .record .title.keynote, #dialog_main #resource_file_area .pages_list ul li a.page_link.ppt, #dialog_main #resource_file_area .pages_list ul li a.page_link.keynote { @include icon('file-powerpoint-o'); } + #records.files .record .title.xls, #records.files .record .title.numbers, #dialog_main #resource_file_area .pages_list ul li a.page_link.xls, #dialog_main #resource_file_area .pages_list ul li a.page_link.numbers { @include icon('file-excel-o'); } + #records.files .record .title.zip, #records.files .record .title.rar, #dialog_main #resource_file_area .pages_list ul li a.page_link.zip, #dialog_main #resource_file_area .pages_list ul li a.page_link.rar { @include icon('file-zip-o'); } + #records.files .record .title.mp3, #records.files .record .title.wav, #records.files .record .title.aiff, #records.files .record .title.m4a, #dialog_main #resource_file_area .pages_list ul li a.page_link.mp3, #dialog_main #resource_file_area .pages_list ul li a.page_link.wav, #dialog_main #resource_file_area .pages_list ul li a.page_link.aiff, #dialog_main #resource_file_area .pages_list ul li a.page_link.m4a { @include icon('file-audio-o'); } + #records .actions { - position: absolute; - right: 0px; - top: 0px; - width: 120px; - text-align: right; - display: block; - line-height: 28px; + position : absolute; + right : 0px; + top : 0px; + width : 120px; + text-align : right; + display : block; + line-height : 28px; } + #records.tree.icons .title { - display: block; - margin: 0 120px 0 20px; + display : block; + margin : 0 120px 0 20px; &.toggle { - cursor: pointer; + cursor : pointer; } } + #records.tree .actions { - line-height: 22px; - top: 1px; + line-height : 22px; + top : 1px; } + .published { - width: 25px; - text-align: center; + width : 25px; + text-align : center; } + #content #records.tree > ul li .actions a { - margin: 3px 3px 0px 3px; - line-height: 24px; + margin : 3px 3px 0px 3px; + line-height : 24px; } + .actions a * { - padding: 4px 4px 1px 4px; + padding : 4px 4px 1px 4px; } + .actions a img { - vertical-align: middle; - padding: 2px 4px 4px 4px; + vertical-align : middle; + padding : 2px 4px 4px 4px; } + #records.tree .actions a img { - padding-top: 4px; + padding-top : 4px; } + #records.tree li span.item { - display: block; - float: left; - width: 16px; - height: 16px; - margin: 3px 3px 0 0; + display : block; + float : left; + width : 16px; + height : 16px; + margin : 3px 3px 0 0; @include icon('file-o', $icon_page_colour); &.toggle { - cursor: pointer; - @include icon('folder',$icon_folder_colour); + cursor : pointer; + @include icon('folder', $icon_folder_colour); } + &.toggle.expanded { - @include icon('folder-open',$icon_folder_colour); + @include icon('folder-open', $icon_folder_colour); } } + #records.tree li.loading > div > span.icon { @include icon('spinner'); } + #image_grid .actions a img { - padding: 4px 4px 1px 4px; - vertical-align: top; + padding : 4px 4px 1px 4px; + vertical-align : top; } .actions a.reorder_anchor:hover { - background: inherit !important; - cursor: move; + background : inherit !important; + cursor : move; } + #other_records { - width: 68%; + width : 68%; } + #common_actions { - margin: 0; - padding: 0; + margin : 0; + padding : 0; + li { - margin: 0; - list-style: none; - padding: 5px 0px 5px 0px; + margin : 0; + list-style : none; + padding : 5px 0px 5px 0px; + } + + a { + font-weight : bold; } - a { - font-weight: bold; - } } + .larger { - font-size: 200%; + font-size : 200%; } + .brown_border { - border: 1px solid #99998B; + border : 1px solid #99998B; } + #inquiry, .inquiry { - border-collapse: collapse; - width: 100%; + border-collapse : collapse; + width : 100%; } + #inquiry td, .inquiry td { - border-bottom: 1px solid #CCCCCC; - padding: 7px; + border-bottom : 1px solid #CCCCCC; + padding : 7px; } + #inquiry tr:last-child td, .inquiry tr:last-child td { - border-bottom: 0px; + border-bottom : 0px; } + #inquiry td label.stripped, .inquiry td label.stripped { - font-weight: bold; + font-weight : bold; } + body.dialog { - background: #FFF; + background : #FFF; } + body.dialog, body.visual_editor_dialog { - text-align: left; + text-align : left; } + body.dialog form { - width: 100% !important; + width : 100% !important; } + .visual_editor_dialog_table { - height: 250px; + height : 250px; } + .no_picked_image_selected {@include icon('warning', $icon_warning_colour)} + .dialog { #dialog_main { - float: left; - margin-left: 130px; - min-height: 405px; - width: 696px; + float : left; + margin-left : 130px; + min-height : 405px; + width : 696px; } + span.radio { - display: block; - line-height: 18px; - padding: 6px 0px; + display : block; + line-height : 18px; + padding : 6px 0px; } + span.radio * { - cursor: pointer; - font-weight: bold; + cursor : pointer; + font-weight : bold; } + #dialog_menu_left { - position: fixed; - left: 12px; - top: 9px; - width: 130px; + position : fixed; + left : 12px; + top : 9px; + width : 130px; } + #existing_image_content { - position: relative; - height: 300px; - padding: 12px; + position : relative; + height : 300px; + padding : 12px; } + #existing_image_area_content, #existing_image_area_crops { - margin-top: 28px; + margin-top : 28px; + ul { - margin: 0px; - padding: 0px; + margin : 0px; + padding : 0px; + li { - list-style: none; - padding: 0px; - margin: 0px 2px 0px 0px; - float: left; - height: 114px; - max-height: 114px; - width: 114px; - max-width: 114px; - overflow: hidden; - cursor: pointer; - text-align: center; - vertical-align: middle; + list-style : none; + padding : 0px; + margin : 0px 2px 0px 0px; + float : left; + height : 114px; + max-height : 114px; + width : 114px; + max-width : 114px; + overflow : hidden; + cursor : pointer; + text-align : center; + vertical-align : middle; + img { - border: 4px solid transparent; + border : 4px solid transparent; } + &.selected img { - border: 4px solid #22A7F2; + border : 4px solid #22A7F2; } } } } + #existing_image_size_area { - margin-top: 18px; - margin-bottom: 50px; + margin-top : 18px; + margin-bottom : 50px; + ul { - margin: 0px; - padding: 10px 0px 0px 0px; + margin : 0px; + padding : 10px 0px 0px 0px; + li { - float: left; - list-style: none; - margin: 0px 18px 0px 0px; - text-align:center; + float : left; + list-style : none; + margin : 0px 18px 0px 0px; + text-align : center; + a { - display: block; - border: 1px solid #999999; - font-size: 10px; + display : block; + border : 1px solid #999999; + font-size : 10px; } + &.selected { a { - border-color: #22A7F2; - background: #22A7F2; - color: white; - font-weight: bold; + border-color : #22A7F2; + background : #22A7F2; + color : white; + font-weight : bold; } } } } } + #existing_image_size_area { - #image_dialog_size_0 a { height: 30px; width: 30px; line-height: 30px; margin-top: 10px } - #image_dialog_size_1 a { height: 50px; width: 50px; line-height: 50px; margin-top: 0px } - #image_dialog_size_2 a { height: 70px; width: 70px; line-height: 70px; margin-top:-10px } - #image_dialog_size_3 a { height: 90px; width: 90px; line-height: 90px; margin-top:-20px } + #image_dialog_size_0 a { height : 30px; width : 30px; line-height : 30px; margin-top : 10px } + + #image_dialog_size_1 a { height : 50px; width : 50px; line-height : 50px; margin-top : 0px } + + #image_dialog_size_2 a { height : 70px; width : 70px; line-height : 70px; margin-top : -10px } + + #image_dialog_size_3 a { height : 90px; width : 90px; line-height : 90px; margin-top : -20px } } + #content { - padding: 0px; + padding : 0px; } } + #upload_image_area, #upload_resource_area { - padding: 12px; + padding : 12px; } + .visual_editor_dialog #page { - width: 940px; - padding: 6px; + width : 940px; + padding : 6px; } + #dialog_main { .pagination { - margin: 0px; - position: fixed; - bottom: 5px; - right: 12px; - z-index: 1000; + margin : 0px; + position : fixed; + bottom : 5px; + right : 12px; + z-index : 1000; } + .pages_list { - width: 100%; - padding-bottom: 40px; + width : 100%; + padding-bottom : 40px; + ul { - margin: 0px 12px 0px 12px; - padding: 0px; + margin : 0px 12px 0px 12px; + padding : 0px; + li { - cursor: pointer; - line-height: 24px; - list-style: none; + cursor : pointer; + line-height : 24px; + list-style : none; + a { - display: block; - padding: 3px 3px 3px 27px; - text-decoration: none; - border-bottom: none; - border: 1px solid transparent; + display : block; + padding : 3px 3px 3px 27px; + text-decoration : none; + border-bottom : none; + border : 1px solid transparent; } + &:hover { - background-color: #C9DAE2; + background-color : #C9DAE2; } } + li.child a { - padding-left: 27px; + padding-left : 27px; } + li.child1 a { - padding-left: 47px; + padding-left : 47px; } + li.child2 a { - padding-left: 67px; + padding-left : 67px; } + li.child3 a { - padding-left: 87px; + padding-left : 87px; } + li.child4 a { - padding-left: 107px; + padding-left : 107px; } } } + .actions { - margin-right: 48px; + margin-right : 48px; } + .pages_list .linked a, .pages_list .linked a:hover { - border: 1px solid #00A017; - color: #00A017; + border : 1px solid #00A017; + color : #00A017; @include icon('check-circle', green); } + .pages_list .linked a em { - color: #00A017; + color : #00A017; } + #web_address_area, #dialog_main #email_address_area { - padding: 12px; + padding : 12px; } } + #link_title { - margin-top: 12px; + margin-top : 12px; + label { - margin: 3px 0px 0px 0px !important; - width: 130px; - display: block; - float: left; + margin : 3px 0px 0px 0px !important; + width : 130px; + display : block; + float : left; } + input { - width: 770px; + width : 770px; } } + ul#menu.reordering_menu li a { - cursor: move; + cursor : move; } + #search { - border: 1px solid #b3b3b3; - line-height: 18px; - padding: 2px; - font-size: 16px; - width: 10em; + border : 1px solid #b3b3b3; + line-height : 18px; + padding : 2px; + font-size : 16px; + width : 10em; } + .cancel-search { - float: right; + float : right; } + .pt-BR #search { - width: 107px; + width : 107px; } + .en #search { - width: 130px; + width : 130px; } + .search_form { - position: relative; + position : relative; + .button, .button-wrapper { - position: absolute; - right: 0px; - top: 2px; + position : absolute; + right : 0px; + top : 2px; } } + form input[type=submit]:hover { - background: #65c3f7; + background : #65c3f7; } + .clearfix:after { - content:"."; - display:block; - height:0; - clear:both; - visibility:hidden; + content : '.'; + display : block; + height : 0; + clear : both; + visibility : hidden; } -.clearfix {display:inline-block;} + +.clearfix {display : inline-block;} + /* Hide from IE Mac \*/ -.clearfix {display:block;} +.clearfix {display : block;} + /* End hide from IE Mac */ /* Firefox Dotted Line Fix - http://sonspring.com/journal/removing-dotted-links */ a:focus { - outline: none; + outline : none; } + a img { - border: 0px none; + border : 0px none; } - /* page parts */ -ul#page_parts, +ul#page_parts, ul#page_parts_controls { - margin: 0; - padding: 0; + margin : 0; + padding : 0; } ul#page_parts { - float: left; - width: 92%; - z-index: 1; + float : left; + width : 92%; + z-index : 1; } ul#page_parts_controls { - float: right; - margin: 20px 3px 0 0; - z-index: 2; + float : right; + margin : 20px 3px 0 0; + z-index : 2; li { - list-style: none; - float: right; - margin: 0 3px; + list-style : none; + float : right; + margin : 0 3px; a { - border: 0px none; + border : 0px none; } } } - #page-tabs.ui-sortable.reordering { li { - cursor: move; + cursor : move; + a { - cursor: move; + cursor : move; } } } + #page_part_editors { - clear:left; + clear : left; } /* dialog stuff */ #dialog_frame { - width:952px; - height:460px; - padding: 0px; - border: 0px solid #F2F1ED; + width : 952px; + height : 460px; + padding : 0px; + border : 0px solid #F2F1ED; } + .visual_editor_hideables { - display: none; + display : none; } + #content .form-actions, .wym_dialog .form-actions, .ui-dialog .form-actions { @include form-actions; } + .dialog form { - margin-bottom: 45px; + margin-bottom : 45px; } + .dialog .dialog_area > div > .field label:first-child, .dialog .dialog_area > div > label:first-child { - margin-top: 0px; + margin-top : 0px; } + .visual_editor_dialog .form-actions, #content.form-actions.dialog-form-actions, .ui-dialog .form-actions { - margin-top: 16px; + margin-top : 16px; } + #content .form-actions .form-actions-left, #content .form-actions .form-actions-right, - .visual_editor_dialog .form-actions .form-actions-left, .visual_editor_dialog .form-actions .form-actions-right, - .ui-dialog .form-actions .form-actions-left, .ui-dialog .form-actions .form-actions-right { - position: absolute; - top: 10px; +.visual_editor_dialog .form-actions .form-actions-left, .visual_editor_dialog .form-actions .form-actions-right, +.ui-dialog .form-actions .form-actions-left, .ui-dialog .form-actions .form-actions-right { + position : absolute; + top : 10px; } + #content .form-actions .form-actions-left, .visual_editor_dialog .form-actions .form-actions-left, .ui-dialog .form-actions .form-actions-left { - left: 10px; + left : 10px; } + #content .form-actions .form-actions-right, .visual_editor_dialog .form-actions .form-actions-right, .ui-dialog .form-actions .form-actions-right { - right: 10px; + right : 10px; } + #content .form-actions .save-loader { - position: absolute; - right: -24px; - top: 4px; + position : absolute; + right : -24px; + top : 4px; } + .visual_editor_dialog .form-actions, .ui-dialog .form-actions { - border: 0px none; - border-top: 1px solid #E8E8E8; + border : 0px none; + border-top : 1px solid #E8E8E8; } + #dialog_iframe { - position: relative; + position : relative; } + #dialog_container #content .form-actions, .ui-dialog .form-actions, .dialog_container .form-actions { - position: absolute; - bottom: 0px; - left: 0px; - right: 0px; - border-right: 0px; - border-left: 0px; - border-bottom: 0px; - width: auto; + position : absolute; + bottom : 0px; + left : 0px; + right : 0px; + border-right : 0px; + border-left : 0px; + border-bottom : 0px; + width : auto; } + #dialog_container.dialog.iframed #content .form-actions { - position: fixed; + position : fixed; } + body.dialog #content .search_form { - float: right; - width: auto !important; - min-width: 300px; - margin-bottom: 0px; + float : right; + width : auto !important; + min-width : 300px; + margin-bottom : 0px; } + #existing_image_area { - padding-top:6px; + padding-top : 6px; } + .ui-dialog div.field { - margin: 0px 10px; + margin : 0px 10px; } + #dialog_container, .dialog_container { - margin: 0px; - padding: 12px; -} -ul#image_grid, .pagination_container > ul#image_grid { - width: 100%; - padding: 0px; - margin: 10px 0px 15px 0px; -} -ul#image_grid li, .pagination_container > ul#image_grid li { - position: relative; - float: left; - margin: 0px 12px 12px 0px; - padding: 0px; - width: 149px; - height: 186px; - max-width: 149px; - max-height: 186px; - text-align: center; - overflow: hidden; -} -ul#image_grid li.image_3 { - margin-left: 0px; - margin-right: 0px; -} -#records ul#image_grid li .actions { - top: auto; - bottom: 0px; -} -#records ul#image_grid li .actions a { - line-height: 24px; -} -ul#image_grid li.row-end { - margin-right: 0px; - float: right; -} -ul#image_grid li a { - border: 0 none; -} -ul#image_grid li p { - margin: 3px 0; -} -ul#image_grid li span.actions { - width: 100%; + margin : 0px; + padding : 12px; +} + +// Image Indexes Grid view and List view + +ul#image_grid { + width : 100%; + display : grid; + grid-template-columns : repeat(auto-fill, 149px); + gap : 0.5rem; + + li { + height : 180px; // image: 149px, actions: 29px + rounding; + text-align : center; + overflow : hidden; + + .item { + a { border : none; + + &.edit { + display : inline-grid; + font-size : 1rem; + } + } + + .locales { + position : absolute; + top : 0; + bottom : auto; + left : 6px; + line-height : 28px; + background-color : rgba(255, 255, 255, 0.7); + } + + .preview { + // info-icon is in the same place and shows the same information + display: none; + } + } + + .actions { + position : absolute; + line-height : 24px; + background-color : rgba(255, 255, 255, 0.4); + display : flex; + flex-direction : row; + flex-wrap : wrap; + top : auto; + left : 0; + bottom : 0; + } + } +} + +ul#image_list { + li { + .item { + width : 33rem; + display : grid; + grid-template-columns : 1fr 4rem; + grid-template-rows : [major]1.5rem [minor]1rem; + column-gap : 1rem; + grid-template-areas : + 'title locales' + 'preview preview'; + + .title {grid-area : title} + + .locales {grid-area : locales} + + .preview {grid-area : preview} + + a.edit.title, a.edit.locale { + display : inline-grid; + font-size : 1rem; + } + + a.locale { + // put this above the image, which is also clickable + z-index : 10; + } + + .preview { + line-height : 1.2rem; + font-size : 0.8rem; + color : $lowlight; + white-space:nowrap; + overflow:hidden; + text-overflow:ellipsis; + + &:hover { + overflow: visible; + color: $menu-color; + background-color : white; + border: 1px solid $admin-blue; + white-space: normal; + height: fit-content; + //box-shadow: 2px 2px 2px #888; + padding: 0.25rem; + + z-index: 10; + font-size: 1rem; + } + } + } + } } + +// End of Image indexes ul.checkboxes { - margin: 0px; - padding: 0px; + margin : 0px; + padding : 0px; } + ul.checkboxes li { - list-style: none; + list-style : none; } + .label_inline_with_link label { - float: left; - margin-right: 6px; + float : left; + margin-right : 6px; } + .label_inline_with_link a { - border: 0px none; - margin-top: 19px; - line-height: 17px; - float: left; + border : 0px none; + margin-top : 19px; + line-height : 17px; + float : left; } + .label_inline_with_link a img { - vertical-align: middle; + vertical-align : middle; } + .remove_picked_image { - margin-top:8px; - display:inline-block; - width:auto; + margin-top : 8px; + display : inline-block; + width : auto; } + #new_page_part_dialog .field { - padding: 0px 10px; + padding : 0px 10px; } + .hide-overflow { - overflow: hidden; + overflow : hidden; } + #remove_resource { - margin-top:8px; - display:inline-block; - width:auto; + margin-top : 8px; + display : inline-block; + width : auto; } + .visual_editor_dialog_paste .field textarea { - width: 98%; + width : 98%; } + .ui-dialog .visual_editor_dialog_paste .field, .ui-dialog .visual_editor_dialog_paste .field textarea { - margin: 0px 0px 45px 0px; - height: 300px; + margin : 0px 0px 45px 0px; + height : 300px; } + input.button, a.button, #content a.button, span.button-wrapper, span.button-wrapper input { - cursor:pointer; - background: #22a7f2; - color: white; - padding: 0px 14px 0px 14px; - font-size: 14px; - line-height: 24px; - height: 24px; - display: inline-block; - border: 0px none; - margin-top: 0px; - margin-bottom: 0px; + cursor : pointer; + background : #22a7f2; + color : white; + padding : 0px 14px 0px 14px; + font-size : 14px; + line-height : 24px; + height : 24px; + display : inline-block; + border : 0px none; + margin-top : 0px; + margin-bottom : 0px; } + /* for those pesky IE browsers */ span.button-wrapper { - padding: 0px; + padding : 0px; } + span.button-wrapper input { - display: inherit; + display : inherit; } + /* fixes firefox display */ input.button { - padding-bottom: 3px; + padding-bottom : 3px; } + input.button.close_dialog, a.button.close_dialog, #content a.button.close_dialog, span.button-wrapper.close_dialog, span.button-wrapper.close_dialog input { - background: #bcbcbc; + background : #bcbcbc; } + input.button:hover, a.button:hover, #content a.button:hover, span.button-wrapper:hover, span.button-wrapper:hover input { - background:#62bef2; + background : #62bef2; } + input.button.close_dialog:hover, a.button.close_dialog:hover, #content a.button.close_dialog:hover, span.button-wrapper.close_dialog:hover { - background: #cdcdcd; + background : #cdcdcd; } + input.button:active, a.button:active, #content a.button:active, span.button-wrapper:active, span.button-wrapper:active input { - background: #004a8f; + background : #004a8f; } -input.button.close_dialog:active, a.button.close_dialog:active, #content a.button.close_dialog:active, span.button-wrapper.close_dialog:active, span.button-wrapper.close_dialog:active input { - background: #808080; + +input.button.close_dialog:active, a.button.close_dialog:active, #content a.button.close_dialog:active, span.button-wrapper.close_dialog:active, span.button-wrapper.close_dialog:active input { + background : #808080; } + .visual_editor_dialog a.button.visual_editor_cancel.close_dialog { - margin-left: 6px; + margin-left : 6px; } + #content a.button.close_dialog:active { - color: white; + color : white; } + .form-actions a.confirm-delete, #content .form-actions a.confirm-delete { - background: #ee1100; - position: absolute; - right: 0px; + background : #ee1100; + position : absolute; + right : 0px; } + .form-actions a.confirm-delete:hover, #content .form-actions a.confirm-delete:hover { - background: #ff3322; + background : #ff3322; } + .form-actions a.confirm-delete:active, #content .form-actions a.confirm-delete:active { - background: #bb0000; + background : #bb0000; } + .field input[type=text], .field input[type=password], .field input[type=email], .field input[type=tel], .field input[type=number], .field textarea { - border: 1px solid #7f9db9; - padding: 0.4% 0.5%; - line-height: 20px; + border : 1px solid #7f9db9; + padding : 0.4% 0.5%; + line-height : 20px; } + /* ## Advanced Page Options --------------------------------------------- */ #more_options_field { - span#draft_field {float: right;} + span#draft_field {float : right;} } -#more_options{ - overflow:hidden; + +#more_options { + overflow : hidden; } + .hemisquare { - padding: 10px; - margin: 0px 0px; - margin-left: 10px; - float: left; - width: 45%; + padding : 10px; + margin : 0px 0px; + margin-left : 10px; + float : left; + width : 45%; + &.right_side { - float: right; + float : right; } + input, textarea, select { - margin: 7px 0px; + margin : 7px 0px; } + textarea { - margin-bottom: 0px; + margin-bottom : 0px; } + label { - margin: 0px; + margin : 0px; } + small { - font-size: 0.9em; + font-size : 0.9em; } } + #content .hemisquare h2 { - margin-top: 0px; + margin-top : 0px; } + #content .hemisquare .field { - margin: 0 0 20px 0px; - width: 98%; + margin : 0 0 20px 0px; + width : 98%; } + .label_with_help { - vertical-align: middle; + vertical-align : middle; } + .label_with_help label, .label_with_help span.help, .label_with_help img.help { - display: inline; + display : inline; } + .label_with_help img.help { - vertical-align: middle; + vertical-align : middle; } + .label_with_help span.help { - font-weight: normal; - margin-left: 3px; - border-bottom: 1px dotted #727272; - cursor: help; + font-weight : normal; + margin-left : 3px; + border-bottom : 1px dotted #727272; + cursor : help; } + #more_options_field { - position: relative; + position : relative; } .nothing_selected { - width: auto; - margin-bottom: 12px; - display: inline-block; + width : auto; + margin-bottom : 12px; + display : inline-block; } + #upgrade_wrapper li a { - line-height: 20px; + line-height : 20px; } + /* resource-picker */ #resource_actions { - float: right; - margin-right: 20px; + float : right; + margin-right : 20px; } /* Locale picker */ #switch_locale_picker { - margin: 0px; - padding: 0px; + margin : 0px; + padding : 0px; + li { - float: left; - padding: 0px; - margin: 0; - list-style: none; + float : left; + padding : 0px; + margin : 0; + list-style : none; + a { - background-color: #cdcdcd; - background-position: 12px; - background-repeat: no-repeat; - border-bottom: 0; - border-right: solid 1px white; - margin-bottom: 1px; - display: block; - padding: 7px 3px 3px 3px; - line-height: 0; + background-color : #cdcdcd; + background-position : 12px; + background-repeat : no-repeat; + border-bottom : 0; + border-right : solid 1px white; + margin-bottom : 1px; + display : block; + padding : 7px 3px 3px 3px; + line-height : 0; + &:hover { - background-color: #cae7fb; + background-color : #cae7fb; } + &:active { - background-color: #22A7F2; + background-color : #22A7F2; } } + &:first-child a { - border-radius-left: 5px; - -moz-border-radius-topleft: 5px; - -moz-border-radius-bottomleft: 5px; - -webkit-border-top-left-radius: 5px; - -webkit-border-bottom-left-radius: 5px; + border-radius-left : 5px; + -moz-border-radius-topleft : 5px; + -moz-border-radius-bottomleft : 5px; + -webkit-border-top-left-radius : 5px; + -webkit-border-bottom-left-radius : 5px; } + &:last-child a { - border-radius-right: 5px; - -moz-border-radius-topright: 5px; - -moz-border-radius-bottomright: 5px; - -webkit-border-top-right-radius: 5px; - -webkit-border-bottom-right-radius: 5px; + border-radius-right : 5px; + -moz-border-radius-topright : 5px; + -moz-border-radius-bottomright : 5px; + -webkit-border-top-right-radius : 5px; + -webkit-border-bottom-right-radius : 5px; } + &.selected a { - background-color: #65c3f7; + background-color : #65c3f7; } } } + #locale_picker { li { - list-style: none; - margin: 0; + list-style : none; + margin : 0; + a { - background-color: #cdcdcd; - background-position: 12px; - background-repeat: no-repeat; - border: 0; - border-bottom: solid 1px white; - display: block; - padding: 3px 14px 3px 9px; - position: relative; + background-color : #cdcdcd; + background-position : 12px; + background-repeat : no-repeat; + border : 0; + border-bottom : solid 1px white; + display : block; + padding : 3px 14px 3px 9px; + position : relative; + &:hover { - background-color: #cae7fb; + background-color : #cae7fb; } + &:active { - background-color: #22A7F2; + background-color : #22A7F2; } + span.action { - border-bottom: 1px dotted #727272; - position: absolute; - right: 9px; - top: 5px; + border-bottom : 1px dotted #727272; + position : absolute; + right : 9px; + top : 5px; } } + &:first-child a { - border-radius-top: 5px; - -moz-border-radius-topleft: 5px; - -moz-border-radius-topright: 5px; - -webkit-border-top-left-radius: 5px; - -webkit-border-top-right-radius: 5px; + border-radius-top : 5px; + -moz-border-radius-topleft : 5px; + -moz-border-radius-topright : 5px; + -webkit-border-top-left-radius : 5px; + -webkit-border-top-right-radius : 5px; } + &:last-child a { - border-radius-bottom: 5px; - -moz-border-radius-bottomleft: 5px; - -moz-border-radius-bottomright: 5px; - -webkit-border-bottom-left-radius: 5px; - -webkit-border-bottom-right-radius: 5px; + border-radius-bottom : 5px; + -moz-border-radius-bottomleft : 5px; + -moz-border-radius-bottomright : 5px; + -webkit-border-bottom-left-radius : 5px; + -webkit-border-bottom-right-radius : 5px; } } + #current_locale, #other_locales { - margin: 0; + margin : 0; } + #current_locale li { a { - background-color: #65c3f7; + background-color : #65c3f7; } } } + .locale_marker { - font-size:8px; - display: inline; - .fa-stack .fa-comment {color: $icon_locale_colour; font-size: 24px;} + font-size : 8px; + display : inline; + + .fa-stack .fa-comment {color : $icon_locale_colour; font-size : 24px;} } #content #records .title .preview a.locale { - border-bottom: 0px none; + border-bottom : 0px none; } + /* AJAX pagination */ .pagination_container { - position: relative; + position : relative; } + .pagination_frame { - padding: 0; - width: 100%; - right: auto; - -moz-transition: all 0.3s ease-in-out; - -o-transition: all 0.3s ease-in-out; - -webkit-transition: all 0.3s ease-in-out; - transition: all 0.3s ease-in-out; + padding : 0; + width : 100%; + right : auto; + -moz-transition : all 0.3s ease-in-out; + -o-transition : all 0.3s ease-in-out; + -webkit-transition : all 0.3s ease-in-out; + transition : all 0.3s ease-in-out; } + .pagination_container > div.pagination_frame { - top: 40px; + top : 40px; } + .pagination_frame.frame_left { - left: -3000px; + left : -3000px; } + .pagination_frame.frame_right { - left: 3000px; - -moz-transition: all 0.3s ease-in-out; - -o-transition: all 0.3s ease-in-out; - -webkit-transition: all 0.3s ease-in-out; - transition: all 0.3s ease-in-out; + left : 3000px; + -moz-transition : all 0.3s ease-in-out; + -o-transition : all 0.3s ease-in-out; + -webkit-transition : all 0.3s ease-in-out; + transition : all 0.3s ease-in-out; } + .pagination_frame.frame_center { - left: 0; + left : 0; } + .pagination_frame li { - position: relative; - padding-left: 5px; + position : relative; + padding-left : 5px; } + a.information:hover { - background: #22a7f2; + background : #22a7f2; } + /* dubiously in here */ .current_image_link { - display: inline-block; - width: auto; + display : inline-block; + width : auto; } + .label { - padding: 1px 3px 2px; - font-size: 9.75px; - font-weight: bold; - color: #ffffff; - text-transform: uppercase; - white-space: nowrap; - background-color: #bfbfbf; - margin-right: 0.25em; - &.important{ - background-color: #c43c35; - } - &.warning{ - background-color: #f89406; - } - &.success{ - background-color: #46a546; - } - &.notice{ - background-color: #62cffc; + padding : 1px 3px 2px; + font-size : 9.75px; + font-weight : bold; + color : #ffffff; + text-transform : uppercase; + white-space : nowrap; + background-color : #bfbfbf; + margin-right : 0.25em; + + &.important { + background-color : #c43c35; + } + + &.warning { + background-color : #f89406; + } + + &.success { + background-color : #46a546; + } + + &.notice { + background-color : #62cffc; } } diff --git a/core/app/helpers/refinery/translation_helper.rb b/core/app/helpers/refinery/translation_helper.rb index f3d36f3cbb..5619210ee1 100644 --- a/core/app/helpers/refinery/translation_helper.rb +++ b/core/app/helpers/refinery/translation_helper.rb @@ -1,6 +1,5 @@ module Refinery module TranslationHelper - # Overrides Rails' core I18n.t() function to produce a more helpful error message. # The default one wreaks havoc with CSS and makes it hard to understand the problem. def t(key, options = {}) @@ -14,5 +13,40 @@ def t(key, options = {}) def translated_field(record, field) Refinery::TranslatedFieldPresenter.new(record).call(field) end + + # Markup for the translation links on index pages + def switch_locale(object, edit_path, field = :title) + return unless Refinery::I18n.frontend_locales.many? + + path_minus_locale = remove_locale_from_path(edit_path) + + object.translations + .sort_by { |t| Refinery::I18n.frontend_locales.index(t.locale) } + .select { |t| t.send(field).present? } + .map { |t| locale_markup(path_minus_locale, t.locale) } + .join(' ') + end + + private + + def locale_markup(path, locale) + link_to locale_marker(locale.upcase), locale_edit_path(path, locale), class: [:locale, :edit], title: locale.upcase + end + + # just adding back the switch-locale with the new locale + def locale_edit_path(path, locale) + "#{path}?switch_locale=#{locale}" + end + + def locale_marker(locale) + tag.span locale_text_icon(locale), class: [locale, :locale_marker] + end + + def remove_locale_from_path(edit_path) + uri = URI.parse(edit_path) + queries = URI.decode_www_form(uri.query || '').to_h + uri.query = queries.except('switch-locale').presence + uri.to_s + end end end diff --git a/core/spec/system/refinery/admin/xhr_paging_spec.rb b/core/spec/system/refinery/admin/xhr_paging_spec.rb index c1272f48f1..b694739ede 100644 --- a/core/spec/system/refinery/admin/xhr_paging_spec.rb +++ b/core/spec/system/refinery/admin/xhr_paging_spec.rb @@ -18,7 +18,7 @@ module Refinery it 'performs ajax paging of index' do visit refinery.admin_images_path - expect(page).to have_selector('ul#image_grid li > img', count: 1) + expect(page).to have_selector('ul#image_grid li .item > a.edit img', count: 1) expect(page).to have_css(%Q{img[alt="#{first_image.title}"]}) # placeholder which would disappear in a full page refresh. diff --git a/images/app/presenters/refinery/admin/images/collection_presenter.rb b/images/app/presenters/refinery/admin/images/collection_presenter.rb new file mode 100644 index 0000000000..e9a9040de3 --- /dev/null +++ b/images/app/presenters/refinery/admin/images/collection_presenter.rb @@ -0,0 +1,53 @@ +module Refinery + module Admin + module Images + class CollectionPresenter < Refinery::BasePresenter + include ActionView::Helpers::TagHelper + include Refinery::PaginationHelper + + attr_accessor :context, :collection, :layout, :pagination_class + delegate :group_by_date, :output_buffer, :output_buffer=, :params, :request, :t, to: :context + + def initialize(collection, view_format, context) + @collection = collection.map { |image| Refinery::Admin::Images::ImagePresenter.new(image, view_format, context) } + @context = context + @collection_id = "image_#{view_format}" + @view_format = "#{view_format}_view" + @pagination_class = context.pagination_css_class + end + + def to_html + tag.ul id: @collection_id, class: ['clearfix', 'pagination_frame', pagination_class] do + self.send(@view_format) + end + end + + def grid_view + collection.each.reduce(ActiveSupport::SafeBuffer.new) do |buffer, image| + buffer << image.to_html { image.grid_entry } + end + end + + def list_view + group_by_date(collection) + .each + .reduce(ActiveSupport::SafeBuffer.new) do |groups_buffer, (_container, image_group)| + date_time = image_group.first.created_at + date_header = tag.h3 context.l(Date.parse(date_time.to_s), format: :long) + # darn zebra striping + images = image_group.each_with_index.reduce(ActiveSupport::SafeBuffer.new) do |items_buffer, (image, index)| + items_buffer << image.to_html(index.odd?) { image.list_entry } + end + groups_buffer << [date_header, images].join(' ').html_safe + end + end + + private + + def view_classes + ['clearfix', 'pagination_frame', 'images_list', pagination_css_class] + end + end + end + end +end diff --git a/images/app/presenters/refinery/admin/images/image_presenter.rb b/images/app/presenters/refinery/admin/images/image_presenter.rb new file mode 100644 index 0000000000..492d1f9b16 --- /dev/null +++ b/images/app/presenters/refinery/admin/images/image_presenter.rb @@ -0,0 +1,117 @@ +require 'action_view/helpers/tag_helper' +require 'action_view/helpers/url_helper' + +module Refinery + module Admin + module Images + class ImagePresenter < Refinery::BasePresenter + include ActionView::Helpers::TagHelper + include ActionView::Helpers::UrlHelper + include Refinery::ImageHelper + include Refinery::TagHelper + include Refinery::TranslationHelper + + attr_accessor :image, :created_at, :context, :urls + delegate :refinery, :params, :output_buffer, :output_buffer=, :t, to: :context + delegate_missing_to :image + + def initialize(image, view_format, context) + @context = context + @created_at = image.created_at + @image = image + @urls = { + edit: refinery.edit_admin_image_path(image), + delete: refinery.admin_image_path(image), + preview: image.url + } + @view = view_format + end + + def to_html(stripe=true ) + stripe_class = stripe ? 'on' : 'on-hover' + tag.li id: "image_#{image.id}", class: stripe_class do + entry = tag.span class: :item do + [yield, *translations, image_settings].join.html_safe + end + entry << actions + end + end + + def list_entry + edit_link { image.title} + end + + def grid_entry + edit_link { context.image_fu image, '149x149#c', title: image_title, alt: image.alt } + end + + private + + def edit_link + link_to urls[:edit], class: [:edit, :title], + tooltip: t('edit', scope: 'refinery.admin.images', title: image_title) do + yield + end + end + + def image_settings + tag.span class: [:preview] do + image_information + end + end + + def actions + tag.span class: :actions do + [edit_icon, info_icon, delete_icon, preview_icon].join(' ').html_safe + end + end + + # Actions + def preview_icon + action_icon :preview, urls[:preview], t('view_live_html', scope: 'refinery.admin.images') + end + + def edit_icon + action_icon :edit, urls[:edit], t('edit', scope: 'refinery.admin.images', title: image_title) + end + + def delete_icon + delete_options = { + class: %w[cancel confirm-delete], + data: { confirm: ::I18n.t('message', scope: 'refinery.admin.delete', title: image_title) } + } + action_icon :delete, urls[:delete], t('delete', scope: 'refinery.admin.images'), delete_options + end + + def info_icon + action_icon :info, '', image_information + end + + def image_information + # give as much info as we have, but without duplication + # title, alt and filename may all be different, or any two may be the same. Only show what is different + # Title is already shown in the edit_link + # + filename = image.image_name.split('.').first + + settings = ["Title: #{title}"] + settings << "File: #{filename}" unless filename == title + settings << "Alt: #{image_alt}" unless image_alt.nil? || image_alt == filename || image_alt == title + settings << "Type: #{image.image.mime_type}" + settings << "Size: #{context.number_to_human_size(image.size)}" + settings.join(', ').html_safe + end + + def translations + if Refinery::I18n.frontend_locales.many? + tag.span class: :locales do + switch_locale(image, urls[:edit], :image_title).html_safe + end + end + end + + end + end + end +end + diff --git a/images/app/views/refinery/admin/images/_grid_view.html.erb b/images/app/views/refinery/admin/images/_grid_view.html.erb deleted file mode 100644 index eaf40f540b..0000000000 --- a/images/app/views/refinery/admin/images/_grid_view.html.erb +++ /dev/null @@ -1,16 +0,0 @@ - diff --git a/images/app/views/refinery/admin/images/_images.html.erb b/images/app/views/refinery/admin/images/_images.html.erb index 64ed047d1f..58a072a3bb 100644 --- a/images/app/views/refinery/admin/images/_images.html.erb +++ b/images/app/views/refinery/admin/images/_images.html.erb @@ -1,2 +1,9 @@ <%= will_paginate @images if Refinery::Admin::ImagesController.pageable? %> -<%= render "#{Refinery::Images.preferred_image_view}_view" %> + +<% + requested_view = Refinery::Images.preferred_image_view + presenter = Refinery::Admin::Images::CollectionPresenter.new(@images, requested_view, self) +%> +<%= presenter.to_html %> + + diff --git a/images/app/views/refinery/admin/images/_list_view_image.html.erb b/images/app/views/refinery/admin/images/_list_view_image.html.erb deleted file mode 100644 index cbe228c612..0000000000 --- a/images/app/views/refinery/admin/images/_list_view_image.html.erb +++ /dev/null @@ -1,30 +0,0 @@ -
  • - - <%= translated_field(list_view_image, :title) %> - - - <% if Refinery::I18n.frontend_locales.many? %> - - <% list_view_image.translations.sort_by{ |t| Refinery::I18n.frontend_locales.index(t.locale)}.each do |translation| %> - <% if translation.image_title.present? %> - <%= link_to refinery.edit_admin_image_path(list_view_image, switch_locale: translation.locale), - class: 'locale', title: translation.locale.upcase do %> - -
    - <%= locale_text_icon(translation.locale.upcase) %> -
    - <% end %> - <% end %> - <% end %> -
    - <% end %> - - <%= list_view_image.image_name %> - - - <%= action_icon :preview, list_view_image.url, t('view_live_html', scope: 'refinery.admin.images') %> - <%= action_icon :edit, refinery.edit_admin_image_path(list_view_image), t('edit', scope: 'refinery.admin.images') %> - <%= action_icon :delete, refinery.admin_image_path(list_view_image), t('delete', scope: 'refinery.admin.images'), class: 'confirm-delete', - data: { confirm: t('message', scope: 'refinery.admin.delete', title: list_view_image.title)} %> - -
  • diff --git a/images/config/locales/en.yml b/images/config/locales/en.yml index b6cc910d9b..9f27f0ef37 100644 --- a/images/config/locales/en.yml +++ b/images/config/locales/en.yml @@ -8,8 +8,8 @@ en: locale_picker: language: Language images: + edit: Edit %{title} delete: Remove this image forever - edit: Edit this image form: image: Image use_current_image: Use current image diff --git a/images/config/locales/fr.yml b/images/config/locales/fr.yml index 53882954ec..602d68401d 100644 --- a/images/config/locales/fr.yml +++ b/images/config/locales/fr.yml @@ -7,7 +7,7 @@ fr: admin: images: delete: Supprimer définitivement cette image - edit: Modifier cette image + edit: Modifier %{title} form: image: Image use_current_image: Utiliser l'image actuelle diff --git a/images/spec/support/shared_contexts/admin_images_tab.rb b/images/spec/support/shared_contexts/admin_images_tab.rb index 61fc059c11..a794a8d5a0 100644 --- a/images/spec/support/shared_contexts/admin_images_tab.rb +++ b/images/spec/support/shared_contexts/admin_images_tab.rb @@ -7,11 +7,12 @@ let(:dialog_frame_id) {'dialog_iframe'} let(:initial_path) { refinery.admin_images_path(view: %w(grid list).sample) } - let(:index_item_selector) {'#records li'} - let(:gridview_img_selector) {' > img'} - let(:gridview_title_selector) {'[tooltip]'} - let(:gridview_alt_selector) {'[alt]'} - let(:listview_title_selector) {' > span.title'} - let(:listview_filename_selector) {' > span.preview'} + let(:index_item_selector) {'#records li .item '} + + + let(:gridview_img_selector) {' > a > img'} + let(:gridview_title_selector) {' span.preview'} + + let(:listview_title_selector) {' > a.title'} end diff --git a/images/spec/support/shared_examples/image_deleter.rb b/images/spec/support/shared_examples/image_deleter.rb index a8ff8cf90b..8988708aa8 100644 --- a/images/spec/support/shared_examples/image_deleter.rb +++ b/images/spec/support/shared_examples/image_deleter.rb @@ -1,31 +1,22 @@ shared_examples_for 'deletes an image' do before do - raise "please set let(:initial_path)" if initial_path.blank? + raise 'please set let(:initial_path)' if initial_path.blank? ensure_on(initial_path) end let(:image_count) {[Refinery::Image.count, Refinery::Images.pages_per_admin_index].min} let(:deleting_an_image) { -> { - first("#records li").click_link(::I18n.t('delete', scope: 'refinery.admin.images')) + first('#records li').click_link(::I18n.t('delete', scope: 'refinery.admin.images')) } } - it 'has a delete image link for each image' do + it 'every image can be deleted' do expect(page).to have_selector('#records.images li a.confirm-delete', count: image_count) end - it "removes an image" do + it 'deletes an image' do expect(deleting_an_image).to change(Refinery::Image, :count).by(-1) - end - - it 'says the image has been removed' do - image_title = page.has_selector?('#image_grid') ? find("#image_grid li:first").first("img")[:title] : - find("#image_list li:first").first("span.title").text - - expect(image_title).to be_present - - first(".images_list li:first").click_link(::I18n.t('delete', scope: 'refinery.admin.images')) - expect(page).to have_content(::I18n.t('destroyed', scope: 'refinery.crudify', what: "'#{image_title}'")) + expect(page).to have_content(::I18n.t('destroyed', scope: 'refinery.crudify', what: '')) end end diff --git a/images/spec/support/shared_examples/image_indexer.rb b/images/spec/support/shared_examples/image_indexer.rb index 0dc60b06e6..9a20d9a9de 100644 --- a/images/spec/support/shared_examples/image_indexer.rb +++ b/images/spec/support/shared_examples/image_indexer.rb @@ -1,14 +1,14 @@ shared_examples_for 'indexes images' do - - let(:image_count) {[Refinery::Image.count, Refinery::Images.pages_per_admin_index].min} + let(:image_count) { [Refinery::Image.count, Refinery::Images.pages_per_admin_index].min } before do - raise "please set let(:initial_path)" if initial_path.blank? + raise 'please set let(:initial_path)' if initial_path.blank? + ensure_on(initial_path) initialize_context end - it 'shows all the images', js: true do + it 'shows images', js: true do if index_in_frame page.within_frame(dialog_frame_id) do expect(page).to have_selector(index_item_selector, count: image_count) @@ -17,79 +17,62 @@ expect(page).to have_selector(index_item_selector, count: image_count) end end - end # image index -shared_examples_for 'shows list and grid views' do - - let(:image_count) {[Refinery::Image.count, Refinery::Images.pages_per_admin_index].min} +shared_examples_for 'different views' do + let(:image_count) { [Refinery::Image.count, Refinery::Images.pages_per_admin_index].min } before do - raise "please set let(:initial_path)" if initial_path.blank? + raise 'please set let(:initial_path)' if initial_path.blank? + ensure_on(initial_path) end - context "when in grid view" do - - before { ensure_on(current_path + "?view=grid") } + context 'grid view' do + before { ensure_on(current_path + '?view=grid') } - it 'shows the images with thumbnails', js: true do + it 'shows thumbnails', js: true do expect(page).to have_selector(index_item_selector << gridview_img_selector, count: image_count) end - it 'makes the title attribute of each image available', js: true do - expect(page).to have_selector(index_item_selector << gridview_img_selector << gridview_title_selector, count: image_count) - end - - it 'makes the alt attribute of each image available', js: true do - expect(page).to have_selector(index_item_selector << gridview_img_selector << gridview_alt_selector, count: image_count) - end - - it 'has an option to switch to list view' do + it 'can switch to list view' do expect(page).to have_content(::I18n.t('switch_to', view_name: 'list', scope: 'refinery.admin.images.index.view')) end + end # grid view - end # grid view - - context "when in list view" do - - before do - ensure_on(current_path + "?view=list") - end - - it 'makes the title attribute of each image available', js: true do - expect(page).to have_selector(index_item_selector << listview_title_selector, count: image_count) + context 'list view' do + before do + ensure_on(current_path + '?view=list') end - it 'makes the filename of each image available' do - expect(page).to have_selector(index_item_selector << listview_filename_selector, count: image_count) + it 'shows image titles', js: true do + expect(page).to have_selector(index_item_selector << listview_title_selector, count: image_count) end - it 'has an option to switch to grid view' do + it 'can switch to grid view' do ensure_on(current_path + '?view=list') - expect(page).to have_content(::I18n.t('switch_to', view_name: 'grid', scope: 'refinery.admin.images.index.view')) end - - end # list view + end end shared_examples_for 'paginates the list of images' do - let(:image_count) {[Refinery::Image.count, Refinery::Images.pages_per_admin_index].min} before do - raise "please set let(:initial_path)" if initial_path.blank? + raise 'please set let(:initial_path)' if initial_path.blank? + ensure_on(initial_path) end describe 'pagination', unless: Refinery::Image.count <= 2 do - before { + before do Refinery::Images.pages_per_admin_index = 2 - Refinery::Images.pages_per_dialog_that_have_size_options = 2 } + Refinery::Images.pages_per_dialog_that_have_size_options = 2 + end it 'divides the index into pages' do - expect(page).to have_selector("div.pagination em.current") + expect(page).to have_selector('div.pagination em.current') end context 'when on the first page' do @@ -112,7 +95,6 @@ it 'has disabled the next link' do expect(page).to have_selector('.next_page.disabled') end - end - end # pagination + end # pagination end # image index diff --git a/images/spec/system/refinery/admin/images_spec.rb b/images/spec/system/refinery/admin/images_spec.rb index 1dc1b26945..2528877875 100644 --- a/images/spec/system/refinery/admin/images_spec.rb +++ b/images/spec/system/refinery/admin/images_spec.rb @@ -20,7 +20,7 @@ module Refinery include_context 'one image' it_has_behaviour 'indexes images' - it_has_behaviour 'shows list and grid views' + it_has_behaviour 'different views' it_has_behaviour 'shows an image preview' it_has_behaviour 'deletes an image' it_has_behaviour 'edits an image' @@ -32,7 +32,7 @@ module Refinery include_context 'many images' it_has_behaviour 'indexes images' - it_has_behaviour 'shows list and grid views' + it_has_behaviour 'different views' it_has_behaviour 'paginates the list of images' it_has_behaviour 'shows an image preview' it_has_behaviour 'deletes an image' From 821bfd9f16786eb236ab2efbc4d3f95e98c86d48 Mon Sep 17 00:00:00 2001 From: Anita Graham Date: Fri, 22 Jan 2021 12:52:02 +0800 Subject: [PATCH 2/4] Change github actions/workflow to use ruby/setup-ruby. actions/setup_ruby is deprecated Merge imagePresenter and collectionPresenter. Tests pass. --- Gemfile | 1 + .../refinery/sections/_layout.scss | 2 +- .../{images => }/collection_presenter.rb | 0 .../refinery/admin/image_presenter.rb | 159 ++++++++++++++++++ .../refinery/admin/images/image_presenter.rb | 117 ------------- .../refinery/admin/images/_images.html.erb | 2 +- images/config/locales/en.yml | 2 +- .../spec/support/shared_contexts/no_images.rb | 1 + .../spec/support/shared_contexts/one_image.rb | 1 + .../visual_editor_add_image.rb | 3 - .../support/shared_examples/image_uploader.rb | 35 ++-- 11 files changed, 183 insertions(+), 140 deletions(-) rename images/app/presenters/refinery/admin/{images => }/collection_presenter.rb (100%) create mode 100644 images/app/presenters/refinery/admin/image_presenter.rb delete mode 100644 images/app/presenters/refinery/admin/images/image_presenter.rb diff --git a/Gemfile b/Gemfile index 4ae7be828d..2beb628014 100644 --- a/Gemfile +++ b/Gemfile @@ -1,6 +1,7 @@ source 'https://rubygems.org' gemspec +gem 'rails', '~>6.0' path "./" do gem "refinerycms-core" diff --git a/core/app/assets/stylesheets/refinery/sections/_layout.scss b/core/app/assets/stylesheets/refinery/sections/_layout.scss index 61ba4d875f..cc34b330cb 100644 --- a/core/app/assets/stylesheets/refinery/sections/_layout.scss +++ b/core/app/assets/stylesheets/refinery/sections/_layout.scss @@ -1468,7 +1468,7 @@ ul#image_grid { .actions { position : absolute; line-height : 24px; - background-color : rgba(255, 255, 255, 0.4); + //background-color : rgba(255, 255, 255, 0.4); display : flex; flex-direction : row; flex-wrap : wrap; diff --git a/images/app/presenters/refinery/admin/images/collection_presenter.rb b/images/app/presenters/refinery/admin/collection_presenter.rb similarity index 100% rename from images/app/presenters/refinery/admin/images/collection_presenter.rb rename to images/app/presenters/refinery/admin/collection_presenter.rb diff --git a/images/app/presenters/refinery/admin/image_presenter.rb b/images/app/presenters/refinery/admin/image_presenter.rb new file mode 100644 index 0000000000..fbc21a2ca6 --- /dev/null +++ b/images/app/presenters/refinery/admin/image_presenter.rb @@ -0,0 +1,159 @@ +require 'action_view/helpers/tag_helper' +require 'action_view/helpers/url_helper' + +module Refinery + module Admin + class ImagePresenter < Refinery::BasePresenter + include ActionView::Helpers::TagHelper + include ActionView::Helpers::UrlHelper + include Refinery::ImageHelper + include Refinery::TagHelper + include Refinery::TranslationHelper + + attr_accessor :image, :created_at, :context, :urls + delegate :refinery, :params, :output_buffer, :output_buffer=, :t, to: :context + delegate_missing_to :image + + def initialize(image, context) + @context = context + @created_at = image.created_at + @image = image + @urls = { + edit: refinery.edit_admin_image_path(image), + delete: refinery.admin_image_path(image), + preview: image.url + } + end + + class << self + attr_accessor :context, :images, :view, :pagination_class + delegate :tag, :group_by_date, to: :context + + def collection(images, view_format, context) + @view = "#{view_format}_view" + @context = context + @pagination_class = context.pagination_css_class + @collection_id = "image_#{view_format}" + @images = images.map { |image| self.new(image, context) } + self + end + + def to_html + tag.ul id: @collection_id, class: ['clearfix', 'pagination_frame', pagination_class] do + self.send(@view) + end + end + + def grid_view + images.each.reduce(ActiveSupport::SafeBuffer.new) do |buffer, image| + buffer << image.to_html { image.grid_entry } + end + end + + def list_view + group_by_date(images) + .each + .reduce(ActiveSupport::SafeBuffer.new) do |groups_buffer, (_container, image_group)| + date_time = image_group.first.created_at + date_header = tag.h3 context.l(Date.parse(date_time.to_s), format: :long) + # darn zebra striping + images = image_group.each_with_index.reduce(ActiveSupport::SafeBuffer.new) do |items_buffer, (image, index)| + items_buffer << image.to_html(index.odd?) { image.list_entry } + end + groups_buffer << [date_header, images].join(' ').html_safe + end + end + + def view_classes + ['clearfix', 'pagination_frame', 'images_list', pagination_class] + end + end + + def to_html(stripe = true) + stripe_class = stripe ? 'on-hover' : 'on' + tag.li id: "image_#{image.id}", class: stripe_class do + entry = tag.span class: :item do + [yield, *translations, image_settings].join.html_safe + end + entry << actions + end + end + + def list_entry + edit_link { image.title } + end + + def grid_entry + edit_link { context.image_fu image, '149x149#c', title: image_title, alt: image.alt } + end + + private + + def edit_link + link_to urls[:edit], class: [:edit, :title], + tooltip: t('edit', scope: 'refinery.admin.images') do + yield + end + end + + def image_settings + tag.span class: [:preview] do + image_information + end + end + + def actions + tag.span class: :actions do + [edit_icon, info_icon, delete_icon, preview_icon].join(' ').html_safe + end + end + + # Actions + def preview_icon + action_icon :preview, urls[:preview], t('view_live_html', scope: 'refinery.admin.images') + end + + def edit_icon + action_icon :edit, urls[:edit], t('edit', scope: 'refinery.admin.images', title: image_title) + end + + def delete_icon + delete_options = { + class: %w[cancel confirm-delete], + data: { confirm: ::I18n.t('message', scope: 'refinery.admin.delete', title: image_title) } + } + action_icon :delete, urls[:delete], t('delete', scope: 'refinery.admin.images'), delete_options + end + + def info_icon + action_icon :info, '', image_information + end + + def image_information + # give as much info as we have, but without duplication + # title, alt and filename may all be different, or any two may be the same. Only show what is different + # Title is already shown in the edit_link + # + filename = image.image_name.split('.').first + + settings = ["Title: #{title}"] + settings << "File: #{filename}" unless filename == title + settings << "Alt: #{image_alt}" unless image_alt.nil? || image_alt == filename || image_alt == title + settings << "Type: #{image.image.mime_type}" + settings << "Size: #{context.number_to_human_size(image.size)}" + settings.join(', ').html_safe + end + + def translations + if Refinery::I18n.frontend_locales.many? + tag.span class: :locales do + switch_locale(image, urls[:edit], :image_title).html_safe + end + end + end + + end + end +end + + diff --git a/images/app/presenters/refinery/admin/images/image_presenter.rb b/images/app/presenters/refinery/admin/images/image_presenter.rb deleted file mode 100644 index 492d1f9b16..0000000000 --- a/images/app/presenters/refinery/admin/images/image_presenter.rb +++ /dev/null @@ -1,117 +0,0 @@ -require 'action_view/helpers/tag_helper' -require 'action_view/helpers/url_helper' - -module Refinery - module Admin - module Images - class ImagePresenter < Refinery::BasePresenter - include ActionView::Helpers::TagHelper - include ActionView::Helpers::UrlHelper - include Refinery::ImageHelper - include Refinery::TagHelper - include Refinery::TranslationHelper - - attr_accessor :image, :created_at, :context, :urls - delegate :refinery, :params, :output_buffer, :output_buffer=, :t, to: :context - delegate_missing_to :image - - def initialize(image, view_format, context) - @context = context - @created_at = image.created_at - @image = image - @urls = { - edit: refinery.edit_admin_image_path(image), - delete: refinery.admin_image_path(image), - preview: image.url - } - @view = view_format - end - - def to_html(stripe=true ) - stripe_class = stripe ? 'on' : 'on-hover' - tag.li id: "image_#{image.id}", class: stripe_class do - entry = tag.span class: :item do - [yield, *translations, image_settings].join.html_safe - end - entry << actions - end - end - - def list_entry - edit_link { image.title} - end - - def grid_entry - edit_link { context.image_fu image, '149x149#c', title: image_title, alt: image.alt } - end - - private - - def edit_link - link_to urls[:edit], class: [:edit, :title], - tooltip: t('edit', scope: 'refinery.admin.images', title: image_title) do - yield - end - end - - def image_settings - tag.span class: [:preview] do - image_information - end - end - - def actions - tag.span class: :actions do - [edit_icon, info_icon, delete_icon, preview_icon].join(' ').html_safe - end - end - - # Actions - def preview_icon - action_icon :preview, urls[:preview], t('view_live_html', scope: 'refinery.admin.images') - end - - def edit_icon - action_icon :edit, urls[:edit], t('edit', scope: 'refinery.admin.images', title: image_title) - end - - def delete_icon - delete_options = { - class: %w[cancel confirm-delete], - data: { confirm: ::I18n.t('message', scope: 'refinery.admin.delete', title: image_title) } - } - action_icon :delete, urls[:delete], t('delete', scope: 'refinery.admin.images'), delete_options - end - - def info_icon - action_icon :info, '', image_information - end - - def image_information - # give as much info as we have, but without duplication - # title, alt and filename may all be different, or any two may be the same. Only show what is different - # Title is already shown in the edit_link - # - filename = image.image_name.split('.').first - - settings = ["Title: #{title}"] - settings << "File: #{filename}" unless filename == title - settings << "Alt: #{image_alt}" unless image_alt.nil? || image_alt == filename || image_alt == title - settings << "Type: #{image.image.mime_type}" - settings << "Size: #{context.number_to_human_size(image.size)}" - settings.join(', ').html_safe - end - - def translations - if Refinery::I18n.frontend_locales.many? - tag.span class: :locales do - switch_locale(image, urls[:edit], :image_title).html_safe - end - end - end - - end - end - end -end - diff --git a/images/app/views/refinery/admin/images/_images.html.erb b/images/app/views/refinery/admin/images/_images.html.erb index 58a072a3bb..97ef942e8e 100644 --- a/images/app/views/refinery/admin/images/_images.html.erb +++ b/images/app/views/refinery/admin/images/_images.html.erb @@ -2,7 +2,7 @@ <% requested_view = Refinery::Images.preferred_image_view - presenter = Refinery::Admin::Images::CollectionPresenter.new(@images, requested_view, self) + presenter = Refinery::Admin::ImagePresenter.collection(@images, requested_view, self) %> <%= presenter.to_html %> diff --git a/images/config/locales/en.yml b/images/config/locales/en.yml index 9f27f0ef37..cd3a434e73 100644 --- a/images/config/locales/en.yml +++ b/images/config/locales/en.yml @@ -8,7 +8,7 @@ en: locale_picker: language: Language images: - edit: Edit %{title} + edit: Edit this image delete: Remove this image forever form: image: Image diff --git a/images/spec/support/shared_contexts/no_images.rb b/images/spec/support/shared_contexts/no_images.rb index 35297b2ad6..472ac9616b 100644 --- a/images/spec/support/shared_contexts/no_images.rb +++ b/images/spec/support/shared_contexts/no_images.rb @@ -1,3 +1,4 @@ shared_context "no existing images" do + Refinery::Image.delete_all let(:image) { FactoryBot.create(:image) } end diff --git a/images/spec/support/shared_contexts/one_image.rb b/images/spec/support/shared_contexts/one_image.rb index a9cef818d6..ddff210541 100644 --- a/images/spec/support/shared_contexts/one_image.rb +++ b/images/spec/support/shared_contexts/one_image.rb @@ -1,3 +1,4 @@ shared_context "one image" do + Refinery::Image.delete_all let!(:image) { FactoryBot.create(:image) } end diff --git a/images/spec/support/shared_contexts/visual_editor_add_image.rb b/images/spec/support/shared_contexts/visual_editor_add_image.rb index b91f3c4158..9cc5cf9797 100644 --- a/images/spec/support/shared_contexts/visual_editor_add_image.rb +++ b/images/spec/support/shared_contexts/visual_editor_add_image.rb @@ -16,9 +16,6 @@ let(:initial_path) { refinery.edit_admin_page_path(page_for_image) } - # let(:target_image) { find(:xpath, "//img[@title='Beach']")} - # let(:url){target_image["data-#{size}"]} - let(:index_in_frame) {true} let(:dialog_frame_id) {'dialog_frame'} let(:index_item_selector) {'#existing_image_area_content ul li img'} diff --git a/images/spec/support/shared_examples/image_uploader.rb b/images/spec/support/shared_examples/image_uploader.rb index a55f6d4583..08c9958aac 100644 --- a/images/spec/support/shared_examples/image_uploader.rb +++ b/images/spec/support/shared_examples/image_uploader.rb @@ -1,37 +1,38 @@ shared_examples 'uploads images' do before do - raise "please set let(:initial_path)" if initial_path.blank? + raise 'please set let(:initial_path)' if initial_path.blank? + ensure_on(initial_path) initialize_context end - let(:uploading_an_image) { - ->{ - open_upload_dialog - page.within_frame(dialog_frame_id) do - select_upload - attach_file 'image_image', image_path - fill_in 'image_image_title', with: 'Image With Dashes' - fill_in 'image_image_alt', with: "Alt description for image" - click_button ::I18n.t('save', scope: 'refinery.admin.form_actions') - end + let(:uploading_an_image) do + ->{ + open_upload_dialog + page.within_frame(dialog_frame_id) do + select_upload + attach_file 'image_image', image_path + fill_in 'image_image_title', with: 'Image With Dashes' + fill_in 'image_image_alt', with: 'Alt description for image' + click_button ::I18n.t('save', scope: 'refinery.admin.form_actions') + end } - } + end context 'when the image type is acceptable' do - let(:image_path) {Refinery.roots('refinery/images').join("spec/fixtures/image-with-dashes.jpg")} - it 'the image is uploaded', :js => true do + let(:image_path) { Refinery.roots('refinery/images').join('spec/fixtures/image-with-dashes.jpg')} + it 'the image is uploaded', js: true do expect(uploading_an_image).to change(Refinery::Image, :count).by(1) end end context 'when the image type is not acceptable' do - let(:image_path) {Refinery.roots('refinery/images').join("spec/fixtures/cape-town-tide-table.pdf")} - it 'the image is rejected', :js => true do + let(:image_path) {Refinery.roots('refinery/images').join('spec/fixtures/cape-town-tide-table.pdf')} + it 'the image is rejected', js: true do expect(uploading_an_image).to_not change(Refinery::Image, :count) page.within_frame(dialog_frame_id) do expect(page).to have_content(::I18n.t('incorrect_format', - :scope => 'activerecord.errors.models.refinery/image', + scope: 'activerecord.errors.models.refinery/image', actual: 'application/pdf', valid_types: 'image/jpeg, image/png, image/gif or image/tiff')) end From 820b1b9dd21026a149b491deb66d5fdd3cf13e02 Mon Sep 17 00:00:00 2001 From: Anita Graham Date: Mon, 26 Apr 2021 11:45:34 +0800 Subject: [PATCH 3/4] Use safe navigation when getting titles --- core/app/helpers/refinery/meta_helper.rb | 2 +- images/app/views/refinery/admin/images/_form.html.erb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/app/helpers/refinery/meta_helper.rb b/core/app/helpers/refinery/meta_helper.rb index 712dd98ebb..77dabfdc0c 100644 --- a/core/app/helpers/refinery/meta_helper.rb +++ b/core/app/helpers/refinery/meta_helper.rb @@ -21,7 +21,7 @@ def page_title(options = {}) objects = (options[:chain_page_title] and object.respond_to?(:ancestors)) ? [object.ancestors, object] : [object] objects.flatten.compact.each do |obj| - obj_title = obj.title if obj.title + obj_title = obj&.title.presence # Only link when the object responds to a url method. if options[:link] && obj.respond_to?(:url) diff --git a/images/app/views/refinery/admin/images/_form.html.erb b/images/app/views/refinery/admin/images/_form.html.erb index bdcdf4dca5..0f9d75dbe8 100644 --- a/images/app/views/refinery/admin/images/_form.html.erb +++ b/images/app/views/refinery/admin/images/_form.html.erb @@ -113,4 +113,4 @@ <% end %> <% content_for :stylesheets, stylesheet_link_tag('cropper') -%> -<% end %> \ No newline at end of file +<% end %> From 3ff13600eb67e33748e8c52d3328e5916789883e Mon Sep 17 00:00:00 2001 From: Anita Graham Date: Mon, 18 Oct 2021 14:20:54 +0800 Subject: [PATCH 4/4] Reflect suggestions and changes from refinery/master --- images/app/presenters/refinery/admin/image_presenter.rb | 1 - images/app/views/refinery/admin/images/_images.html.erb | 9 +-------- images/spec/support/shared_contexts/no_images.rb | 1 - images/spec/support/shared_contexts/one_image.rb | 1 - 4 files changed, 1 insertion(+), 11 deletions(-) diff --git a/images/app/presenters/refinery/admin/image_presenter.rb b/images/app/presenters/refinery/admin/image_presenter.rb index fbc21a2ca6..0dd167eed1 100644 --- a/images/app/presenters/refinery/admin/image_presenter.rb +++ b/images/app/presenters/refinery/admin/image_presenter.rb @@ -151,7 +151,6 @@ def translations end end end - end end end diff --git a/images/app/views/refinery/admin/images/_images.html.erb b/images/app/views/refinery/admin/images/_images.html.erb index 97ef942e8e..108f31008f 100644 --- a/images/app/views/refinery/admin/images/_images.html.erb +++ b/images/app/views/refinery/admin/images/_images.html.erb @@ -1,9 +1,2 @@ <%= will_paginate @images if Refinery::Admin::ImagesController.pageable? %> - -<% - requested_view = Refinery::Images.preferred_image_view - presenter = Refinery::Admin::ImagePresenter.collection(@images, requested_view, self) -%> -<%= presenter.to_html %> - - +<%= Refinery::Admin::ImagePresenter.collection(@images, Refinery::Images.preferred_image_view, self).to_html %> diff --git a/images/spec/support/shared_contexts/no_images.rb b/images/spec/support/shared_contexts/no_images.rb index 472ac9616b..35297b2ad6 100644 --- a/images/spec/support/shared_contexts/no_images.rb +++ b/images/spec/support/shared_contexts/no_images.rb @@ -1,4 +1,3 @@ shared_context "no existing images" do - Refinery::Image.delete_all let(:image) { FactoryBot.create(:image) } end diff --git a/images/spec/support/shared_contexts/one_image.rb b/images/spec/support/shared_contexts/one_image.rb index ddff210541..a9cef818d6 100644 --- a/images/spec/support/shared_contexts/one_image.rb +++ b/images/spec/support/shared_contexts/one_image.rb @@ -1,4 +1,3 @@ shared_context "one image" do - Refinery::Image.delete_all let!(:image) { FactoryBot.create(:image) } end