Add a locale selector
This commit is contained in:
parent
cf9831c0af
commit
6bdb7703c2
20 changed files with 9073 additions and 1 deletions
|
@ -41,4 +41,12 @@ folder 'vendor/assets' do
|
|||
file 'iD.js', 'dist/iD.js'
|
||||
end
|
||||
end
|
||||
|
||||
folder 'jquery.uls' do
|
||||
from 'https://github.com/wikimedia/jquery.uls.git' do
|
||||
folder 'css'
|
||||
folder 'src'
|
||||
folder 'images'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
//= require i18n
|
||||
//= require matomo
|
||||
//= require richtext
|
||||
//= require uls
|
||||
|
||||
{
|
||||
const application_data = $("head").data();
|
||||
|
|
|
@ -28,6 +28,7 @@ OSM = {
|
|||
%>,
|
||||
|
||||
DEFAULT_LOCALE: <%= I18n.default_locale.to_json %>,
|
||||
AVAILABLE_LOCALES: <%= I18n.available_locales.map(&:to_s).to_json %>,
|
||||
|
||||
LAYER_DEFINITIONS: <%= YAML.load_file(Rails.root.join("config/layers.yml")).to_json %>,
|
||||
LAYERS_WITH_MAP_KEY: <%= YAML.load_file(Rails.root.join("config/key.yml")).keys.to_json %>,
|
||||
|
|
30
app/assets/javascripts/uls.js
Normal file
30
app/assets/javascripts/uls.js
Normal file
|
@ -0,0 +1,30 @@
|
|||
//= require src/jquery.uls.data
|
||||
//= require src/jquery.uls.data.utils
|
||||
//= require src/jquery.uls.lcd
|
||||
//= require src/jquery.uls.languagefilter
|
||||
//= require src/jquery.uls.core
|
||||
|
||||
$(document).ready(function () {
|
||||
function updateLanguage(language) {
|
||||
Cookies.set("_osm_locale", language, { secure: true, path: "/", samesite: "lax" });
|
||||
|
||||
document.location.reload();
|
||||
}
|
||||
|
||||
const languages = $.uls.data.getAutonyms();
|
||||
|
||||
for (const code in languages) {
|
||||
if (!OSM.AVAILABLE_LOCALES.includes(code)) {
|
||||
delete languages[code];
|
||||
}
|
||||
}
|
||||
|
||||
$(".uls-trigger").uls({
|
||||
onSelect: updateLanguage,
|
||||
languages: languages
|
||||
});
|
||||
|
||||
const application_data = $("head").data();
|
||||
|
||||
$(".uls-trigger").text(Cookies.get("_osm_locale") || application_data.locale);
|
||||
});
|
42
app/assets/stylesheets/uls.scss
Normal file
42
app/assets/stylesheets/uls.scss
Normal file
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
*= require css/jquery.uls
|
||||
*= require css/jquery.uls.grid
|
||||
*= require css/jquery.uls.lcd
|
||||
*/
|
||||
|
||||
.uls-menu {
|
||||
z-index: 100000;
|
||||
|
||||
h1 {
|
||||
margin: 16px 0px;
|
||||
}
|
||||
|
||||
.row {
|
||||
display: block;
|
||||
|
||||
* {
|
||||
width: auto;
|
||||
max-width: none;
|
||||
}
|
||||
|
||||
li {
|
||||
width: max-content;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.uls-trigger {
|
||||
cursor: pointer;
|
||||
background-image: image-url('images/language.png');
|
||||
background-image: linear-gradient(transparent, transparent), image-url('images/language.svg');
|
||||
}
|
||||
|
||||
.uls-icon-close {
|
||||
background-image: image-url('images/close.png');
|
||||
background-image: linear-gradient(transparent, transparent), image-url('images/close.svg');
|
||||
}
|
||||
|
||||
.uls-menu .uls-search-label {
|
||||
background-image: image-rl('images/search.png');
|
||||
background-image: linear-gradient(transparent, transparent), image-url('images/search.svg');
|
||||
}
|
|
@ -192,6 +192,8 @@ class ApplicationController < ActionController::Base
|
|||
def preferred_languages
|
||||
@preferred_languages ||= if params[:locale]
|
||||
Locale.list(params[:locale])
|
||||
elsif request.cookies["_osm_locale"]
|
||||
Locale.list(request.cookies["_osm_locale"])
|
||||
elsif current_user
|
||||
current_user.preferred_languages
|
||||
else
|
||||
|
|
|
@ -187,7 +187,11 @@ class UsersController < ApplicationController
|
|||
current_user.data_public = true
|
||||
current_user.description = "" if current_user.description.nil?
|
||||
current_user.creation_address = request.remote_ip
|
||||
current_user.languages = http_accept_language.user_preferred_languages
|
||||
current_user.languages = if request.cookies["_osm_locale"]
|
||||
Locale.list(request.cookies["_osm_locale"])
|
||||
else
|
||||
http_accept_language.user_preferred_languages
|
||||
end
|
||||
current_user.terms_agreed = Time.now.utc
|
||||
current_user.tou_agreed = Time.now.utc
|
||||
current_user.terms_seen = true
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
<% end -%>
|
||||
</li>
|
||||
<% end %>
|
||||
<li class="compact-hide uls-trigger"></li>
|
||||
<li class="nav-item">
|
||||
<%= link_to t("layouts.history"), history_path, :class => header_nav_link_class(history_path) %>
|
||||
</li>
|
||||
|
|
119
vendor/assets/jquery.uls/css/jquery.uls.css
vendored
Normal file
119
vendor/assets/jquery.uls/css/jquery.uls.css
vendored
Normal file
|
@ -0,0 +1,119 @@
|
|||
.uls-trigger {
|
||||
background: url( ../images/language.svg ) no-repeat left center;
|
||||
padding-left: 24px;
|
||||
}
|
||||
|
||||
.uls-menu {
|
||||
position: absolute;
|
||||
z-index: 1000;
|
||||
display: none;
|
||||
margin-top: 1px;
|
||||
background-color: #fff;
|
||||
border: 1px solid #ccc;
|
||||
border-color: rgba( 0, 0, 0, 0.2 );
|
||||
-webkit-box-shadow: 0 5px 10px rgba( 0, 0, 0, 0.2 );
|
||||
-moz-box-shadow: 0 5px 10px rgba( 0, 0, 0, 0.2 );
|
||||
box-shadow: 0 5px 10px rgba( 0, 0, 0, 0.2 );
|
||||
-webkit-background-clip: padding-box;
|
||||
-moz-background-clip: padding;
|
||||
background-clip: padding-box;
|
||||
}
|
||||
|
||||
.uls-wide {
|
||||
min-width: 715px;
|
||||
}
|
||||
|
||||
.uls-medium {
|
||||
min-width: 360px;
|
||||
}
|
||||
|
||||
/* Override the grid */
|
||||
.uls-medium.grid .row {
|
||||
min-width: 300px;
|
||||
}
|
||||
|
||||
.uls-narrow {
|
||||
min-width: 180px;
|
||||
}
|
||||
|
||||
/* Override the grid */
|
||||
.uls-narrow.grid .row {
|
||||
min-width: 150px;
|
||||
}
|
||||
|
||||
.uls-search {
|
||||
background-color: #fff;
|
||||
padding: 5px 16px;
|
||||
border-bottom: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.grid .uls-search {
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
/* Make space for magnifying class on the front */
|
||||
.uls-search-wrapper {
|
||||
position: relative;
|
||||
padding-left: 44px;
|
||||
margin-right: 5px;
|
||||
height: 32px;
|
||||
}
|
||||
|
||||
.uls-search-label {
|
||||
background: url( ../images/search.svg ) no-repeat center center;
|
||||
background-size: 20px;
|
||||
height: 32px;
|
||||
width: 44px;
|
||||
display: block;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.uls-search-input-wrapper {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/* There are two input boxes. This class applies to both of them */
|
||||
.uls-filterinput {
|
||||
font-size: 1.143em;
|
||||
height: 32px;
|
||||
width: 100%;
|
||||
/* For the custom clear (X) icon */
|
||||
padding: 6px 25px 6px 0;
|
||||
outline: 0;
|
||||
border: 0;
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
/* This is the actual input */
|
||||
.uls-languagefilter {
|
||||
background-color: transparent;
|
||||
border: 0;
|
||||
color: #222;
|
||||
}
|
||||
|
||||
/* This is the shadow input box showing completion suggestions */
|
||||
.uls-filtersuggestion {
|
||||
background-color: #fff;
|
||||
color: #777;
|
||||
}
|
||||
|
||||
.uls-languagefilter-clear {
|
||||
background: url( ../images/close.svg ) no-repeat left center;
|
||||
background-size: 15px;
|
||||
cursor: pointer;
|
||||
height: 15px;
|
||||
width: 15px;
|
||||
opacity: 0.7;
|
||||
|
||||
/* Vertical margins: (32 - 15) / 2 */
|
||||
margin: 8.5px 5px;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
/* Make it appear above the input boxes */
|
||||
z-index: 1;
|
||||
}
|
307
vendor/assets/jquery.uls/css/jquery.uls.grid.css
vendored
Normal file
307
vendor/assets/jquery.uls/css/jquery.uls.grid.css
vendored
Normal file
|
@ -0,0 +1,307 @@
|
|||
/* Generated using Foundation http://foundation.zurb.com/docs/grid.php */
|
||||
/* Global Reset & Standards ---------------------- */
|
||||
.grid * {
|
||||
-webkit-box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/* Misc ---------------------- */
|
||||
.grid .left {
|
||||
float: left;
|
||||
}
|
||||
|
||||
.grid .right {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.grid .text-left {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.grid .text-right {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.grid .text-center {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.grid .hide {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.grid .highlight {
|
||||
background: #ff9;
|
||||
}
|
||||
|
||||
/* The Grid ---------------------- */
|
||||
|
||||
.grid .row {
|
||||
width: 100%;
|
||||
max-width: none;
|
||||
min-width: 600px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.grid .row .row {
|
||||
width: auto;
|
||||
max-width: none;
|
||||
min-width: 0;
|
||||
margin: 0 -5px;
|
||||
}
|
||||
|
||||
.grid .column,
|
||||
.grid .columns {
|
||||
float: left;
|
||||
min-height: 1px;
|
||||
padding: 0 5px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.grid .row.collapse .column,
|
||||
.grid .row.collapse .columns {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.grid .row .row.collapse {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.grid .column.centered,
|
||||
.grid .columns.centered {
|
||||
float: none;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.grid .row .one {
|
||||
width: 8.333%;
|
||||
}
|
||||
|
||||
.grid .row .two {
|
||||
width: 16.667%;
|
||||
}
|
||||
|
||||
.grid .row .three {
|
||||
width: 25%;
|
||||
}
|
||||
|
||||
.grid .row .four {
|
||||
width: 33.333%;
|
||||
}
|
||||
|
||||
.grid .row .five {
|
||||
width: 41.667%;
|
||||
}
|
||||
|
||||
.grid .row .six {
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
.grid .row .seven {
|
||||
width: 58.333%;
|
||||
}
|
||||
|
||||
.grid .row .eight {
|
||||
width: 66.667%;
|
||||
}
|
||||
|
||||
.grid .row .nine {
|
||||
width: 75%;
|
||||
}
|
||||
|
||||
.grid .row .ten {
|
||||
width: 83.333%;
|
||||
}
|
||||
|
||||
.grid .row .eleven {
|
||||
width: 91.667%;
|
||||
}
|
||||
|
||||
.grid .row .twelve {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.grid .row .offset-by-one {
|
||||
margin-left: 8.333%;
|
||||
}
|
||||
|
||||
.grid .row .offset-by-two {
|
||||
margin-left: 16.667%;
|
||||
}
|
||||
|
||||
.grid .row .offset-by-three {
|
||||
margin-left: 25%;
|
||||
}
|
||||
|
||||
.grid .row .offset-by-four {
|
||||
margin-left: 33.333%;
|
||||
}
|
||||
|
||||
.grid .row .offset-by-five {
|
||||
margin-left: 41.667%;
|
||||
}
|
||||
|
||||
.grid .row .offset-by-six {
|
||||
margin-left: 50%;
|
||||
}
|
||||
|
||||
.grid .row .offset-by-seven {
|
||||
margin-left: 58.333%;
|
||||
}
|
||||
|
||||
.grid .row .offset-by-eight {
|
||||
margin-left: 66.667%;
|
||||
}
|
||||
|
||||
.grid .row .offset-by-nine {
|
||||
margin-left: 75%;
|
||||
}
|
||||
|
||||
.grid .row .offset-by-ten {
|
||||
margin-left: 83.333%;
|
||||
}
|
||||
|
||||
.grid .push-two {
|
||||
left: 16.667%;
|
||||
}
|
||||
|
||||
.grid .pull-two {
|
||||
right: 16.667%;
|
||||
}
|
||||
|
||||
.grid .push-three {
|
||||
left: 25%;
|
||||
}
|
||||
|
||||
.grid .pull-three {
|
||||
right: 25%;
|
||||
}
|
||||
|
||||
.grid .push-four {
|
||||
left: 33.333%;
|
||||
}
|
||||
|
||||
.grid .pull-four {
|
||||
right: 33.333%;
|
||||
}
|
||||
|
||||
.grid .push-five {
|
||||
left: 41.667%;
|
||||
}
|
||||
|
||||
.grid .pull-five {
|
||||
right: 41.667%;
|
||||
}
|
||||
|
||||
.grid .push-six {
|
||||
left: 50%;
|
||||
}
|
||||
|
||||
.grid .pull-six {
|
||||
right: 50%;
|
||||
}
|
||||
|
||||
.grid .push-seven {
|
||||
left: 58.333%;
|
||||
}
|
||||
|
||||
.grid .pull-seven {
|
||||
right: 58.333%;
|
||||
}
|
||||
|
||||
.grid .push-eight {
|
||||
left: 66.667%;
|
||||
}
|
||||
|
||||
.grid .pull-eight {
|
||||
right: 66.667%;
|
||||
}
|
||||
|
||||
.grid .push-nine {
|
||||
left: 75%;
|
||||
}
|
||||
|
||||
.grid .pull-nine {
|
||||
right: 75%;
|
||||
}
|
||||
|
||||
.grid .push-ten {
|
||||
left: 83.333%;
|
||||
}
|
||||
|
||||
.grid .pull-ten {
|
||||
right: 83.333%;
|
||||
}
|
||||
|
||||
.grid .row:before,
|
||||
.grid .row:after {
|
||||
content: '';
|
||||
display: table;
|
||||
}
|
||||
|
||||
.grid .row:after {
|
||||
clear: both;
|
||||
}
|
||||
|
||||
/* Block Grids ---------------------- */
|
||||
/* These are 2-up, 3-up, 4-up and 5-up ULs, suited
|
||||
for repeating blocks of content. Add 'mobile' to
|
||||
them to switch them just like the layout grid
|
||||
(one item per line) on phones
|
||||
|
||||
For IE7/8 compatibility block-grid items need to be
|
||||
the same height. You can optionally uncomment the
|
||||
lines below to support arbitrary height, but know
|
||||
that IE7/8 do not support :nth-child.
|
||||
-------------------------------------------------- */
|
||||
.grid .block-grid {
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.grid .block-grid > li {
|
||||
display: block;
|
||||
height: auto;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.grid .block-grid.two-up {
|
||||
margin: 0 -15px;
|
||||
}
|
||||
|
||||
.grid .block-grid.two-up > li {
|
||||
width: 50%;
|
||||
padding: 0 15px 15px;
|
||||
}
|
||||
|
||||
/* .block-grid.two-up>li:nth-child(2n+1) {clear: left;} */
|
||||
.grid .block-grid.three-up {
|
||||
margin: 0 -12px;
|
||||
}
|
||||
|
||||
.grid .block-grid.three-up > li {
|
||||
width: 33.33%;
|
||||
padding: 0 12px 12px;
|
||||
}
|
||||
|
||||
/* .block-grid.three-up>li:nth-child(3n+1) {clear: left;} */
|
||||
.grid .block-grid.four-up {
|
||||
margin: 0 -10px;
|
||||
}
|
||||
|
||||
.grid .block-grid.four-up > li {
|
||||
width: 25%;
|
||||
padding: 0 10px 10px;
|
||||
}
|
||||
|
||||
/* .block-grid.four-up>li:nth-child(4n+1) {clear: left;} */
|
||||
.grid .block-grid.five-up {
|
||||
margin: 0 -8px;
|
||||
}
|
||||
|
||||
.grid .block-grid.five-up > li {
|
||||
width: 20%;
|
||||
padding: 0 8px 8px;
|
||||
}
|
140
vendor/assets/jquery.uls/css/jquery.uls.lcd.css
vendored
Normal file
140
vendor/assets/jquery.uls/css/jquery.uls.lcd.css
vendored
Normal file
|
@ -0,0 +1,140 @@
|
|||
/*
|
||||
* Language Category Display (LCD) consists of multiple sections:
|
||||
* - one to display when there are no search results (which might display suggested languages)
|
||||
* - one for each region of the world, plus regions for world languages and suggested languages
|
||||
* The regions consist of one or more rows (blocks) which consist of one-to-four columns. Each
|
||||
* column is an ul element, and contains up to 8 li elements, each containing a link.
|
||||
*/
|
||||
|
||||
.uls-lcd {
|
||||
background-color: #fcfcfc;
|
||||
height: 20em;
|
||||
/* Work around Chrome bug where it places scrollbar on the left in
|
||||
* in RTL mode but actually reserves the place on the right side */
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
width: auto;
|
||||
padding: 0 16px;
|
||||
}
|
||||
|
||||
.uls-lcd-region-title {
|
||||
color: #555;
|
||||
font-size: 1em;
|
||||
padding-left: 28px;
|
||||
}
|
||||
|
||||
.uls-lcd--no-quicklist [ data-region='all' ] .uls-lcd-region-title {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.uls-lcd-region-section {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
/*
|
||||
* We need to have this as a grid row to push rest of the content below it, but resetting
|
||||
* padding and margin so that calculating them for children is easier.
|
||||
*/
|
||||
.grid .uls-language-block.row {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.uls-language-block > ul {
|
||||
/*
|
||||
* We don't want any visible bullets in this list. Not by default anyway.
|
||||
* Using very unspecific selector here to allow other classes to override.
|
||||
* Bug because overflow: hidden is incompatible with bullets, also render
|
||||
* the bullets inside the list in case there should be any.
|
||||
*/
|
||||
list-style: none none;
|
||||
}
|
||||
|
||||
/*
|
||||
* Each block should have 16px padding on both sides. But because we already gave
|
||||
* 16px for the whole menu, we need to remove it for first and last items the blocks.
|
||||
*/
|
||||
.grid .uls-language-block > ul {
|
||||
margin: 0 0 20px 0;
|
||||
padding: 0 16px;
|
||||
}
|
||||
|
||||
.grid .uls-language-block > ul:first-child {
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.grid .uls-language-block > ul:last-child {
|
||||
padding-right: 0;
|
||||
}
|
||||
|
||||
.uls-language-block > ul > li {
|
||||
margin-left: 20px;
|
||||
padding: 0;
|
||||
/*
|
||||
* The directionality (ltr/rtl) for each list item is set dynamically
|
||||
* as HTML attributes in JavaScript. Setting directionality also applies
|
||||
* alignment, but a list with mixed alignment is hard to read.
|
||||
* All items are therefore explicitly aligned to the left, including names
|
||||
* of right-to-left languages in left-to-right environment and vice versa.
|
||||
* As long as the directionality of the item is set correctly, the text
|
||||
* is readable.
|
||||
*/
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.uls-language-block > ul > li:hover {
|
||||
background-color: #eaeff7;
|
||||
}
|
||||
|
||||
.uls-language-block a {
|
||||
cursor: pointer;
|
||||
text-decoration: none;
|
||||
color: #36c;
|
||||
font-size: 1em;
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
overflow-x: hidden;
|
||||
padding: 8px;
|
||||
/*
|
||||
* Some languages have long names for various reasons and we still want
|
||||
* them to appear on one line.
|
||||
* To make it work correctly, the directionality must be set correctly
|
||||
* on the item level.
|
||||
*/
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.uls-no-results-view {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.uls-lcd.uls-no-results > .uls-lcd-region-section {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.uls-lcd.uls-no-results > .uls-no-results-view {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.uls-no-results-found-title {
|
||||
font-size: 1.143em;
|
||||
padding: 0 16px 0 28px;
|
||||
margin: 20px 0;
|
||||
border-bottom: 0;
|
||||
color: #54595d;
|
||||
}
|
||||
|
||||
.uls-no-found-more {
|
||||
border-top: 1px solid #eaecf0;
|
||||
color: #54595d;
|
||||
padding: 12px 16px 12px 44px;
|
||||
font-size: 0.9em;
|
||||
width: 100%;
|
||||
margin-top: 1.6em;
|
||||
line-height: 1.6;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
}
|
307
vendor/assets/jquery.uls/css/jquery.uls.mobile.css
vendored
Normal file
307
vendor/assets/jquery.uls/css/jquery.uls.mobile.css
vendored
Normal file
|
@ -0,0 +1,307 @@
|
|||
/* stylelint-disable declaration-no-important */
|
||||
@media only screen and ( max-width: 767px ) {
|
||||
.uls-mobile.uls-menu {
|
||||
width: 95%;
|
||||
left: 2.5%;
|
||||
}
|
||||
|
||||
.uls-mobile .uls-language-list {
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
|
||||
.uls-mobile .uls-language-block {
|
||||
padding-left: 15px !important;
|
||||
}
|
||||
|
||||
.uls-mobile .uls-language-block ul {
|
||||
min-height: 14em;
|
||||
}
|
||||
|
||||
.uls-mobile .uls-language-block a {
|
||||
font-size: 1.143em;
|
||||
line-height: 1.7em;
|
||||
}
|
||||
|
||||
.uls-mobile .row {
|
||||
width: auto;
|
||||
min-width: 0;
|
||||
margin-left: 0;
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.uls-mobile .column,
|
||||
.uls-mobile .columns {
|
||||
width: auto !important;
|
||||
float: none;
|
||||
}
|
||||
|
||||
.uls-mobile .column:last-child,
|
||||
.uls-mobile .columns:last-child {
|
||||
float: none;
|
||||
}
|
||||
|
||||
.uls-mobile [ class*='column' ] + [ class*='column' ]:last-child {
|
||||
float: none;
|
||||
}
|
||||
|
||||
.uls-mobile .column:before,
|
||||
.uls-mobile .uls-mobile .columns:before,
|
||||
.uls-mobile .column:after,
|
||||
.columns:after {
|
||||
content: '';
|
||||
display: table;
|
||||
}
|
||||
|
||||
.uls-mobile .column:after,
|
||||
.uls-mobile .columns:after {
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.uls-mobile .offset-by-one,
|
||||
.uls-mobile .offset-by-two,
|
||||
.uls-mobile .offset-by-three,
|
||||
.uls-mobile .offset-by-four,
|
||||
.uls-mobile .offset-by-five,
|
||||
.uls-mobile .offset-by-six,
|
||||
.uls-mobile .offset-by-seven,
|
||||
.uls-mobile .offset-by-eight,
|
||||
.uls-mobile .offset-by-nine,
|
||||
.uls-mobile .offset-by-ten {
|
||||
margin-left: 0 !important;
|
||||
}
|
||||
|
||||
.uls-mobile .push-two,
|
||||
.uls-mobile .push-three,
|
||||
.uls-mobile .push-four,
|
||||
.uls-mobile .push-five,
|
||||
.uls-mobile .push-six,
|
||||
.uls-mobile .push-seven,
|
||||
.uls-mobile .push-eight,
|
||||
.uls-mobile .push-nine,
|
||||
.uls-mobile .push-ten {
|
||||
left: auto;
|
||||
}
|
||||
|
||||
.uls-mobile .pull-two,
|
||||
.uls-mobile .pull-three,
|
||||
.uls-mobile .pull-four,
|
||||
.uls-mobile .pull-five,
|
||||
.uls-mobile .pull-six,
|
||||
.uls-mobile .pull-seven,
|
||||
.uls-mobile .pull-eight,
|
||||
.uls-mobile .pull-nine,
|
||||
.uls-mobile .pull-ten {
|
||||
right: auto;
|
||||
}
|
||||
|
||||
/* Mobile 4-column Grid */
|
||||
.uls-mobile .row .mobile-one {
|
||||
width: 25% !important;
|
||||
float: left;
|
||||
padding: 0 4px;
|
||||
}
|
||||
|
||||
.uls-mobile .row .mobile-one:last-child {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.uls-mobile .row.collapse .mobile-one {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.uls-mobile .row .mobile-two {
|
||||
width: 50% !important;
|
||||
float: left;
|
||||
padding: 0 4px;
|
||||
}
|
||||
|
||||
.uls-mobile .row .mobile-two:last-child {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.uls-mobile .row.collapse .mobile-two {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.uls-mobile .row .mobile-three {
|
||||
width: 75% !important;
|
||||
float: left;
|
||||
padding: 0 4px;
|
||||
}
|
||||
|
||||
.uls-mobile .row .mobile-three:last-child {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.uls-mobile .row.collapse .mobile-three {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.uls-mobile .row .mobile-four {
|
||||
width: 100% !important;
|
||||
float: left;
|
||||
padding: 0 4px;
|
||||
}
|
||||
|
||||
.uls-mobile .row .mobile-four:last-child {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.uls-mobile .row.collapse .mobile-four {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.uls-mobile .push-one-mobile {
|
||||
left: 25%;
|
||||
}
|
||||
|
||||
.uls-mobile .pull-one-mobile {
|
||||
right: 25%;
|
||||
}
|
||||
|
||||
.uls-mobile .push-two-mobile {
|
||||
left: 50%;
|
||||
}
|
||||
|
||||
.uls-mobile .pull-two-mobile {
|
||||
right: 50%;
|
||||
}
|
||||
|
||||
.uls-mobile .push-three-mobile {
|
||||
left: 75%;
|
||||
}
|
||||
|
||||
.uls-mobile .pull-three-mobile {
|
||||
right: 75%;
|
||||
}
|
||||
}
|
||||
|
||||
/* Visibility Classes ---------------------- */
|
||||
/* Standard (large) display targeting */
|
||||
.uls-mobile .show-for-small,
|
||||
.uls-mobile .show-for-medium,
|
||||
.uls-mobile .show-for-medium-down,
|
||||
.uls-mobile .hide-for-large,
|
||||
.uls-mobile .hide-for-large-up,
|
||||
.uls-mobile .show-for-xlarge {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.uls-mobile .hide-for-xlarge,
|
||||
.uls-mobile .show-for-large,
|
||||
.uls-mobile .show-for-large-up,
|
||||
.uls-mobile .hide-for-small,
|
||||
.uls-mobile .hide-for-medium,
|
||||
.uls-mobile .hide-for-medium-down {
|
||||
display: block !important;
|
||||
}
|
||||
|
||||
/* Very large display targeting */
|
||||
@media only screen and ( min-width: 1441px ) {
|
||||
.uls-mobile .hide-for-small,
|
||||
.uls-mobile .hide-for-medium,
|
||||
.uls-mobile .hide-for-medium-down,
|
||||
.hide-for-large,
|
||||
.show-for-large-up,
|
||||
.show-for-xlarge {
|
||||
display: block !important;
|
||||
}
|
||||
|
||||
.show-for-small,
|
||||
.uls-mobile .show-for-medium,
|
||||
.uls-mobile .show-for-medium-down,
|
||||
.uls-mobile .show-for-large,
|
||||
.uls-mobile .hide-for-large-up,
|
||||
.uls-mobile .hide-for-xlarge {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* Medium display targeting */
|
||||
@media only screen and ( max-width: 1279px ) and ( min-width: 768px ) {
|
||||
.uls-mobile .hide-for-small,
|
||||
.uls-mobile .show-for-medium,
|
||||
.uls-mobile .show-for-medium-down,
|
||||
.uls-mobile .hide-for-large,
|
||||
.uls-mobile .hide-for-large-up,
|
||||
.uls-mobile .hide-for-xlarge {
|
||||
display: block !important;
|
||||
}
|
||||
|
||||
.uls-mobile .show-for-small,
|
||||
.uls-mobile .hide-for-medium,
|
||||
.uls-mobile .hide-for-medium-down,
|
||||
.uls-mobile .show-for-large,
|
||||
.uls-mobile .show-for-large-up,
|
||||
.uls-mobile .show-for-xlarge {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* Small display targeting */
|
||||
@media only screen and ( max-width: 767px ) {
|
||||
.uls-mobile .show-for-small,
|
||||
.uls-mobile .hide-for-medium,
|
||||
.uls-mobile .show-for-medium-down,
|
||||
.uls-mobile .hide-for-large,
|
||||
.uls-mobile .hide-for-large-up,
|
||||
.uls-mobile .hide-for-xlarge {
|
||||
display: block !important;
|
||||
}
|
||||
|
||||
.uls-mobile .hide-for-small,
|
||||
.uls-mobile .show-for-medium,
|
||||
.uls-mobile .hide-for-medium-down,
|
||||
.uls-mobile .show-for-large,
|
||||
.uls-mobile .show-for-large-up,
|
||||
.uls-mobile .show-for-xlarge {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* Orientation targeting */
|
||||
.uls-mobile .show-for-landscape,
|
||||
.uls-mobile .hide-for-portrait {
|
||||
display: block !important;
|
||||
}
|
||||
|
||||
.uls-mobile .hide-for-landscape,
|
||||
.uls-mobile .show-for-portrait {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
@media screen and ( orientation: landscape ) {
|
||||
.uls-mobile .show-for-landscape,
|
||||
.uls-mobile .hide-for-portrait {
|
||||
display: block !important;
|
||||
}
|
||||
|
||||
.uls-mobile .hide-for-landscape,
|
||||
.uls-mobile .show-for-portrait {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and ( orientation: portrait ) {
|
||||
.uls-mobile .show-for-portrait,
|
||||
.uls-mobile .hide-for-landscape {
|
||||
display: block !important;
|
||||
}
|
||||
|
||||
.uls-mobile .hide-for-portrait,
|
||||
.uls-mobile .show-for-landscape {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* Touch-enabled device targeting */
|
||||
.uls-mobile .show-for-touch,
|
||||
.uls-mobile .touch .hide-for-touch {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
/* stylelint-disable-next-line no-descending-specificity */
|
||||
.uls-mobile .hide-for-touch,
|
||||
.uls-mobile .touch .show-for-touch {
|
||||
display: block !important;
|
||||
}
|
8
vendor/assets/jquery.uls/images/close.svg
vendored
Normal file
8
vendor/assets/jquery.uls/images/close.svg
vendored
Normal file
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20">
|
||||
<title>
|
||||
close
|
||||
</title>
|
||||
<path d="M4.34 2.93l12.73 12.73-1.41 1.41L2.93 4.35z"/>
|
||||
<path d="M17.07 4.34L4.34 17.07l-1.41-1.41L15.66 2.93z"/>
|
||||
</svg>
|
After Width: | Height: | Size: 273 B |
7
vendor/assets/jquery.uls/images/language.svg
vendored
Normal file
7
vendor/assets/jquery.uls/images/language.svg
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20">
|
||||
<title>
|
||||
language
|
||||
</title>
|
||||
<path d="M20 18h-1.44a.61.61 0 0 1-.4-.12.81.81 0 0 1-.23-.31L17 15h-5l-1 2.54a.77.77 0 0 1-.22.3.59.59 0 0 1-.4.14H9l4.55-11.47h1.89zm-3.53-4.31L14.89 9.5a11.62 11.62 0 0 1-.39-1.24q-.09.37-.19.69l-.19.56-1.58 4.19zm-6.3-1.58a13.43 13.43 0 0 1-2.91-1.41 11.46 11.46 0 0 0 2.81-5.37H12V4H7.31a4 4 0 0 0-.2-.56C6.87 2.79 6.6 2 6.6 2l-1.47.5s.4.89.6 1.5H0v1.33h2.15A11.23 11.23 0 0 0 5 10.7a17.19 17.19 0 0 1-5 2.1q.56.82.87 1.38a23.28 23.28 0 0 0 5.22-2.51 15.64 15.64 0 0 0 3.56 1.77zM3.63 5.33h4.91a8.11 8.11 0 0 1-2.45 4.45 9.11 9.11 0 0 1-2.46-4.45z"/>
|
||||
</svg>
|
After Width: | Height: | Size: 717 B |
7
vendor/assets/jquery.uls/images/search.svg
vendored
Normal file
7
vendor/assets/jquery.uls/images/search.svg
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20">
|
||||
<title>
|
||||
search
|
||||
</title>
|
||||
<path fill-rule="evenodd" d="M12.2 13.6a7 7 0 111.4-1.4l5.4 5.4-1.4 1.4-5.4-5.4zM13 8A5 5 0 113 8a5 5 0 0110 0z"/>
|
||||
</svg>
|
After Width: | Height: | Size: 274 B |
499
vendor/assets/jquery.uls/src/jquery.uls.core.js
vendored
Normal file
499
vendor/assets/jquery.uls/src/jquery.uls.core.js
vendored
Normal file
|
@ -0,0 +1,499 @@
|
|||
/**
|
||||
* Universal Language Selector
|
||||
* ULS core component.
|
||||
*
|
||||
* Copyright (C) 2012 Alolita Sharma, Amir Aharoni, Arun Ganesh, Brandon Harris,
|
||||
* Niklas Laxström, Pau Giner, Santhosh Thottingal, Siebrand Mazeland and other
|
||||
* contributors. See CREDITS for a list.
|
||||
*
|
||||
* UniversalLanguageSelector is dual licensed GPLv2 or later and MIT. You don't
|
||||
* have to do anything special to choose one license or the other and you don't
|
||||
* have to notify anyone which license you are using. You are free to use
|
||||
* UniversalLanguageSelector in commercial projects as long as the copyright
|
||||
* header is left intact. See files GPL-LICENSE and MIT-LICENSE for details.
|
||||
*
|
||||
* @file
|
||||
* @license GNU General Public Licence 2.0 or later
|
||||
* @license MIT License
|
||||
*/
|
||||
|
||||
( function ( $ ) {
|
||||
'use strict';
|
||||
|
||||
var template, ULS;
|
||||
|
||||
// Region numbers in id attributes also appear in the langdb.
|
||||
template = '<div class="grid uls-menu"> \
|
||||
<div id="search" class="row uls-search"> \
|
||||
<div class="uls-search-wrapper"> \
|
||||
<label class="uls-search-label" for="uls-languagefilter"></label>\
|
||||
<div class="uls-search-input-wrapper">\
|
||||
<span class="uls-languagefilter-clear"></span>\
|
||||
<input type="text" class="uls-filterinput uls-filtersuggestion"\
|
||||
disabled="true" autocomplete="off">\
|
||||
<input type="text" class="uls-filterinput uls-languagefilter"\
|
||||
maxlength="40"\
|
||||
data-clear="uls-languagefilter-clear"\
|
||||
data-suggestion="uls-filtersuggestion"\
|
||||
placeholder="Search for a language" autocomplete="off">\
|
||||
</div>\
|
||||
</div>\
|
||||
</div>\
|
||||
<div class="row uls-language-list"></div>\
|
||||
<div class="row" id="uls-settings-block"></div>\
|
||||
</div>';
|
||||
|
||||
/**
|
||||
* ULS Public class definition
|
||||
*
|
||||
* @param {Element} element
|
||||
* @param {Object} options
|
||||
*/
|
||||
ULS = function ( element, options ) {
|
||||
var code;
|
||||
this.$element = $( element );
|
||||
this.options = $.extend( {}, $.fn.uls.defaults, options );
|
||||
this.$menu = $( template );
|
||||
this.languages = this.options.languages;
|
||||
|
||||
for ( code in this.languages ) {
|
||||
if ( $.uls.data.languages[ code ] === undefined ) {
|
||||
// Language is unknown to ULS.
|
||||
delete this.languages[ code ];
|
||||
}
|
||||
}
|
||||
|
||||
this.left = this.options.left;
|
||||
this.top = this.options.top;
|
||||
this.shown = false;
|
||||
this.initialized = false;
|
||||
this.shouldRecreate = false;
|
||||
this.menuWidth = this.getMenuWidth();
|
||||
|
||||
this.$languageFilter = this.$menu.find( '.uls-languagefilter' );
|
||||
this.$resultsView = this.$menu.find( '.uls-language-list' );
|
||||
|
||||
this.render();
|
||||
this.listen();
|
||||
this.ready();
|
||||
};
|
||||
|
||||
ULS.prototype = {
|
||||
constructor: ULS,
|
||||
|
||||
/**
|
||||
* A "hook" that runs after the ULS constructor.
|
||||
* At this point it is not guaranteed that the ULS has its dimensions
|
||||
* and that the languages lists are initialized.
|
||||
*
|
||||
* To use it, pass a function as the onReady parameter
|
||||
* in the options when initializing ULS.
|
||||
*/
|
||||
ready: function () {
|
||||
if ( this.options.onReady ) {
|
||||
this.options.onReady.call( this );
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* A "hook" that runs after the ULS panel becomes visible
|
||||
* by using the show method.
|
||||
*
|
||||
* To use it, pass a function as the onVisible parameter
|
||||
* in the options when initializing ULS.
|
||||
*/
|
||||
visible: function () {
|
||||
if ( this.options.onVisible ) {
|
||||
this.options.onVisible.call( this );
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Calculate the position of ULS
|
||||
* Returns an object with top and left properties.
|
||||
*
|
||||
* @return {Object}
|
||||
*/
|
||||
position: function () {
|
||||
var pos,
|
||||
top = this.top,
|
||||
left = this.left;
|
||||
|
||||
if ( this.options.onPosition ) {
|
||||
return this.options.onPosition.call( this );
|
||||
}
|
||||
|
||||
// Default implementation (middle of the screen under the trigger)
|
||||
if ( top === undefined ) {
|
||||
pos = $.extend( {}, this.$element.offset(), {
|
||||
height: this.$element[ 0 ].offsetHeight
|
||||
} );
|
||||
top = pos.top + pos.height;
|
||||
}
|
||||
|
||||
if ( left === undefined ) {
|
||||
left = $( window ).width() / 2 - this.$menu.outerWidth() / 2;
|
||||
}
|
||||
|
||||
return {
|
||||
top: top,
|
||||
left: left
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Show the ULS window
|
||||
*/
|
||||
show: function () {
|
||||
var widthClasses = {
|
||||
wide: 'uls-wide',
|
||||
medium: 'uls-medium',
|
||||
narrow: 'uls-narrow'
|
||||
};
|
||||
|
||||
this.$menu.addClass( widthClasses[ this.menuWidth ] );
|
||||
|
||||
if ( !this.initialized ) {
|
||||
$( document.body ).prepend( this.$menu );
|
||||
this.i18n();
|
||||
this.initialized = true;
|
||||
}
|
||||
|
||||
this.$menu.css( this.position() );
|
||||
this.$menu.show();
|
||||
this.$menu.scrollIntoView();
|
||||
this.shown = true;
|
||||
|
||||
if ( !this.isMobile() ) {
|
||||
this.$languageFilter.trigger( 'focus' );
|
||||
}
|
||||
|
||||
this.visible();
|
||||
},
|
||||
|
||||
i18n: function () {
|
||||
if ( $.i18n ) {
|
||||
this.$menu.find( '[data-i18n]' ).i18n();
|
||||
this.$languageFilter.prop( 'placeholder', $.i18n( 'uls-search-placeholder' ) );
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Hide the ULS window
|
||||
*/
|
||||
hide: function () {
|
||||
this.$menu.hide();
|
||||
this.shown = false;
|
||||
|
||||
this.$menu.removeClass( 'uls-wide uls-medium uls-narrow' );
|
||||
|
||||
if ( this.shouldRecreate ) {
|
||||
this.recreateLanguageFilter();
|
||||
}
|
||||
|
||||
if ( this.options.onCancel ) {
|
||||
this.options.onCancel.call( this );
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Render the UI elements.
|
||||
* Does nothing by default. Can be used for customization.
|
||||
*/
|
||||
render: function () {
|
||||
// Rendering stuff here
|
||||
},
|
||||
|
||||
/**
|
||||
* Callback for results found context.
|
||||
*/
|
||||
success: function () {
|
||||
this.$resultsView.show();
|
||||
},
|
||||
|
||||
createLanguageFilter: function () {
|
||||
var lcd, languagesCount,
|
||||
columnsOptions = {
|
||||
wide: 4,
|
||||
medium: 2,
|
||||
narrow: 1
|
||||
};
|
||||
|
||||
languagesCount = Object.keys( this.options.languages ).length;
|
||||
lcd = this.$resultsView.lcd( {
|
||||
languages: this.languages,
|
||||
columns: columnsOptions[ this.menuWidth ],
|
||||
|
||||
quickList: languagesCount > 12 ? this.options.quickList : [],
|
||||
clickhandler: this.select.bind( this ),
|
||||
showRegions: this.options.showRegions,
|
||||
languageDecorator: this.options.languageDecorator,
|
||||
noResultsTemplate: this.options.noResultsTemplate,
|
||||
itemsPerColumn: this.options.itemsPerColumn,
|
||||
groupByRegion: this.options.groupByRegion
|
||||
} ).data( 'lcd' );
|
||||
|
||||
this.$languageFilter.languagefilter( {
|
||||
lcd: lcd,
|
||||
languages: this.languages,
|
||||
ulsPurpose: this.options.ulsPurpose,
|
||||
searchAPI: this.options.searchAPI,
|
||||
onSelect: this.select.bind( this )
|
||||
} );
|
||||
|
||||
this.$languageFilter.on( 'noresults.uls', lcd.noResults.bind( lcd ) );
|
||||
},
|
||||
|
||||
recreateLanguageFilter: function () {
|
||||
this.$resultsView.removeData( 'lcd' );
|
||||
this.$resultsView.empty();
|
||||
this.$languageFilter.removeData( 'languagefilter' );
|
||||
this.createLanguageFilter();
|
||||
|
||||
this.shouldRecreate = false;
|
||||
},
|
||||
|
||||
/**
|
||||
* Bind the UI elements with their event listeners
|
||||
*/
|
||||
listen: function () {
|
||||
// Register all event listeners to the ULS here.
|
||||
this.$element.on( 'click', this.click.bind( this ) );
|
||||
|
||||
// Don't do anything if pressing on empty space in the ULS
|
||||
this.$menu.on( 'click', function ( e ) {
|
||||
e.stopPropagation();
|
||||
} );
|
||||
|
||||
// Handle key press events on the menu
|
||||
this.$menu.on( 'keydown', this.keypress.bind( this ) );
|
||||
|
||||
this.createLanguageFilter();
|
||||
|
||||
this.$languageFilter.on( 'resultsfound.uls', this.success.bind( this ) );
|
||||
|
||||
$( document.body ).on( 'click', this.cancel.bind( this ) );
|
||||
$( window ).on( 'resize', $.fn.uls.debounce( this.resize.bind( this ), 250 ) );
|
||||
},
|
||||
|
||||
resize: function () {
|
||||
var menuWidth = this.getMenuWidth();
|
||||
|
||||
if ( this.menuWidth === menuWidth ) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.menuWidth = menuWidth;
|
||||
this.shouldRecreate = true;
|
||||
if ( !this.shown ) {
|
||||
this.recreateLanguageFilter();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* On select handler for search results
|
||||
*
|
||||
* @param {string} langCode
|
||||
* @param {Object} event The jQuery click event
|
||||
*/
|
||||
select: function ( langCode, event ) {
|
||||
this.hide();
|
||||
if ( this.options.onSelect ) {
|
||||
this.options.onSelect.call( this, langCode, event );
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* On cancel handler for the uls menu
|
||||
*
|
||||
* @param {Event} e
|
||||
*/
|
||||
cancel: function ( e ) {
|
||||
if ( e && ( this.$element.is( e.target ) ||
|
||||
$.contains( this.$element[ 0 ], e.target ) ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.hide();
|
||||
},
|
||||
|
||||
keypress: function ( e ) {
|
||||
if ( !this.shown ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( e.keyCode === 27 ) { // escape
|
||||
this.cancel();
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}
|
||||
},
|
||||
|
||||
click: function () {
|
||||
if ( this.shown ) {
|
||||
this.hide();
|
||||
} else {
|
||||
this.show();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Get the panel menu width parameter
|
||||
*
|
||||
* @return {string}
|
||||
*/
|
||||
getMenuWidth: function () {
|
||||
var languagesCount,
|
||||
screenWidth = document.documentElement.clientWidth;
|
||||
|
||||
if ( this.options.menuWidth ) {
|
||||
return this.options.menuWidth;
|
||||
}
|
||||
|
||||
languagesCount = Object.keys( this.options.languages ).length;
|
||||
|
||||
if ( screenWidth > 900 && languagesCount >= 48 ) {
|
||||
return 'wide';
|
||||
}
|
||||
|
||||
if ( screenWidth > 500 && languagesCount >= 24 ) {
|
||||
return 'medium';
|
||||
}
|
||||
|
||||
return 'narrow';
|
||||
},
|
||||
|
||||
isMobile: function () {
|
||||
return navigator.userAgent.match( /(iPhone|iPod|iPad|Android|BlackBerry)/ );
|
||||
}
|
||||
};
|
||||
|
||||
/* ULS PLUGIN DEFINITION
|
||||
* =========================== */
|
||||
|
||||
$.fn.uls = function ( option ) {
|
||||
return this.each( function () {
|
||||
var $this = $( this ),
|
||||
data = $this.data( 'uls' ),
|
||||
options = typeof option === 'object' && option;
|
||||
|
||||
if ( !data ) {
|
||||
$this.data( 'uls', ( data = new ULS( this, options ) ) );
|
||||
}
|
||||
|
||||
if ( typeof option === 'string' ) {
|
||||
data[ option ]();
|
||||
}
|
||||
} );
|
||||
};
|
||||
|
||||
$.fn.uls.defaults = {
|
||||
// DEPRECATED: CSS top position for the dialog
|
||||
top: undefined,
|
||||
// DEPRECATED: CSS left position for the dialog
|
||||
left: undefined,
|
||||
// Callback function when user selects a language
|
||||
onSelect: undefined,
|
||||
// Callback function when the dialog is closed without selecting a language
|
||||
onCancel: undefined,
|
||||
// Callback function when ULS has initialized
|
||||
onReady: undefined,
|
||||
// Callback function when ULS dialog is shown
|
||||
onVisible: undefined,
|
||||
// Callback function when ULS dialog is ready to be shown
|
||||
onPosition: undefined,
|
||||
// Languages to be used for ULS, default is all languages
|
||||
languages: $.uls.data.getAutonyms(),
|
||||
// The options are wide (4 columns), medium (2 columns), and narrow (1 column).
|
||||
// If not specified, it will be set automatically.
|
||||
menuWidth: undefined,
|
||||
// What is this ULS used for.
|
||||
// Should be set for distinguishing between different instances of ULS
|
||||
// in the same application.
|
||||
ulsPurpose: '',
|
||||
// Used by LCD
|
||||
quickList: [],
|
||||
// Used by LCD
|
||||
showRegions: undefined,
|
||||
// Used by LCD
|
||||
languageDecorator: undefined,
|
||||
// Used by LCD
|
||||
noResultsTemplate: undefined,
|
||||
// Used by LCD
|
||||
itemsPerColumn: undefined,
|
||||
// Used by LCD
|
||||
groupByRegion: undefined,
|
||||
// Used by LanguageFilter
|
||||
searchAPI: undefined
|
||||
};
|
||||
|
||||
// Define a dummy i18n function, if jquery.i18n not integrated.
|
||||
if ( !$.fn.i18n ) {
|
||||
$.fn.i18n = function () {};
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and returns a new debounced version of the passed function,
|
||||
* which will postpone its execution, until after wait milliseconds have elapsed
|
||||
* since the last time it was invoked.
|
||||
*
|
||||
* @param {Function} fn Function to be debounced.
|
||||
* @param {number} wait Wait interval in milliseconds.
|
||||
* @param {boolean} [immediate] Trigger the function on the leading edge of the wait interval,
|
||||
* instead of the trailing edge.
|
||||
* @return {Function} Debounced function.
|
||||
*/
|
||||
$.fn.uls.debounce = function ( fn, wait, immediate ) {
|
||||
var timeout;
|
||||
|
||||
return function () {
|
||||
var callNow, self = this,
|
||||
later = function () {
|
||||
timeout = null;
|
||||
if ( !immediate ) {
|
||||
fn.apply( self, arguments );
|
||||
}
|
||||
};
|
||||
|
||||
callNow = immediate && !timeout;
|
||||
clearTimeout( timeout );
|
||||
timeout = setTimeout( later, wait || 100 );
|
||||
|
||||
if ( callNow ) {
|
||||
fn.apply( self, arguments );
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
/*
|
||||
* Simple scrollIntoView plugin.
|
||||
* Scrolls the element to the viewport smoothly if it is not already.
|
||||
*/
|
||||
$.fn.scrollIntoView = function () {
|
||||
return this.each( function () {
|
||||
var scrollPosition,
|
||||
$window = $( window ),
|
||||
windowHeight = $window.height(),
|
||||
windowTop = $window.scrollTop(),
|
||||
windowBottom = windowTop + windowHeight,
|
||||
$element = $( this ),
|
||||
panelHeight = $element.height(),
|
||||
panelTop = $element.offset().top,
|
||||
panelBottom = panelTop + panelHeight;
|
||||
|
||||
if ( ( panelTop < windowTop ) || ( panelBottom > windowBottom ) ) {
|
||||
if ( windowTop > panelTop ) {
|
||||
scrollPosition = panelTop;
|
||||
} else {
|
||||
scrollPosition = panelBottom - windowHeight;
|
||||
}
|
||||
// eslint-disable-next-line no-jquery/no-global-selector
|
||||
$( 'html, body' ).stop().animate( {
|
||||
scrollTop: scrollPosition
|
||||
}, 500 );
|
||||
}
|
||||
} );
|
||||
};
|
||||
|
||||
$.fn.uls.Constructor = ULS;
|
||||
}( jQuery ) );
|
6412
vendor/assets/jquery.uls/src/jquery.uls.data.js
vendored
Normal file
6412
vendor/assets/jquery.uls/src/jquery.uls.data.js
vendored
Normal file
File diff suppressed because it is too large
Load diff
335
vendor/assets/jquery.uls/src/jquery.uls.data.utils.js
vendored
Normal file
335
vendor/assets/jquery.uls/src/jquery.uls.data.utils.js
vendored
Normal file
|
@ -0,0 +1,335 @@
|
|||
/**
|
||||
* Utility functions for querying language data.
|
||||
*
|
||||
* Copyright (C) 2012 Alolita Sharma, Amir Aharoni, Arun Ganesh, Brandon Harris,
|
||||
* Niklas Laxström, Pau Giner, Santhosh Thottingal, Siebrand Mazeland and other
|
||||
* contributors. See CREDITS for a list.
|
||||
*
|
||||
* UniversalLanguageSelector is dual licensed GPLv2 or later and MIT. You don't
|
||||
* have to do anything special to choose one license or the other and you don't
|
||||
* have to notify anyone which license you are using. You are free to use
|
||||
* UniversalLanguageSelector in commercial projects as long as the copyright
|
||||
* header is left intact. See files GPL-LICENSE and MIT-LICENSE for details.
|
||||
*
|
||||
* @file
|
||||
* @license GNU General Public Licence 2.0 or later
|
||||
* @license MIT License
|
||||
*/
|
||||
|
||||
( function ( $ ) {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Is this language a redirect to another language?
|
||||
*
|
||||
* @param {string} language Language code
|
||||
* @return {string|boolean} Target language code if it's a redirect or false if it's not
|
||||
*/
|
||||
$.uls.data.isRedirect = function ( language ) {
|
||||
return ( $.uls.data.languages[ language ] !== undefined &&
|
||||
$.uls.data.languages[ language ].length === 1 ) ?
|
||||
$.uls.data.languages[ language ][ 0 ] : false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the script of the language.
|
||||
*
|
||||
* @param {string} language Language code
|
||||
* @return {string}
|
||||
*/
|
||||
$.uls.data.getScript = function ( language ) {
|
||||
var target = $.uls.data.isRedirect( language );
|
||||
|
||||
if ( target ) {
|
||||
return $.uls.data.getScript( target );
|
||||
}
|
||||
|
||||
if ( !$.uls.data.languages[ language ] ) {
|
||||
// Undetermined
|
||||
return 'Zyyy';
|
||||
}
|
||||
|
||||
return $.uls.data.languages[ language ][ 0 ];
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the regions in which a language is spoken.
|
||||
*
|
||||
* @param {string} language Language code
|
||||
* @return {string|string[]}
|
||||
*/
|
||||
$.uls.data.getRegions = function ( language ) {
|
||||
var target = $.uls.data.isRedirect( language );
|
||||
|
||||
if ( target ) {
|
||||
return $.uls.data.getRegions( target );
|
||||
}
|
||||
|
||||
return ( $.uls.data.languages[ language ] && $.uls.data.languages[ language ][ 1 ] ) || 'UNKNOWN';
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the autonym of the language.
|
||||
*
|
||||
* @param {string} language Language code
|
||||
* @return {string}
|
||||
*/
|
||||
$.uls.data.getAutonym = function ( language ) {
|
||||
var target = $.uls.data.isRedirect( language );
|
||||
|
||||
if ( target ) {
|
||||
return $.uls.data.getAutonym( target );
|
||||
}
|
||||
|
||||
return ( $.uls.data.languages[ language ] &&
|
||||
$.uls.data.languages[ language ][ 2 ] ) || language;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns all language codes and corresponding autonyms
|
||||
*
|
||||
* @return {string[]}
|
||||
*/
|
||||
$.uls.data.getAutonyms = function () {
|
||||
var language,
|
||||
autonymsByCode = {};
|
||||
|
||||
for ( language in $.uls.data.languages ) {
|
||||
if ( $.uls.data.isRedirect( language ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
autonymsByCode[ language ] = $.uls.data.getAutonym( language );
|
||||
}
|
||||
|
||||
return autonymsByCode;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns all languages written in script.
|
||||
*
|
||||
* @param {string} script string
|
||||
* @return {string[]} languages codes
|
||||
*/
|
||||
$.uls.data.getLanguagesInScript = function ( script ) {
|
||||
return $.uls.data.getLanguagesInScripts( [ script ] );
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns all languages written in the given scripts.
|
||||
*
|
||||
* @param {string[]} scripts
|
||||
* @return {string[]} languages codes
|
||||
*/
|
||||
$.uls.data.getLanguagesInScripts = function ( scripts ) {
|
||||
var language, i,
|
||||
languagesInScripts = [];
|
||||
|
||||
for ( language in $.uls.data.languages ) {
|
||||
if ( $.uls.data.isRedirect( language ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for ( i = 0; i < scripts.length; i++ ) {
|
||||
if ( scripts[ i ] === $.uls.data.getScript( language ) ) {
|
||||
languagesInScripts.push( language );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return languagesInScripts;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns an associative array of languages in a region,
|
||||
* grouped by script group.
|
||||
*
|
||||
* @param {string} region Region code
|
||||
* @return {Object}
|
||||
*/
|
||||
$.uls.data.getLanguagesByScriptGroupInRegion = function ( region ) {
|
||||
return $.uls.data.getLanguagesByScriptGroupInRegions( [ region ] );
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the given list of languages grouped by script.
|
||||
*
|
||||
* @param {string[]} languages Array of language codes to group
|
||||
* @return {string[]} Array of language codes
|
||||
*/
|
||||
$.uls.data.getLanguagesByScriptGroup = function ( languages ) {
|
||||
var languagesByScriptGroup = {},
|
||||
language, languageIndex, resolvedRedirect, langScriptGroup;
|
||||
|
||||
for ( languageIndex = 0; languageIndex < languages.length; languageIndex++ ) {
|
||||
language = languages[ languageIndex ];
|
||||
resolvedRedirect = $.uls.data.isRedirect( language ) || language;
|
||||
langScriptGroup = $.uls.data.getScriptGroupOfLanguage( resolvedRedirect );
|
||||
if ( !languagesByScriptGroup[ langScriptGroup ] ) {
|
||||
languagesByScriptGroup[ langScriptGroup ] = [];
|
||||
}
|
||||
languagesByScriptGroup[ langScriptGroup ].push( language );
|
||||
}
|
||||
return languagesByScriptGroup;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns an associative array of languages in several regions,
|
||||
* grouped by script group.
|
||||
*
|
||||
* @param {string[]} regions region codes
|
||||
* @return {Object}
|
||||
*/
|
||||
$.uls.data.getLanguagesByScriptGroupInRegions = function ( regions ) {
|
||||
var language, i, scriptGroup,
|
||||
languagesByScriptGroupInRegions = {};
|
||||
|
||||
for ( language in $.uls.data.languages ) {
|
||||
if ( $.uls.data.isRedirect( language ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for ( i = 0; i < regions.length; i++ ) {
|
||||
if ( $.uls.data.getRegions( language ).indexOf( regions[ i ] ) !== -1 ) {
|
||||
scriptGroup = $.uls.data.getScriptGroupOfLanguage( language );
|
||||
|
||||
if ( languagesByScriptGroupInRegions[ scriptGroup ] === undefined ) {
|
||||
languagesByScriptGroupInRegions[ scriptGroup ] = [];
|
||||
}
|
||||
|
||||
languagesByScriptGroupInRegions[ scriptGroup ].push( language );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return languagesByScriptGroupInRegions;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the script group of a script or 'Other' if it doesn't
|
||||
* belong to any group.
|
||||
*
|
||||
* @param {string} script Script code
|
||||
* @return {string} script group name
|
||||
*/
|
||||
$.uls.data.getGroupOfScript = function ( script ) {
|
||||
var scriptGroup;
|
||||
|
||||
for ( scriptGroup in $.uls.data.scriptgroups ) {
|
||||
if ( $.uls.data.scriptgroups[ scriptGroup ].indexOf( script ) !== -1 ) {
|
||||
return scriptGroup;
|
||||
}
|
||||
}
|
||||
|
||||
return 'Other';
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the script group of a language.
|
||||
*
|
||||
* @param {string} language Language code
|
||||
* @return {string} script group name
|
||||
*/
|
||||
$.uls.data.getScriptGroupOfLanguage = function ( language ) {
|
||||
return $.uls.data.getGroupOfScript( $.uls.data.getScript( language ) );
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the list of languages sorted by script groups.
|
||||
*
|
||||
* @param {string[]} languages Array of language codes to sort
|
||||
* @return {string[]} Array of language codes
|
||||
*/
|
||||
$.uls.data.sortByScriptGroup = function ( languages ) {
|
||||
var groupedLanguages, scriptGroups, i,
|
||||
allLanguages = [];
|
||||
|
||||
groupedLanguages = $.uls.data.getLanguagesByScriptGroup( languages );
|
||||
scriptGroups = Object.keys( groupedLanguages ).sort();
|
||||
|
||||
for ( i = 0; i < scriptGroups.length; i++ ) {
|
||||
allLanguages = allLanguages.concat( groupedLanguages[ scriptGroups[ i ] ] );
|
||||
}
|
||||
|
||||
return allLanguages;
|
||||
};
|
||||
|
||||
/**
|
||||
* A callback for sorting languages by autonym.
|
||||
* Can be used as an argument to a sort function.
|
||||
*
|
||||
* @param {string} a Language code
|
||||
* @param {string} b Language code
|
||||
* @return {number}
|
||||
*/
|
||||
$.uls.data.sortByAutonym = function ( a, b ) {
|
||||
var autonymA = $.uls.data.getAutonym( a ) || a,
|
||||
autonymB = $.uls.data.getAutonym( b ) || b;
|
||||
|
||||
return ( autonymA.toLowerCase() < autonymB.toLowerCase() ) ? -1 : 1;
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if a language is right-to-left.
|
||||
*
|
||||
* @param {string} language Language code
|
||||
* @return {boolean}
|
||||
*/
|
||||
$.uls.data.isRtl = function ( language ) {
|
||||
return $.uls.data.rtlscripts.indexOf( $.uls.data.getScript( language ) ) !== -1;
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the direction of the language
|
||||
*
|
||||
* @param {string} language Language code
|
||||
* @return {string}
|
||||
*/
|
||||
$.uls.data.getDir = function ( language ) {
|
||||
return $.uls.data.isRtl( language ) ? 'rtl' : 'ltr';
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the languages spoken in a territory.
|
||||
*
|
||||
* @param {string} territory Territory code
|
||||
* @return {string[]} list of language codes
|
||||
*/
|
||||
$.uls.data.getLanguagesInTerritory = function ( territory ) {
|
||||
return $.uls.data.territories[ territory ] || [];
|
||||
};
|
||||
|
||||
/**
|
||||
* Adds a language in run time and sets its options as provided.
|
||||
* If the target option is provided, the language is defined as a redirect.
|
||||
* Other possible options are script, regions and autonym.
|
||||
*
|
||||
* @param {string} code New language code.
|
||||
* @param {Object} options Language properties.
|
||||
*/
|
||||
$.uls.data.addLanguage = function ( code, options ) {
|
||||
if ( options.target ) {
|
||||
$.uls.data.languages[ code ] = [ options.target ];
|
||||
} else {
|
||||
$.uls.data.languages[ code ] = [ options.script, options.regions, options.autonym ];
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Removes a language from the langdb in run time.
|
||||
*
|
||||
* @param {string} code Language code to delete.
|
||||
* @return {boolean} true if the language was removed, false otherwise.
|
||||
*/
|
||||
$.uls.data.deleteLanguage = function ( code ) {
|
||||
if ( $.uls.data.languages[ code ] ) {
|
||||
delete $.uls.data.languages[ code ];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
}( jQuery ) );
|
361
vendor/assets/jquery.uls/src/jquery.uls.languagefilter.js
vendored
Normal file
361
vendor/assets/jquery.uls/src/jquery.uls.languagefilter.js
vendored
Normal file
|
@ -0,0 +1,361 @@
|
|||
/**
|
||||
* jQuery language filter plugin.
|
||||
*
|
||||
* Copyright (C) 2012 Alolita Sharma, Amir Aharoni, Arun Ganesh, Brandon Harris,
|
||||
* Niklas Laxström, Pau Giner, Santhosh Thottingal, Siebrand Mazeland and other
|
||||
* contributors. See CREDITS for a list.
|
||||
*
|
||||
* UniversalLanguageSelector is dual licensed GPLv2 or later and MIT. You don't
|
||||
* have to do anything special to choose one license or the other and you don't
|
||||
* have to notify anyone which license you are using. You are free to use
|
||||
* UniversalLanguageSelector in commercial projects as long as the copyright
|
||||
* header is left intact. See files GPL-LICENSE and MIT-LICENSE for details.
|
||||
*
|
||||
* @file
|
||||
* @license GNU General Public Licence 2.0 or later
|
||||
* @license MIT License
|
||||
*/
|
||||
|
||||
/**
|
||||
* Usage: $( 'inputbox' ).languagefilter();
|
||||
* The values for autocompletion is from the options.languages or options.searchAPI.
|
||||
*
|
||||
* @param {jQuery} $
|
||||
*/
|
||||
( function ( $ ) {
|
||||
'use strict';
|
||||
|
||||
var LanguageFilter;
|
||||
|
||||
/**
|
||||
* Check if a prefix is visually prefix of a string
|
||||
*
|
||||
* @param {string} prefix
|
||||
* @param {string} string
|
||||
* @return {boolean}
|
||||
*/
|
||||
function isVisualPrefix( prefix, string ) {
|
||||
// Pre-base vowel signs of Indic languages. A vowel sign is called pre-base if
|
||||
// consonant + vowel becomes [vowel][consonant] when rendered. Eg: ക + െ => കെ
|
||||
var prebases = 'െേൈൊോൌெேைொோௌେୈୋୌિਿिিেৈোৌෙේෛොෝෞ';
|
||||
return prebases.indexOf( string[ prefix.length ] ) <= 0;
|
||||
}
|
||||
|
||||
LanguageFilter = function ( element, options ) {
|
||||
this.$element = $( element );
|
||||
this.options = $.extend( {}, $.fn.languagefilter.defaults, options );
|
||||
this.$element.addClass( 'languagefilter' );
|
||||
this.resultCount = 0;
|
||||
this.$suggestion = this.$element.siblings( '.' + this.$element.data( 'suggestion' ) );
|
||||
this.$clear = this.$element.siblings( '.' + this.$element.data( 'clear' ) );
|
||||
this.selectedLanguage = null;
|
||||
this.init();
|
||||
this.listen();
|
||||
};
|
||||
|
||||
LanguageFilter.prototype = {
|
||||
init: function () {
|
||||
this.search();
|
||||
},
|
||||
|
||||
listen: function () {
|
||||
this.$element.on( 'keydown', this.keypress.bind( this ) );
|
||||
this.$element.on( 'input', $.fn.uls.debounce( this.onInputChange.bind( this ), 300 ) );
|
||||
|
||||
if ( this.$clear.length ) {
|
||||
this.$clear.on( 'click', this.clear.bind( this ) );
|
||||
}
|
||||
|
||||
this.toggleClear();
|
||||
},
|
||||
|
||||
onInputChange: function () {
|
||||
this.selectedLanguage = null;
|
||||
|
||||
if ( !this.$element.val() ) {
|
||||
this.clear();
|
||||
} else {
|
||||
this.options.lcd.empty();
|
||||
this.search();
|
||||
}
|
||||
|
||||
this.toggleClear();
|
||||
},
|
||||
|
||||
keypress: function ( e ) {
|
||||
var suggestion, query;
|
||||
|
||||
switch ( e.keyCode ) {
|
||||
case 9: // Tab -> Autocomplete
|
||||
suggestion = this.$suggestion.val();
|
||||
|
||||
if ( suggestion && suggestion !== this.$element.val() ) {
|
||||
this.$element.val( suggestion );
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}
|
||||
break;
|
||||
case 13: // Enter
|
||||
if ( !this.options.onSelect ) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Avoid bubbling this 'enter' to background page elements
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
query = ( this.$element.val() || '' ).trim().toLowerCase();
|
||||
|
||||
if ( this.selectedLanguage ) {
|
||||
// this.selectLanguage will be populated from a matching search
|
||||
this.options.onSelect( this.selectedLanguage, e );
|
||||
} else if ( this.options.languages[ query ] ) {
|
||||
// Search is yet to happen (in timeout delay),
|
||||
// but we have a matching language code.
|
||||
this.options.onSelect( query, e );
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Clears the current search removing
|
||||
* clear buttons and suggestions.
|
||||
*/
|
||||
deactivate: function () {
|
||||
this.$element.val( '' );
|
||||
|
||||
if ( !$.fn.uls.Constructor.prototype.isMobile() ) {
|
||||
this.$element.trigger( 'focus' );
|
||||
}
|
||||
|
||||
this.toggleClear();
|
||||
this.autofill();
|
||||
},
|
||||
|
||||
/**
|
||||
* Clears the search and shows all languages
|
||||
*/
|
||||
clear: function () {
|
||||
this.deactivate();
|
||||
this.search();
|
||||
},
|
||||
|
||||
/**
|
||||
* Toggles the visibility of clear icon depending
|
||||
* on whether there is anything to clear.
|
||||
*/
|
||||
toggleClear: function () {
|
||||
if ( !this.$clear.length ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( this.$element.val() ) {
|
||||
this.$clear.show();
|
||||
} else {
|
||||
this.$clear.hide();
|
||||
}
|
||||
},
|
||||
|
||||
search: function () {
|
||||
var languages = Object.keys( this.options.languages ),
|
||||
results = [],
|
||||
query = ( this.$element.val() || '' ).trim().toLowerCase();
|
||||
|
||||
if ( query === '' ) {
|
||||
this.options.lcd.setGroupByRegionOverride( null );
|
||||
this.resultHandler( query, languages );
|
||||
return;
|
||||
}
|
||||
|
||||
this.options.lcd.setGroupByRegionOverride( false );
|
||||
// Local search results
|
||||
results = languages.filter( function ( langCode ) {
|
||||
return this.filter( langCode, query );
|
||||
}.bind( this ) );
|
||||
|
||||
// Use the searchAPI if available, assuming that it has superior search results.
|
||||
if ( this.options.searchAPI ) {
|
||||
this.searchAPI( query )
|
||||
.done( this.resultHandler.bind( this ) )
|
||||
.fail( this.resultHandler.bind( this, query, results, undefined ) );
|
||||
} else {
|
||||
this.resultHandler( query, results );
|
||||
}
|
||||
},
|
||||
|
||||
searchAPI: function ( query ) {
|
||||
return $.get( this.options.searchAPI, { search: query } ).then( function ( result ) {
|
||||
var autofillLabel,
|
||||
results = [];
|
||||
|
||||
// eslint-disable-next-line no-jquery/no-each-util
|
||||
$.each( result.languagesearch, function ( apiCode, name ) {
|
||||
var code, redirect;
|
||||
|
||||
if ( this.options.languages[ apiCode ] ) {
|
||||
code = apiCode;
|
||||
} else {
|
||||
redirect = $.uls.data.isRedirect( apiCode );
|
||||
if ( !redirect || !this.options.languages[ redirect ] ) {
|
||||
return;
|
||||
}
|
||||
code = redirect;
|
||||
}
|
||||
|
||||
// Because of the redirect checking above, we might get duplicates.
|
||||
// For example if API returns both `sr` and `sr-cyrl`, the former
|
||||
// could get mapped to `sr-cyrl` and then we would have it twice.
|
||||
// The exact cases when this happens of course depends on what is in
|
||||
// options.languages, which might contain redirects such as `sr`. In
|
||||
// this case we only show `sr` if no other variants are there.
|
||||
// This also protects against broken search APIs returning duplicate
|
||||
// results, although that is not happening in practice.
|
||||
if ( results.indexOf( code ) === -1 ) {
|
||||
autofillLabel = autofillLabel || name;
|
||||
results.push( code );
|
||||
}
|
||||
}.bind( this ) );
|
||||
|
||||
return $.Deferred().resolve( query, results, autofillLabel );
|
||||
}.bind( this ) );
|
||||
},
|
||||
|
||||
/**
|
||||
* Handler method to be called once search is over.
|
||||
* Based on search result triggers resultsfound or noresults events
|
||||
*
|
||||
* @param {string} query
|
||||
* @param {string[]} results
|
||||
* @param {string} [autofillLabel]
|
||||
*/
|
||||
resultHandler: function ( query, results, autofillLabel ) {
|
||||
if ( results.length === 0 ) {
|
||||
this.$suggestion.val( '' );
|
||||
this.$element.trigger(
|
||||
'noresults.uls',
|
||||
{
|
||||
query: query,
|
||||
ulsPurpose: this.options.ulsPurpose
|
||||
}
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if ( query ) {
|
||||
this.selectedLanguage = results[ 0 ];
|
||||
this.autofill( results[ 0 ], autofillLabel );
|
||||
}
|
||||
|
||||
results.map( this.render.bind( this ) );
|
||||
this.$element.trigger( 'resultsfound.uls', [ query, results.length ] );
|
||||
},
|
||||
|
||||
autofill: function ( langCode, languageName ) {
|
||||
var autonym, userInput, suggestion;
|
||||
|
||||
if ( !this.$suggestion.length ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( !this.$element.val() ) {
|
||||
this.$suggestion.val( '' );
|
||||
return;
|
||||
}
|
||||
|
||||
languageName = languageName || this.options.languages[ langCode ];
|
||||
|
||||
if ( !languageName ) {
|
||||
return;
|
||||
}
|
||||
|
||||
userInput = this.$element.val();
|
||||
suggestion = userInput +
|
||||
languageName.slice( userInput.length, languageName.length );
|
||||
|
||||
if ( suggestion.toLowerCase() !== languageName.toLowerCase() ) {
|
||||
// see if it was autonym match
|
||||
autonym = $.uls.data.getAutonym( langCode ) || '';
|
||||
suggestion = userInput + autonym.slice( userInput.length, autonym.length );
|
||||
|
||||
if ( suggestion !== autonym ) {
|
||||
// Give up. It may be an ISO/script code match.
|
||||
suggestion = '';
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure that it is a visual prefix.
|
||||
if ( !isVisualPrefix( userInput, suggestion ) ) {
|
||||
suggestion = '';
|
||||
}
|
||||
|
||||
this.$suggestion.val( suggestion );
|
||||
},
|
||||
|
||||
render: function ( langCode ) {
|
||||
return this.options.lcd.append( langCode );
|
||||
},
|
||||
|
||||
escapeRegex: function ( value ) {
|
||||
return value.replace( /[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&' );
|
||||
},
|
||||
|
||||
/**
|
||||
* A search match happens if any of the following passes:
|
||||
* a) Language name in current user interface language
|
||||
* 'starts with' search string.
|
||||
* b) Language autonym 'starts with' search string.
|
||||
* c) ISO 639 code match with search string.
|
||||
* d) ISO 15924 code for the script match the search string.
|
||||
*
|
||||
* @param {string} langCode
|
||||
* @param {string} searchTerm
|
||||
* @return {boolean}
|
||||
*/
|
||||
filter: function ( langCode, searchTerm ) {
|
||||
// FIXME script is ISO 15924 code. We might need actual name of script.
|
||||
var matcher = new RegExp( '^' + this.escapeRegex( searchTerm ), 'i' ),
|
||||
languageName = this.options.languages[ langCode ];
|
||||
|
||||
return matcher.test( languageName ) ||
|
||||
matcher.test( $.uls.data.getAutonym( langCode ) ) ||
|
||||
matcher.test( langCode ) ||
|
||||
matcher.test( $.uls.data.getScript( langCode ) );
|
||||
}
|
||||
};
|
||||
|
||||
$.fn.languagefilter = function ( option ) {
|
||||
return this.each( function () {
|
||||
var $this = $( this ),
|
||||
data = $this.data( 'languagefilter' ),
|
||||
options = typeof option === 'object' && option;
|
||||
|
||||
if ( !data ) {
|
||||
$this.data( 'languagefilter', ( data = new LanguageFilter( this, options ) ) );
|
||||
}
|
||||
|
||||
if ( typeof option === 'string' ) {
|
||||
data[ option ]();
|
||||
}
|
||||
} );
|
||||
};
|
||||
|
||||
$.fn.languagefilter.defaults = {
|
||||
// LanguageCategoryDisplay
|
||||
lcd: undefined,
|
||||
// URL to which we append query parameter with the query value
|
||||
searchAPI: undefined,
|
||||
// What is this ULS used for.
|
||||
// Should be set for distinguishing between different instances of ULS
|
||||
// in the same application.
|
||||
ulsPurpose: '',
|
||||
// Object of language tags to language names
|
||||
languages: [],
|
||||
// Callback function when language is selected
|
||||
onSelect: undefined
|
||||
};
|
||||
|
||||
$.fn.languagefilter.Constructor = LanguageFilter;
|
||||
|
||||
}( jQuery ) );
|
481
vendor/assets/jquery.uls/src/jquery.uls.lcd.js
vendored
Normal file
481
vendor/assets/jquery.uls/src/jquery.uls.lcd.js
vendored
Normal file
|
@ -0,0 +1,481 @@
|
|||
/**
|
||||
* Universal Language Selector
|
||||
* Language category display component - Used for showing the search results,
|
||||
* grouped by regions, scripts
|
||||
*
|
||||
* Copyright (C) 2012 Alolita Sharma, Amir Aharoni, Arun Ganesh, Brandon Harris,
|
||||
* Niklas Laxström, Pau Giner, Santhosh Thottingal, Siebrand Mazeland and other
|
||||
* contributors. See CREDITS for a list.
|
||||
*
|
||||
* UniversalLanguageSelector is dual licensed GPLv2 or later and MIT. You don't
|
||||
* have to do anything special to choose one license or the other and you don't
|
||||
* have to notify anyone which license you are using. You are free to use
|
||||
* UniversalLanguageSelector in commercial projects as long as the copyright
|
||||
* header is left intact. See files GPL-LICENSE and MIT-LICENSE for details.
|
||||
*
|
||||
* @file
|
||||
* @license GNU General Public Licence 2.0 or later
|
||||
* @license MIT License
|
||||
*/
|
||||
|
||||
( function ( $ ) {
|
||||
'use strict';
|
||||
|
||||
var noResultsTemplate = '<div class="uls-no-results-view"> \
|
||||
<h2 data-i18n="uls-no-results-found" class="uls-no-results-found-title">No results found</h2> \
|
||||
<div class="uls-no-results-suggestions"></div> \
|
||||
<div class="uls-no-found-more"> \
|
||||
<div data-i18n="uls-search-help">You can search by language name, script name, ISO code of language or you can browse by region.</div> \
|
||||
</div></div>';
|
||||
|
||||
/**
|
||||
* Language category display
|
||||
*
|
||||
* @param {Element} element The container element to which the languages to be displayed
|
||||
* @param {Object} [options] Configuration object
|
||||
* @cfg {Object} [languages] Selectable languages. Keyed by language code, values are autonyms.
|
||||
* @cfg {string[]} [showRegions] Array of region codes to show. Default is
|
||||
* [ 'WW', 'AM', 'EU', 'ME', 'AF', 'AS', 'PA' ]
|
||||
* @cfg {number} [itemsPerColumn] Number of languages per column.
|
||||
* @cfg {number} [columns] Number of columns for languages. Default is 4.
|
||||
* @cfg {Function} [languageDecorator] Callback function to be called when a language
|
||||
* link is prepared - for custom decoration.
|
||||
* @cfg {Function|string[]} [quickList] The languages to display as suggestions for quick
|
||||
* selection.
|
||||
* @cfg {Function} [clickhandler] Callback when language is selected.
|
||||
* @cfg {jQuery|Function} [noResultsTemplate]
|
||||
*/
|
||||
function LanguageCategoryDisplay( element, options ) {
|
||||
this.$element = $( element );
|
||||
this.options = $.extend( {}, $.fn.lcd.defaults, options );
|
||||
// Ensure the internal region 'all' is always present
|
||||
if ( this.options.showRegions.indexOf( 'all' ) === -1 ) {
|
||||
this.options.showRegions.push( 'all' );
|
||||
}
|
||||
|
||||
this.$element.addClass( 'uls-lcd' );
|
||||
this.regionLanguages = {};
|
||||
this.renderTimeout = null;
|
||||
this.$cachedQuicklist = null;
|
||||
this.groupByRegionOverride = null;
|
||||
|
||||
this.render();
|
||||
this.listen();
|
||||
}
|
||||
|
||||
LanguageCategoryDisplay.prototype = {
|
||||
constructor: LanguageCategoryDisplay,
|
||||
|
||||
/**
|
||||
* Adds language to the language list.
|
||||
*
|
||||
* @param {string} langCode
|
||||
* @param {string} [regionCode]
|
||||
* @return {boolean} Whether the language was known and accepted
|
||||
*/
|
||||
append: function ( langCode, regionCode ) {
|
||||
var i, regions;
|
||||
|
||||
if ( !$.uls.data.languages[ langCode ] ) {
|
||||
// Language is unknown or not in the list of languages for this context.
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( !this.isGroupingByRegionEnabled() ) {
|
||||
regions = [ 'all' ];
|
||||
|
||||
// Make sure we do not get duplicates
|
||||
if ( this.regionLanguages.all.indexOf( langCode ) > -1 ) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
if ( regionCode ) {
|
||||
regions = [ regionCode ];
|
||||
} else {
|
||||
regions = $.uls.data.getRegions( langCode );
|
||||
}
|
||||
}
|
||||
|
||||
for ( i = 0; i < regions.length; i++ ) {
|
||||
if ( this.regionLanguages[ regions[ i ] ] ) {
|
||||
this.regionLanguages[ regions[ i ] ].push( langCode );
|
||||
}
|
||||
}
|
||||
|
||||
// Work around the bad interface, delay rendering until we have got
|
||||
// all the languages to speed up performance.
|
||||
clearTimeout( this.renderTimeout );
|
||||
this.renderTimeout = setTimeout( function () {
|
||||
this.renderRegions();
|
||||
}.bind( this ), 50 );
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
/**
|
||||
* Whether we should render languages grouped to geographic regions.
|
||||
*
|
||||
* @return {boolean}
|
||||
*/
|
||||
isGroupingByRegionEnabled: function () {
|
||||
if ( this.groupByRegionOverride !== null ) {
|
||||
return this.groupByRegionOverride;
|
||||
} else if ( this.options.groupByRegion !== 'auto' ) {
|
||||
return this.options.groupByRegion;
|
||||
} else {
|
||||
return this.options.columns > 1;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Override the default region grouping setting.
|
||||
* This is to allow LanguageFilter to disable grouping when displaying search results.
|
||||
*
|
||||
* @param {boolean|null} val True to force grouping, false to disable, null
|
||||
* to undo override.
|
||||
*/
|
||||
setGroupByRegionOverride: function ( val ) {
|
||||
this.groupByRegionOverride = val;
|
||||
},
|
||||
|
||||
render: function () {
|
||||
var $section,
|
||||
$quicklist = this.buildQuicklist(),
|
||||
regions = [],
|
||||
regionNames = {
|
||||
// These are fallback text when i18n library not present
|
||||
all: 'All languages', // Used if there is quicklist and no region grouping
|
||||
WW: 'Worldwide',
|
||||
SP: 'Special',
|
||||
AM: 'America',
|
||||
EU: 'Europe',
|
||||
ME: 'Middle East',
|
||||
AS: 'Asia',
|
||||
AF: 'Africa',
|
||||
PA: 'Pacific'
|
||||
};
|
||||
|
||||
if ( $quicklist.length ) {
|
||||
regions.push( $quicklist );
|
||||
} else {
|
||||
// We use CSS to hide the header for 'all' when quicklist is NOT present
|
||||
this.$element.addClass( 'uls-lcd--no-quicklist' );
|
||||
}
|
||||
|
||||
this.options.showRegions.forEach( function ( regionCode ) {
|
||||
this.regionLanguages[ regionCode ] = [];
|
||||
|
||||
$section = $( '<div>' )
|
||||
.addClass( 'uls-lcd-region-section hide' )
|
||||
.attr( 'data-region', regionCode );
|
||||
|
||||
$( '<h3>' )
|
||||
.attr( 'data-i18n', 'uls-region-' + regionCode )
|
||||
.addClass( 'uls-lcd-region-title' )
|
||||
.text( regionNames[ regionCode ] )
|
||||
.appendTo( $section );
|
||||
|
||||
regions.push( $section );
|
||||
}.bind( this ) );
|
||||
|
||||
this.$element.append( regions );
|
||||
|
||||
this.i18n();
|
||||
},
|
||||
|
||||
/**
|
||||
* Renders a region and displays it if it has content.
|
||||
*/
|
||||
renderRegions: function () {
|
||||
var languages,
|
||||
lcd = this;
|
||||
|
||||
this.$element.removeClass( 'uls-no-results' );
|
||||
this.$element.children( '.uls-lcd-region-section' ).each( function () {
|
||||
var $region = $( this ),
|
||||
regionCode = $region.data( 'region' );
|
||||
|
||||
if ( $region.is( '.uls-lcd-quicklist' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$region.children( '.uls-language-block' ).remove();
|
||||
|
||||
languages = lcd.regionLanguages[ regionCode ];
|
||||
if ( !languages || languages.length === 0 ) {
|
||||
$region.addClass( 'hide' );
|
||||
return;
|
||||
}
|
||||
|
||||
lcd.renderRegion(
|
||||
$region,
|
||||
languages,
|
||||
lcd.options.itemsPerColumn,
|
||||
lcd.options.columns
|
||||
);
|
||||
$region.removeClass( 'hide' );
|
||||
|
||||
lcd.regionLanguages[ regionCode ] = [];
|
||||
} );
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* Adds given languages sorted into rows and columns into given element.
|
||||
*
|
||||
* @param {jQuery} $region Element to add language list.
|
||||
* @param {Array} languages List of language codes.
|
||||
* @param {number} itemsPerColumn How many languages fit in a column.
|
||||
* @param {number} columnsPerRow How many columns fit in a row.
|
||||
*/
|
||||
renderRegion: function ( $region, languages, itemsPerColumn, columnsPerRow ) {
|
||||
var columnsClasses, i, lastItem, currentScript, nextScript, force,
|
||||
languagesCount = languages.length,
|
||||
items = [],
|
||||
columns = [],
|
||||
rows = [];
|
||||
|
||||
languages = $.uls.data.sortByScriptGroup(
|
||||
languages.sort( $.uls.data.sortByAutonym )
|
||||
);
|
||||
|
||||
if ( columnsPerRow === 1 ) {
|
||||
columnsClasses = 'twelve columns';
|
||||
} else if ( columnsPerRow === 2 ) {
|
||||
columnsClasses = 'six columns';
|
||||
} else {
|
||||
columnsClasses = 'three columns';
|
||||
}
|
||||
|
||||
if ( this.options.columns === 1 ) {
|
||||
// For one-column narrow ULS, just render all the languages
|
||||
// in one simple list without separators or script groups
|
||||
for ( i = 0; i < languagesCount; i++ ) {
|
||||
items.push( this.renderItem( languages[ i ] ) );
|
||||
}
|
||||
|
||||
columns.push( $( '<ul>' ).addClass( columnsClasses ).append( items ) );
|
||||
rows.push( $( '<div>' ).addClass( 'row uls-language-block' ).append( columns ) );
|
||||
} else {
|
||||
// For medium and wide ULS, clever column placement
|
||||
for ( i = 0; i < languagesCount; i++ ) {
|
||||
force = false;
|
||||
nextScript = $.uls.data.getScriptGroupOfLanguage( languages[ i + 1 ] );
|
||||
|
||||
lastItem = languagesCount - i === 1;
|
||||
// Force column break if script changes and column has more than one
|
||||
// row already, but only if grouping by region
|
||||
if ( i === 0 || !this.isGroupingByRegionEnabled() ) {
|
||||
currentScript = $.uls.data.getScriptGroupOfLanguage( languages[ i ] );
|
||||
} else if ( currentScript !== nextScript && items.length > 1 ) {
|
||||
force = true;
|
||||
}
|
||||
currentScript = nextScript;
|
||||
|
||||
items.push( this.renderItem( languages[ i ] ) );
|
||||
|
||||
if ( items.length >= itemsPerColumn || lastItem || force ) {
|
||||
columns.push( $( '<ul>' ).addClass( columnsClasses ).append( items ) );
|
||||
items = [];
|
||||
if ( columns.length >= columnsPerRow || lastItem ) {
|
||||
rows.push( $( '<div>' ).addClass( 'row uls-language-block' ).append( columns ) );
|
||||
columns = [];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$region.append( rows );
|
||||
},
|
||||
|
||||
/**
|
||||
* Creates dom node representing one item in language list.
|
||||
*
|
||||
* @param {string} code Language code
|
||||
* @return {Element}
|
||||
*/
|
||||
renderItem: function ( code ) {
|
||||
var a, name, autonym, li;
|
||||
|
||||
name = this.options.languages[ code ];
|
||||
autonym = $.uls.data.getAutonym( code ) || name || code;
|
||||
|
||||
// Not using jQuery as this is performance hotspot
|
||||
li = document.createElement( 'li' );
|
||||
li.title = name;
|
||||
li.setAttribute( 'data-code', code );
|
||||
|
||||
a = document.createElement( 'a' );
|
||||
a.appendChild( document.createTextNode( autonym ) );
|
||||
a.className = 'autonym';
|
||||
a.lang = code;
|
||||
a.dir = $.uls.data.getDir( code );
|
||||
|
||||
li.appendChild( a );
|
||||
if ( this.options.languageDecorator ) {
|
||||
this.options.languageDecorator( $( a ), code );
|
||||
}
|
||||
return li;
|
||||
},
|
||||
|
||||
i18n: function () {
|
||||
this.$element.find( '[data-i18n]' ).i18n();
|
||||
},
|
||||
|
||||
/**
|
||||
* Adds quicklist as a region.
|
||||
*/
|
||||
quicklist: function () {
|
||||
this.$element.find( '.uls-lcd-quicklist' ).removeClass( 'hide' );
|
||||
},
|
||||
|
||||
buildQuicklist: function () {
|
||||
var quickList, $quickListSection, $quickListSectionTitle;
|
||||
|
||||
if ( this.$cachedQuicklist !== null ) {
|
||||
return this.$cachedQuicklist;
|
||||
}
|
||||
|
||||
if ( typeof this.options.quickList === 'function' ) {
|
||||
this.options.quickList = this.options.quickList();
|
||||
}
|
||||
|
||||
if ( !this.options.quickList.length ) {
|
||||
this.$cachedQuicklist = $( [] );
|
||||
return this.$cachedQuicklist;
|
||||
}
|
||||
|
||||
// Pick only the first elements, because we don't have room for more
|
||||
quickList = this.options.quickList;
|
||||
quickList = quickList.slice( 0, 16 );
|
||||
quickList.sort( $.uls.data.sortByAutonym );
|
||||
|
||||
$quickListSection = $( '<div>' )
|
||||
.addClass( 'uls-lcd-region-section uls-lcd-quicklist' );
|
||||
|
||||
$quickListSectionTitle = $( '<h3>' )
|
||||
.attr( 'data-i18n', 'uls-common-languages' )
|
||||
.addClass( 'uls-lcd-region-title' )
|
||||
.text( 'Suggested languages' ); // This is placeholder text if jquery.i18n not present
|
||||
$quickListSection.append( $quickListSectionTitle );
|
||||
|
||||
this.renderRegion(
|
||||
$quickListSection,
|
||||
quickList,
|
||||
this.options.itemsPerColumn,
|
||||
this.options.columns
|
||||
);
|
||||
|
||||
$quickListSectionTitle.i18n();
|
||||
|
||||
this.$cachedQuicklist = $quickListSection;
|
||||
return this.$cachedQuicklist;
|
||||
},
|
||||
|
||||
show: function () {
|
||||
if ( !this.regionDivs ) {
|
||||
this.render();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Called when a fresh search is started
|
||||
*/
|
||||
empty: function () {
|
||||
this.$element.addClass( 'uls-lcd--no-quicklist' );
|
||||
this.$element.find( '.uls-lcd-quicklist' ).addClass( 'hide' );
|
||||
},
|
||||
|
||||
focus: function () {
|
||||
this.$element.trigger( 'focus' );
|
||||
},
|
||||
|
||||
/**
|
||||
* No-results event handler
|
||||
*
|
||||
* @param {Event} event
|
||||
* @param {Object} data Information about the failed search query
|
||||
*/
|
||||
noResults: function ( event, data ) {
|
||||
var $noResults;
|
||||
|
||||
this.$element.addClass( 'uls-no-results' );
|
||||
|
||||
this.$element.find( '.uls-no-results-view' ).remove();
|
||||
|
||||
if ( typeof this.options.noResultsTemplate === 'function' ) {
|
||||
$noResults =
|
||||
this.options.noResultsTemplate.call( this, data.query );
|
||||
} else if ( this.options.noResultsTemplate instanceof jQuery ) {
|
||||
$noResults = this.options.noResultsTemplate;
|
||||
} else {
|
||||
throw new Error( 'noResultsTemplate option must be ' +
|
||||
'either jQuery or function returning jQuery' );
|
||||
}
|
||||
|
||||
this.$element.append( $noResults.addClass( 'uls-no-results-view' ).i18n() );
|
||||
},
|
||||
|
||||
listen: function () {
|
||||
var lcd = this;
|
||||
|
||||
if ( this.options.clickhandler ) {
|
||||
this.$element.on( 'click', '.row li', function ( event ) {
|
||||
lcd.options.clickhandler.call( this, $( this ).data( 'code' ), event );
|
||||
} );
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
$.fn.lcd = function ( option ) {
|
||||
return this.each( function () {
|
||||
var $this = $( this ),
|
||||
data = $this.data( 'lcd' ),
|
||||
options = typeof option === 'object' && option;
|
||||
|
||||
if ( !data ) {
|
||||
$this.data( 'lcd', ( data = new LanguageCategoryDisplay( this, options ) ) );
|
||||
}
|
||||
|
||||
if ( typeof option === 'string' ) {
|
||||
data[ option ]();
|
||||
}
|
||||
} );
|
||||
};
|
||||
|
||||
$.fn.lcd.defaults = {
|
||||
// List of languages to show
|
||||
languages: [],
|
||||
// List of regions to show
|
||||
showRegions: [ 'WW', 'AM', 'EU', 'ME', 'AF', 'AS', 'PA' ],
|
||||
// Whether to group by region, defaults to true when columns > 1
|
||||
groupByRegion: 'auto',
|
||||
// How many items per column until new "row" starts
|
||||
itemsPerColumn: 8,
|
||||
// Number of columns, only 1, 2 and 4 are supported
|
||||
columns: 4,
|
||||
// Callback function for language item styling
|
||||
languageDecorator: undefined,
|
||||
// Likely candidates
|
||||
quickList: [],
|
||||
// Callback function for language selection
|
||||
clickhandler: undefined,
|
||||
// Callback function when no search results.
|
||||
// If overloaded, it can accept the search string as an argument.
|
||||
noResultsTemplate: function () {
|
||||
var $suggestionsContainer, $suggestions,
|
||||
$noResultsTemplate = $( noResultsTemplate );
|
||||
|
||||
$suggestions = this.buildQuicklist().clone();
|
||||
$suggestions.removeClass( 'hide' )
|
||||
.find( 'h3' )
|
||||
.data( 'i18n', 'uls-no-results-suggestion-title' )
|
||||
.text( 'You may be interested in:' )
|
||||
.i18n();
|
||||
$suggestionsContainer = $noResultsTemplate.find( '.uls-no-results-suggestions' );
|
||||
$suggestionsContainer.append( $suggestions );
|
||||
return $noResultsTemplate;
|
||||
}
|
||||
};
|
||||
|
||||
}( jQuery ) );
|
Loading…
Add table
Add a link
Reference in a new issue