Fixes #2598 - RTL writing system support in Public KB

This commit is contained in:
Mantas Masalskis 2020-04-20 13:28:53 +02:00 committed by Thorsten Eckel
parent 880f1d5e3a
commit 5bcb650b54
13 changed files with 122 additions and 63 deletions

View file

@ -11,13 +11,16 @@ class App.KnowledgeBaseSearchItem extends App.Controller
@render() @render()
data: -> data: ->
extraAttributes = @object.parent().attributesForRendering(App.KnowledgeBaseLocale.localeFor(@object))
output = @details || {} output = @details || {}
output['url'] = @object?.uiUrl("search-return/#{@pathSuffix}") || '#' output.url = @object?.uiUrl("search-return/#{@pathSuffix}") || '#'
output['state'] = @object.parent().attributesForRendering(App.KnowledgeBaseLocale.localeFor(@object)).state output.state = extraAttributes.state
output.iconFont = extraAttributes.iconFont
output output
render: -> render: ->
@html App.view('knowledge_base/search_item')(data: @data()) @html App.view('knowledge_base/search_item')(data: @data(), iconset: @object.parent().knowledge_base().iconset)
searchLinkClicked: -> # setup history and let it continue, no need to prevent default action or bubbling searchLinkClicked: -> # setup history and let it continue, no need to prevent default action or bubbling
if window.history? and @return_path? if window.history? and @return_path?

View file

@ -232,3 +232,10 @@ App.ViewHelpers =
replacePlaceholder: (template, items, encodeLink = false) -> replacePlaceholder: (template, items, encodeLink = false) ->
App.Utils.replaceTags(template, items, encodeLink) App.Utils.replaceTags(template, items, encodeLink)
# prints value depending on direction of active locale
dir: (ltr, rtl) ->
if App.i18n.dir() == 'ltr'
ltr
else
rtl

View file

@ -1,6 +1,7 @@
<% if @previousAnswer: %> <% if @previousAnswer: %>
<a href="<%- @previousAnswer.url %>" class="knowledge-base-article-nav-link knowledge-base-article-nav-link--prev"> <a href="<%- @previousAnswer.url %>" class="knowledge-base-article-nav-link knowledge-base-article-nav-link--prev">
<%- @Icon('arrow-left') %> <%- @Icon('arrow-left') %>
<div class="spacer"></div>
<span class="knowledge-base-article-nav-link-title"><%= @previousAnswer.title %></span> <span class="knowledge-base-article-nav-link-title"><%= @previousAnswer.title %></span>
</a> </a>
<% end %> <% end %>
@ -8,6 +9,7 @@
<% if @nextAnswer: %> <% if @nextAnswer: %>
<a href="<%- @nextAnswer.url %>" class="knowledge-base-article-nav-link knowledge-base-article-nav-link--next"> <a href="<%- @nextAnswer.url %>" class="knowledge-base-article-nav-link knowledge-base-article-nav-link--next">
<span class="knowledge-base-article-nav-link-title"><%= @nextAnswer.title %></span> <span class="knowledge-base-article-nav-link-title"><%= @nextAnswer.title %></span>
<div class="spacer"></div>
<%- @Icon('arrow-right') %> <%- @Icon('arrow-right') %>
</a> </a>
<% end %> <% end %>

View file

@ -36,7 +36,7 @@
<div class="btn btn--action btn--split--last btn--slim centered" data-toggle="dropdown" aria-expanded="false"> <div class="btn btn--action btn--split--last btn--slim centered" data-toggle="dropdown" aria-expanded="false">
<%- @Icon('arrow-down') %> <%- @Icon('arrow-down') %>
</div> </div>
<ul class="dropdown-menu dropdown-menu-right dropdown-menu-full-height" role="menu"> <ul class="dropdown-menu dropdown-menu-<%= @dir('right', 'left') %> dropdown-menu-full-height" role="menu">
<% for locale in @kbLocales.collection: %> <% for locale in @kbLocales.collection: %>
<li role="presentation"> <li role="presentation">
<a href="<%= locale.url %>" role="menuitem" tabindex="-1"> <a href="<%= locale.url %>" role="menuitem" tabindex="-1">

View file

@ -3,6 +3,7 @@
<% if @search_return_url: %> <% if @search_return_url: %>
<a href="<%= @search_return_url %>" class="knowledge-base-article-nav-link knowledge-base-article-nav-link--prev"> <a href="<%= @search_return_url %>" class="knowledge-base-article-nav-link knowledge-base-article-nav-link--prev">
<%- @Icon('arrow-left') %> <%- @Icon('arrow-left') %>
<div class="spacer"></div>
<span class="knowledge-base-article-nav-link-title"><%- @T('Back to search results') %></span> <span class="knowledge-base-article-nav-link-title"><%- @T('Back to search results') %></span>
</a> </a>
<% end %> <% end %>

View file

@ -41,6 +41,7 @@
' <p class="language-banner-text">' + ' <p class="language-banner-text">' +
' The Knowledge Base is available in your language <a class="button button--small">activate</a>' + ' The Knowledge Base is available in your language <a class="button button--small">activate</a>' +
' </p>' + ' </p>' +
' <div class="spacer"></div>' +
' <div class="close">' + ' <div class="close">' +
Zammad.Util.generateIcon('diagonal-cross') + Zammad.Util.generateIcon('diagonal-cross') +
' </div>' + ' </div>' +

View file

@ -117,8 +117,10 @@
SearchResultElement.template = '<a>' + SearchResultElement.template = '<a>' +
' <span class="result-icon"></span>' + ' <span class="result-icon"></span>' +
' <h3 class="result-title"></h3>' + ' <h3 class="result-title"></h3>' +
' <span class="result-category"></span>' + ' <div class="result-subtitle">' +
' <span class="result-preview"></span>' + ' <span class="result-category"></span>' +
' <span class="result-preview"></span>' +
' </div>' +
'</a>'; '</a>';
function SearchResultMessage(data) { function SearchResultMessage(data) {

View file

@ -164,11 +164,6 @@ ol {
} }
} }
ul,
ol {
padding-left: 1.5em;
}
strong, strong,
b { b {
font-weight: 500; font-weight: 500;
@ -206,7 +201,7 @@ b {
&-tag { &-tag {
font-weight: bold; font-weight: bold;
margin-right: 17px; @include bidi-style(margin-right, 17px, margin-left, 0px);
text-transform: uppercase; text-transform: uppercase;
letter-spacing: 0.05em; letter-spacing: 0.05em;
} }
@ -215,9 +210,8 @@ b {
font-size: 13px; font-size: 13px;
} }
&-controls { &-flex {
margin-left: auto; margin: auto;
display: flex;
} }
&-btn { &-btn {
@ -315,7 +309,8 @@ b {
background: white; background: white;
border: 1px solid $border; border: 1px solid $border;
border-radius: 999px; border-radius: 999px;
padding: .75em 1.1em .75em 2.8em; @include ltr(padding, .75em 1.1em .75em 2.8em);
@include rtl(padding, .75em 2.8em .75em 1.1em);
outline: none; outline: none;
font-weight: 300; font-weight: 300;
@ -327,7 +322,7 @@ b {
.icon { .icon {
position: absolute; position: absolute;
left: 1.1em; @include bidi-style(left, 1.1em, right, inherit);
top: 50%; top: 50%;
margin-top: -.54em; margin-top: -.54em;
fill: $dark-color; fill: $dark-color;
@ -339,6 +334,8 @@ b {
&-results { &-results {
list-style: none; list-style: none;
padding: .5em 0 0; padding: .5em 0 0;
padding-right: 0;
padding-left: 0;
.section { .section {
margin-bottom: 2px; margin-bottom: 2px;
@ -363,7 +360,7 @@ b {
border: 1px solid transparent; border: 1px solid transparent;
border-radius: 3px; border-radius: 3px;
padding: .8em; padding: .8em;
padding-left: 2.75em; @include bidi-style(padding-left, 2.75em, padding-right, 0.8em);
position: relative; position: relative;
&:hover { &:hover {
@ -374,7 +371,7 @@ b {
&-icon { &-icon {
position: absolute; position: absolute;
left: .6em; @include bidi-style(left, .6em, right, 0em);
top: .6em; top: .6em;
color: hsl(210,22%,84%); color: hsl(210,22%,84%);
@ -400,6 +397,7 @@ b {
&-category { &-category {
color: $subtle-color; color: $subtle-color;
display: inline-block;
&:after { &:after {
content: ""; content: "";
@ -441,6 +439,11 @@ b {
flex: 1 1 auto; flex: 1 1 auto;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
ul,
ol {
@include bidi-style(padding-left, 1.5em, padding-right, 0);
}
} }
} }
@ -497,7 +500,8 @@ b {
.breadcrumb { .breadcrumb {
position: relative; position: relative;
padding: 6px 20px 6px 11px; @include ltr(padding, 6px 20px 6px 11px);
@include rtl(padding, 6px 11px 6px 20px);
color: inherit; color: inherit;
text-decoration: none; text-decoration: none;
white-space: nowrap; white-space: nowrap;
@ -526,24 +530,28 @@ b {
} }
} }
&:before, &:after,
&:after { &:before {
content: ""; content: "";
position: absolute; position: absolute;
width: 1px; width: 1px;
height: 40%; height: 40%;
background: $color; background: $color;
opacity: .2; opacity: .2;
right: 0; @include ltr(right, 0);
@include rtl(left, 0);
top: 0; top: 0;
transform-origin: bottom; transform-origin: bottom;
transform: translateY(13%) rotate(-37deg);
@include ltr(transform, translateY(13%) rotate(-37deg));
@include rtl(transform, translateY(13%) rotate(37deg));
} }
&:after { &:after {
top: 50%; top: 50%;
transform-origin: top; transform-origin: top;
transform: translateY(-13%) rotate(37deg); @include ltr(transform, translateY(-13%) rotate(37deg));
@include rtl(transform, translateY(-13%) rotate(-37deg));
} }
.icon { .icon {
@ -561,7 +569,7 @@ b {
.icon, .icon,
[data-font] { [data-font] {
margin-right: 3px; @include bidi-style(margin-right, 3px, margin-left, 0px);
vertical-align: middle; vertical-align: middle;
opacity: .75; opacity: .75;
} }
@ -634,7 +642,7 @@ b {
} }
.not-published-note { .not-published-note {
margin-left: .5em; @include bidi-style(margin-left, .5em, margin-right, 0px);
margin-top: .5em; margin-top: .5em;
} }
} }
@ -793,7 +801,8 @@ b {
.section-inner & { .section-inner & {
color: $highlight-color; color: $highlight-color;
fill: currentColor; fill: currentColor;
margin: 4px 9px 0 3px; @include ltr(margin, 4px 9px 0 3px);
@include rtl(margin, 4px 3px 0 9px);
line-height: inherit; line-height: inherit;
flex-shrink: 0; flex-shrink: 0;
} }
@ -1043,7 +1052,7 @@ b {
align-items: center; align-items: center;
.icon { .icon {
margin: 0 5px 0 -2px; @include bidi-style(margin, 0 5px 0 -2px, margin, 0 -2px 0 5px);
fill: currentColor; fill: currentColor;
&:only-child { &:only-child {
@ -1051,7 +1060,7 @@ b {
} }
&:last-child { &:last-child {
margin: 0 -2px 0 7px; @include bidi-style(margin, 0 -2px 0 7px, margin, 0 7px 0 -2px);
} }
} }
@ -1192,7 +1201,7 @@ b {
.icon { .icon {
display: none; display: none;
margin-right: 7px; @include bidi-style(margin-right, 7px, margin-left, 0px);
vertical-align: middle; vertical-align: middle;
} }
} }
@ -1221,12 +1230,16 @@ b {
fill: currentColor; fill: currentColor;
width: 22px; width: 22px;
height: 22px; height: 22px;
margin: 8px 2px 0 10px; @include ltr(margin, 8px 2px 0 10px);
@include rtl(margin, 8px 10px 0 2px);
vertical-align: middle; vertical-align: middle;
} }
.spacer {
margin: auto;
}
.close { .close {
margin-left: auto;
padding: 7px 5px 0; padding: 7px 5px 0;
fill: currentColor; fill: currentColor;
width: 34px; width: 34px;

View file

@ -469,7 +469,8 @@ pre code.hljs {
min-width: 0; min-width: 0;
.icon { .icon {
margin: -2px 5px 0 -2px; @include ltr(margin, -2px 5px 0 -2px);
@include rtl(margin, -2px -2px 0 5px);
} }
.icon:only-child { .icon:only-child {
@ -610,7 +611,10 @@ pre code.hljs {
.icon { .icon {
opacity: 1; opacity: 1;
margin-right: 6px; @include ltr(margin-right, 6px);
@include ltr(margin-left, -2px);
@include rtl(margin-right, -2px);
@include rtl(margin-left, 6px);
width: 16px; width: 16px;
max-height: 16px; max-height: 16px;
object-fit: contain; object-fit: contain;
@ -10518,15 +10522,20 @@ output {
&-menu { &-menu {
display: flex; display: flex;
margin-left: auto; @include ltr(margin-left, auto);
padding-left: 20px; @include rtl(margin-right, auto);
@include bidi-style(padding-left, 20px, padding-right, 0);
} }
} }
.breadcrumb { .breadcrumb {
position: relative; position: relative;
padding: 11px 13px 8px; padding-top: 11px;
padding-right: 21px; padding-bottom: 8px;
@include ltr(padding-right, 21px);
@include ltr(padding-left, 13px);
@include rtl(padding-left, 21px);
@include rtl(padding-right, 13px);
color: inherit; color: inherit;
cursor: pointer; cursor: pointer;
@extend .u-textTruncate; @extend .u-textTruncate;
@ -10539,16 +10548,19 @@ output {
height: 50%; height: 50%;
background: currentColor; background: currentColor;
opacity: .33; opacity: .33;
right: 0; @include ltr(right, 0);
@include rtl(left, 0);
top: 0; top: 0;
transform-origin: bottom; transform-origin: bottom;
transform: rotate(-37deg); @include ltr(transform, rotate(-37deg));
@include rtl(transform, rotate(37deg));
} }
&:after { &:after {
top: 50%; top: 50%;
transform-origin: top; transform-origin: top;
transform: rotate(37deg); @include ltr(transform, rotate(37deg));
@include rtl(transform, rotate(-37deg));
} }
&:last-child { &:last-child {
@ -10559,7 +10571,7 @@ output {
} }
.modified-icon { .modified-icon {
margin-right: 3px; @include bidi-style(margin-right, 3px, margin-left, 0);
display: inline-block; display: inline-block;
vertical-align: middle; vertical-align: middle;
line-height: 1; line-height: 1;
@ -11230,7 +11242,8 @@ span.is-disabled {
&-sidebar { &-sidebar {
position: absolute; position: absolute;
right: 0; @include ltr(right, 0);
@include rtl(left, 0);
top: 0; top: 0;
width: 280px; width: 280px;
height: 100%; height: 100%;
@ -11245,10 +11258,12 @@ span.is-disabled {
&.hidden { &.hidden {
display: block !important; display: block !important;
visibility: visible !important; visibility: visible !important;
transform: translateX(100%); @include ltr(transform, translateX(100%));
@include rtl(transform, translateX(-100%));
+ .knowledge-base-main { + .knowledge-base-main {
margin-right: 0; @include ltr(margin-right, 0);
@include rtl(margin-left, 0);
} }
} }
@ -11259,11 +11274,14 @@ span.is-disabled {
} }
&-main { &-main {
transition: margin-right 500ms; @include ltr(transition, margin-right 500ms);
margin-right: 280px; @include ltr(margin-right, 280px);
@include rtl(transition, margin-left 500ms);
@include rtl(margin-left, 280px);
@include desktop { @include desktop {
margin-right: 28%; @include ltr(margin-right, 28%);
@include rtl(margin-left, 28%);
} }
} }
@ -11459,11 +11477,13 @@ span.is-disabled {
flex-shrink: 0; flex-shrink: 0;
&-holder { &-holder {
margin-right: 11px; @include ltr(margin-right, 11px);
@include rtl(margin-left, 11px);
margin-top: 1px; margin-top: 1px;
.nav-pills & { .nav-pills & {
margin-right: 7px; @include ltr(margin-right, 7px);
@include rtl(margin-left, 7px);
} }
} }
@ -11521,22 +11541,21 @@ span.is-disabled {
padding: 15px; padding: 15px;
max-width: 50%; max-width: 50%;
display: flex; display: flex;
align-items: center;
.spacer {
width: 5px
}
.icon { .icon {
flex-shrink: 0; flex-shrink: 0;
fill: currentColor; fill: currentColor;
opacity: 1; opacity: 1;
margin: 2px 5px 0 0;
vertical-align: top; vertical-align: top;
} }
&--next { &--next {
margin-left: auto; @include bidi-style(margin-left, auto, margin-right, inherit);
.icon {
margin-right: 0;
margin-left: 5px;
}
} }
&-title { &-title {

View file

@ -61,4 +61,8 @@ module KnowledgeBaseHelper
.build(host: host, scheme: scheme, port: port, fragment: path) .build(host: host, scheme: scheme, port: port, fragment: path)
.to_s .to_s
end end
def dropdown_menu_direction
system_locale_via_uri.dir == 'ltr' ? 'right' : 'left'
end
end end

View file

@ -1,4 +1,8 @@
<style> <style>
html {
direction: <%= locale.dir ;%>
}
@font-face { @font-face {
font-family: '<%= knowledge_base.iconset %>'; font-family: '<%= knowledge_base.iconset %>';
src: url('/assets/icon-fonts/<%= knowledge_base.iconset %>.woff'); src: url('/assets/icon-fonts/<%= knowledge_base.iconset %>.woff');

View file

@ -8,6 +8,7 @@
<%= time_tag object.published_at %> <%= time_tag object.published_at %>
<% end %> <% end %>
</span> </span>
<div class="topbar-flex"></div>
<div class="topbar-controls"> <div class="topbar-controls">
<%= link_to zt(edit_kb_link_label(object)), build_kb_link(object), class: 'topbar-btn', target: :_blank %> <%= link_to zt(edit_kb_link_label(object)), build_kb_link(object), class: 'topbar-btn', target: :_blank %>
</div> </div>

View file

@ -1,5 +1,7 @@
<!DOCTYPE HTML> <!DOCTYPE HTML>
<html lang="<%= system_locale_via_uri.locale %>" <html lang="<%= system_locale_via_uri.locale %>"
dir="<%= system_locale_via_uri.dir %>"
adir="ltr"
data-id='<%= @knowledge_base.id %>' data-id='<%= @knowledge_base.id %>'
data-iconset='<%= @knowledge_base.iconset %>' data-iconset='<%= @knowledge_base.iconset %>'
data-available-locales='<%= all_locales.map(&:locale).join(',') %>' data-available-locales='<%= all_locales.map(&:locale).join(',') %>'
@ -10,7 +12,7 @@
<title><%= kb_public_page_title(@knowledge_base, @object, @page_title_error) %></title> <title><%= kb_public_page_title(@knowledge_base, @object, @page_title_error) %></title>
<meta name="viewport" content="width=device-width,initial-scale=1.0,viewport-fit=cover"> <meta name="viewport" content="width=device-width,initial-scale=1.0,viewport-fit=cover">
<%= stylesheet_link_tag "knowledge_base.css", :media => 'all' %> <%= stylesheet_link_tag "knowledge_base.css", :media => 'all' %>
<%= render 'knowledge_base/public/inline_stylesheet', knowledge_base: @knowledge_base %> <%= render 'knowledge_base/public/inline_stylesheet', knowledge_base: @knowledge_base, locale: system_locale_via_uri %>
<div class="wrapper js-wrapper"> <div class="wrapper js-wrapper">
<%= render 'knowledge_base/public/top_banner', object: @object || @knowledge_base if editor? %> <%= render 'knowledge_base/public/top_banner', object: @object || @knowledge_base if editor? %>
@ -54,7 +56,7 @@
<%= system_locale_via_uri.name %> <%= system_locale_via_uri.name %>
<%= icon 'arrow-down' %> <%= icon 'arrow-down' %>
</a> </a>
<ul class="dropdown-menu dropdown-menu-right dropdown-menu-up" role="menu"> <ul class="dropdown-menu dropdown-menu-<%= dropdown_menu_direction %> dropdown-menu-up" role="menu">
<% @object_locales&.each do |locale| %> <% @object_locales&.each do |locale| %>
<li class="<%= 'is-selected' if locale.name == system_locale_via_uri.name %>"> <li class="<%= 'is-selected' if locale.name == system_locale_via_uri.name %>">
<%= link_to custom_path_if_needed(url_for(locale: locale.locale), @knowledge_base), hreflang: locale.locale do %> <%= link_to custom_path_if_needed(url_for(locale: locale.locale), @knowledge_base), hreflang: locale.locale do %>