Выбор часового пояса
Модуль выбора часового пояса, дополнительно имеет JavaScript модуль Combobox для вывода выпадающего списка с возможностью ручного ввода (поиска) с адаптацией для слабовидящих WCAG 2.0, ГОСТ Р 52872-2012.
Живой пример данного модуля и js выпадающих списков combobox смотрите здесь (правый с возможностью поиска значений).
Пример подключения
Берём переменные из куков (cookie).
require D.'deny/mods/zones/index.php'; //Задаём значения по умолчанию $uzd='Europe/Moscow'; if(!$uzs=c('myregion'))$uzs=128;//Europe $region=zoneregion($uzs); if(!$uz=c('mycity'))$uz=$uzd; $uz=htmlspecialchars($uz,ENT_QUOTES); $city=zonecity($region['value'],$uz); if(''==$city['value']){$city['value']=$uzd;$city['text']=ll('zones',$uzd);} date_default_timezone_set($city['value']);
Используем JS Combobox
Первый выпадающий список будет без ручного ввода симулирующий HTML элемент select.
Второй с возможностью ввода. (описание смотрите ниже)
echo '<label id="myregion-label" onclick="ff.g(\'myregion\').focus()" title="',ll('zone','belt'),'">',ll('zone','region'),':</label><br>', '<div class="combo" style="z-index:2">', '<div id="myregion" role="combobox" tabindex="0" aria-labelledby="myregion-label" aria-controls="region" aria-haspopup="listbox" aria-autocomplete="list" aria-expanded="false" onchange="setmyzone(this)" data-v="',$region['value'],'">',$region['text'],'</div>', '<div role="listbox" id="region" tabindex="-1" aria-label="',ll('zone','region'),'">',$region['options'],'</div>', '</div>', '<label for="mycity" title="',ll('zone','belt'),'">',ll('zone','city'),':</label><br>', '<div class="combo" style="z-index:1">', '<input type="text" id="mycity" role="combobox" aria-controls="city" aria-autocomplete="both" aria-haspopup="listbox" aria-expanded="false" onchange="setmyzone(this)" data-v="',$city['value'],'" value="',$city['text'],'">', '<button aria-label="',ll('zone','city'),'" aria-controls="city" aria-expanded="false" tabindex="-1"></button>', '<div role="listbox" id="city" tabindex="-1" aria-label="',ll('zone','city'),'">',$city['options'],'</div>', '</div>'; //подключаем обработку нашего класса в конце /inc/_.js ff.onload(function() { ff.init({ combobox:'combo', ... } ); //по умолчанию combobox:1, будет искать класс combobox. Опции заполнения combobox - div class="combo ...": //вставлять основной текст combobox: - по умолчанию текст из option исключая содержимое тега small (в данной структуре он задуман для вспомогательных данных) - tagout - текст из первого тега - smallout - текст из первого тега small - fullout - весь текст - cutagsout - вырезать все теги с их содержимым, оставить только текст - valueout - текст из option data-v (значение) //можно объединять комбинации: - div class="combo tagout smallout" - текст из 1 тега и тега small - div class="combo tagout valueout" - текст из 1 тега и значение (option data-v) - div class="combo cutagsout valueout" - вырежет теги и добавит option data-v
Добавляем оформление Combobox в CSS
Я собрал в одну "упаковку" сразу оба элемента. !important перебивают заданные стили у меня на сайте, смотрите по месту есть ли в них необходимость..
.combo{height:32px;background-color:#f0f0f0;border:1px solid #cecece;border-radius:5px;position:relative;z-index:2} .combo [role='combobox']{box-sizing:border-box;position:absolute;z-index:2;width:100%;height:32px;margin:0;padding:0 0 0 6px !important;border-radius:5px;font:bold 15px/30px Verdana;color:#fff;text-shadow:0 1px 1px #735206;background:linear-gradient(#ff9000,#ed480c);box-shadow:0 6px 6px -4px rgba(0,0,0,.2);border:1px solid transparent;overflow:hidden;cursor:pointer} .combo [role='combobox']:after{content:'';width:0;height:0;font-size:0;position:absolute;top:13px;left:auto;right:11px;border:6px solid transparent;border-top:5px solid #fff;border-bottom:0;background:none;opacity:1;transition:none} .combo.open [role='combobox']:after{top:12px;border-bottom:5px solid #fff;border-top:0} .combo [role='combobox']::-moz-selection{background-color:#aeaeae} .combo [role='combobox']::selection{background-color:rgba(174,174,174,.99)} .combo button{display:block;position:absolute;z-index:3;width:32px;height:32px;right:0;padding:0;border:0;border-radius:5px;background:none;box-shadow:none;cursor:pointer} .combo button:after{display:block;content:'';width:0;height:0;font-size:0;position:absolute;top:14px;left:auto;right:11px;border:6px solid transparent;border-top:5px solid #fff;border-bottom:0;background:none;opacity:1;transition:none} .combo.open input[role='combobox']{cursor:auto} .combo.open button:after{top:13px;border-bottom:5px solid #fff;border-top:0} .combo [role='listbox']{box-sizing:border-box;display:none;padding-bottom:9px;width:100%;position:absolute;top:32px;max-height:420px;overflow-y:auto;border-radius:3px;border:1px solid #cecece;background-color:#f0f0f0} .combo span{display:block;padding:5px 0 5px 9px;font:13px/20px Verdana;cursor:pointer} .combo span:hover{background-color:#f8f8f8} .combo .selected{color:#aeaeae;background-color:#f8f8f8 !important;cursor:default !important} .combo [aria-selected='true']{color:#000;background-color:#dadada !important} /*Дополнительная информация справа*/ .combo #city span{padding-right:40px} .combo span small{position:absolute;right:4px}
CSS стили по отдельности
.drop{height:32px;background-color:#f0f0f0;border:1px solid #cecece;border-radius:5px;position:relative;z-index:2} .drop [role='combobox']{box-sizing:border-box;position:absolute;z-index:2;width:100%;height:32px;margin:0;padding:0 0 0 6px !important;border-radius:5px;font:bold 15px/30px Verdana;color:#fff;text-shadow:0 1px 1px #735206;background:linear-gradient(#ff9000,#ed480c);box-shadow:0 6px 6px -4px rgba(0,0,0,.2);border:1px solid transparent;overflow:hidden;cursor:pointer} .drop [role='combobox']:after{content:'';width:0;height:0;font-size:0;position:absolute;top:13px;left:auto;right:11px;border:6px solid transparent;border-top:5px solid #fff;border-bottom:0;background:none;opacity:1;transition:none} .drop.open [role='combobox']:after{top:12px;border-bottom:5px solid #fff;border-top:0} .drop [role='listbox']{box-sizing:border-box;display:none;padding-bottom:9px;width:100%;position:absolute;top:32px;max-height:420px;overflow-y:auto;border-radius:3px;border:1px solid #cecece;background-color:#f0f0f0} .drop span{display:block;padding:5px 0 5px 9px;font:13px/20px Verdana;cursor:pointer} .drop span:hover{background-color:#f8f8f8} .drop .selected{color:#aeaeae;background-color:#f8f8f8 !important;cursor:default !important} .drop [aria-selected='true']{color:#000;background-color:#dadada !important} .drop2{height:32px;background-color:#f0f0f0;border:1px solid #cecece;border-radius:5px;position:relative;z-index:2} .drop2 input{box-sizing:border-box;position:absolute;z-index:2;width:100%;height:32px;margin:0 !important;padding:0 0 0 6px !important;border-radius:5px;font:bold 15px/30px Verdana;color:#fff;text-shadow:0 1px 1px #735206;background:linear-gradient(#ff9000,#ed480c);box-shadow:0 6px 6px -4px rgba(0,0,0,.2);border:1px solid transparent} .drop2 input::-moz-selection{background-color:#aeaeae} .drop2 input::selection{background-color:rgba(174,174,174,.99)} .drop2 button{display:block;position:absolute;z-index:3;width:32px;height:32px;right:0;padding:0;border:0;border-radius:5px;background:none;box-shadow:none;cursor:pointer} .drop2 button:after{display:block;content:'';width:0;height:0;font-size:0;position:absolute;top:14px;left:auto;right:11px;border:6px solid transparent;border-top:5px solid #fff;border-bottom:0;background:none;opacity:1;transition:none} .drop2.open input[role='combobox']{cursor:auto} .drop2.open button:after{top:13px;border-bottom:5px solid #fff;border-top:0} .drop2 div{box-sizing:border-box;display:none;padding-bottom:9px;width:100%;position:absolute;top:32px;max-height:420px;overflow-y:auto;border-radius:3px;border:1px solid #cecece;background-color:#f0f0f0} .drop2 span{display:block;padding:5px 40px 5px 9px;font:13px/20px Verdana;cursor:pointer} .drop2 span:hover{background-color:#f8f8f8} .drop2 .selected{color:#aeaeae;background-color:#f8f8f8 !important;cursor:default !important} .drop2 [aria-selected='true']{color:#000;background-color:#dadada !important} .drop2 span small{position:absolute;right:4px}
Получаем значения JS
Решаем как именно сохранять данные и что делать дальше.
function setmyzone(e){ var n,v=ff.atr(e,'data-v');//,t=ff.nn(e,'input')?ff.v(e):e.innerHTML; n=ff.isi(v)?'myregion':'mycity'; ff.sc(n,v,'t');//сохраняем куку и обновляем страницу, в моём скрипте идут манипуляции с адресом - удаляю значение t из $_GET (не обязательно, для примера). }
Если будет необходимо вызвать повторную инициализацию combobox при AJAX запросе - в конце вывода добавьте:
echo '<input type="hidden" id="fseval" value="fo.init(`combo`)">';
или
echo '<input type="hidden" id="fseval" value="fo.init()">';
Горячие клавиши и функционирование Combobox
Для начала стоит отметить, что теги из пунктов вырезаются, т.е. дополнительная информация +3:00 часа итп.
aria-autocomplete="list" - при вводе значений будет произведён поиск и показаны подходящие пункты. Если поля ввода нет, то по нажатию буквы будет выделять по кругу по подходящие пункты списка начинающиеся с такой же с 1-й буквы.
aria-autocomplete="both" - тоже, плюс идёт подстановка "хвоста" значения в поле ввода..
Можно дописать class="combo open focused" : open - откроет(выпадет) список пунктов, focused установит фокус в Combobox.
- Enter (или клик на пункте) - Берёт значения из выделенного пункта и подставляет в поле ввода или div role="combobox". Закрывает выпадающий список. Если изменения есть, пытается вызвать onchange функцию.
- Escape - Закрывает список пунктов, если есть текстовое поле: убирает текст, повторное нажатие возвращает значение по умолчанию.
- Home - Если есть текстовое поле: и открыт список - выделяет первый пункт, если список закрыт стандартно ставит каретку в начало поля ввода. Если поля ввода нет: открывает список и выделяет первый пункт.
- End - Если есть текстовое поле: и открыт список - выделяет последний пункт, если список закрыт стандартно ставит каретку в конец поля ввода. Если поля ввода нет: открывает список и выделяет последний пункт.
- Стрелка влево (ArrowLeft) - Если есть текстовое поле: открывает список(если закрыт) и перемещает каретку на 1 символ влево.
- Стрелка вправо (ArrowRight) - Если есть тектовое поле: открывает список(если закрыт) и перемещает каретку на 1 символ вправо.
- Стрелка вверх (ArrowUp) - Открывает список(если закрыт) и выделяет предыдущий пункт, если его нет - выделяет последний.
- Стрелка вниз (ArrowDown) - Открывает список(если закрыт) и выделяет следующий пункт, если его нет - выделяет первый.
- Alt+Стрелка вверх (Alt+ArrowUp) - Закрыть список пунктов, без выделения пункта.
- Alt+Стрелка вниз (Alt+ArrowDown) - Открыть список пунктов, без выделения пункта.
- Ctrl+~ - Вернуться к предыдущему элементу фокуса (имеется ввиду прыгнуть на предыдущий выделенный элемент страницы).
Описание php функций
zoneregion($z=128, $c='', $j=L, $o=0) - отдаёт регионы часовых поясов.
- $z=128 - Номер или название зоны часового пояса на английском (регистр не важен).
AFRICA=1, AMERICA=2, ANTARCTICA=4, ARCTIC=8, ASIA=16, ATLANTIC=32, AUSTRALIA=64, EUROPE=128, INDIAN=256, PACIFIC=512, UTC=1024, ALL=2047, ALL_WITH_BC=4095, PER_COUNTRY=4096(не используется) - $c='' - Оставлен под события клика на пункт(option) и подобные 'onclick="myfunc(this)"'
- $j=L - Язык вывода (L константа языка по умолчанию).
- $o - Вывести пункты(option) в виде:
0: <span role="option" data-v=""></span>
1: <li role="option" data-v=""></li>
2: <option value=""></option>
Возвращает массив ['value'=>'Номер зоны','text'=>'Название исходя из выбранного языка вывода','options'=>'Список пунктов часовых поясов']. Если значение(value) или текст(text) пустые, значит не найдено.
zonecity($r=128, $z='Europe/Moscow', $c='', $j=L, $o=0, $w=1, $d='<small>+%02d:%02d</small>', $d0=0){ - отдаёт города для выбранного региона часового пояса.
- $z=128 - Номер зоны часового пояса.
- $z='Europe/Moscow' - Выбранный часовой пояс.
- $c='' - Оставлен под события клика на пункт(option) и подобные 'onclick="myfunc(this)"'
- $j=L - Язык вывода (L константа языка по умолчанию).
- $o - Вывести пункты(option) в виде:
0: <span role="option" data-v=""></span>
1: <li role="option" data-v=""></li>
2: <option value=""></option> - $w=1 - Удалять из названия зону, напимер Европа/Москва станет Москва (при выводе всех(ALL=2047, ALL_WITH_BC=4095) часовых поясов, данный флаг игнорируется и выводится всё полностью).
- $d='<small>+%02d:%02d</small>' - Формат вывода смещения времени часового пояса (Европа/Москва +3:00).
- $d0=0 - Вывод дополнительной информации о смещении времени, если совпадает с Всемирным координированным временем (UCT оно же GMT, Greenwich и ещё некоторые - 0:00). Отключено по умолчанию (повторите по аналогии с предыдущим пунктом для включения).
Возвращает массив ['value'=>'Значение часового пояса на английском (Europe/Moscow)','text'=>'Название исходя из выбранного языка вывода','options'=>'Список пунктов городов']. Если значение(value) или текст(text) пустые, значит не найдено.