Забью свой костыль в виде аналога эффекта получаемого с помощью свойства text-overflow: ellipsis.
В моем случае задача немного сложнее, текст не умещался совсем не много, не больше чем на 50%, потому нужно было его отобразить при наведении курсора.
Все очень легко, на помощь пришли, псевдокласс :hover и свойство direction: rtl. Все бы ничего, Firefox, Chrome, Opera, все отлично, IE приплыли.
Ну раз уж, придется задействовать JavaScript, значит чуточку добавим требований, текст не будет просто переключаться с отображения, то с начала, то с конца, пусть он плавно прокручивается, тут и ограничение в 50% снимется.
Сляпал плагин, малютка, меньше сотни строк.
А как работает твой браузер?
Раз, два, три, четыре, пять, вышел зайчик погулять, заинька вышел…
Вдруг охотник выбегает, прямо в зайчика стреляет,
пиф-паф, ой-ой-ой, умирает зайчик мой,
привезли его домой, оказался он живой
Живой пример
Раз, два, три, четыре, пять, вышел зайчик погулять, заинька вышел…
Вдруг охотник выбегает, прямо в зайчика стреляет,
пиф-паф, ой-ой-ой, умирает зайчик мой,
привезли его домой, оказался он живой
Есть нюанс в зависимости от шрифта могут «уехать» точки, нужно добавить некую поправку, но пока править не стал, в моем случае все и так работало.
Рубрика: Веб
Use jQuery .on and hover
используем два события mouseenter и mouseleave, в таком кратком виде
jQuery(function($) { // имитируем подгрузку аяксом $('#test').append( Array(6).join('') ); $('#test').on({ mouseenter: function () { $(this).text( $(this).index() + 1 ); }, mouseleave: function () { setTimeout( $.proxy( function(){$(this).text('')}, this ), 350 ); } }, 'div'); }(jQuery));
Simple filter table jQuery plugin
Понадобился простой фильтр в табличке по значениям с «памятью» все сессий, сваял jQuery плагин с хранением данных в локальном хранилище (localStorage).
N | ИД | МЭС | Договор | Квартал | Комментарий | Состояние |
---|---|---|---|---|---|---|
1 | 58 | МЭС Центра | 30-2012 от 18.10.2012 | IV 2016 | Декабрь 2016 | Формирование |
2 | 57 | МЭС Северо-Запада | 30-2012 от 18.10.2012 | IV 2016 | Декабрь 2016 | Формирование |
3 | 56 | МЭС Волги | 30-2012 от 18.10.2012 | IV 2016 | Декабрь 2016 | Формирование |
4 | 55 | МЭС Урала | 30-2012 от 18.10.2012 | IV 2016 | Декабрь 2016 | Формирование |
5 | 54 | МЭС Западной Сибири | 30-2012 от 18.10.2012 | IV 2016 | Декабрь 2016 | Формирование |
6 | 53 | МЭС Сибири | 30-2012 от 18.10.2012 | IV 2016 | Декабрь 2016 | Формирование |
7 | 52 | МЭС Востока | 30-2012 от 18.10.2012 | IV 2016 | Декабрь 2016 | Формирование |
8 | 51 | МЭС Центра | 30-2012 от 18.10.2012 | III 2016 | Формирование | |
9 | 50 | МЭС Северо-Запада | 30-2012 от 18.10.2012 | IV 2015 | Не подлежит закрытию | Формирование |
10 | 49 | МЭС Волги | 30-2012 от 18.10.2012 | IV 2015 | Не подлежит закрытию | Формирование |
11 | 48 | МЭС Востока | 30-2012 от 18.10.2012 | IV 2016 | Октябрь 2016 | Утвержден |
12 | 47 | МЭС Урала | 30-2012 от 18.10.2012 | IV 2016 | Октябрь 2016 | Утвержден |
13 | 46 | МЭС Западной Сибири | 30-2012 от 18.10.2012 | IV 2016 | Октябрь 2016 | Утвержден |
14 | 45 | МЭС Востока | 30-2012 от 18.10.2012 | IV 2015 | Не подлежит закрытию | Формирование |
15 | 44 | МЭС Урала | 30-2012 от 18.10.2012 | IV 2015 | Не подлежит закрытию | Формирование |
16 | 43 | МЭС Западной Сибири | 30-2012 от 18.10.2012 | IV 2015 | Не подлежит закрытию | Формирование |
17 | 42 | МЭС Центра | 30-2012 от 18.10.2012 | IV 2016 | Перенос на октябрь | Утвержден |
18 | 41 | МЭС Сибири | 30-2012 от 18.10.2012 | IV 2016 | Перенос на октябрь | Утвержден |
19 | 40 | МЭС Центра | 30-2012 от 18.10.2012 | IV 2015 | Не подлежит закрытию | Формирование |
20 | 39 | МЭС Северо-Запада | 30-2012 от 18.10.2012 | IV 2016 | Перенос на октябрь | Утвержден |
21 | 38 | МЭС Центра | 30-2012 от 18.10.2012 | III 2016 | Утвержден | |
22 | 37 | МЭС Юга | 30-2012 от 18.10.2012 | IV 2016 | Декабрь 2016 | Формирование |
23 | 36 | МЭС Волги | 30-2012 от 18.10.2012 | IV 2016 | Перенос на октябрь | Утвержден |
24 | 35 | МЭС Урала | 30-2012 от 18.10.2012 | III 2016 | Утвержден | |
25 | 34 | МЭС Западной Сибири | 30-2012 от 18.10.2012 | III 2016 | Утвержден | |
26 | 33 | МЭС Сибири | 30-2012 от 18.10.2012 | III 2016 | Утвержден | |
27 | 32 | МЭС Сибири | 30-2012 от 18.10.2012 | IV 2015 | Не подлежит закрытию | Формирование |
28 | 31 | МЭС Востока | 30-2012 от 18.10.2012 | III 2016 | Утвержден | |
29 | 26 | МЭС Урала | 30-2012 от 18.10.2012 | II 2016 | Утвержден | |
30 | 25 | МЭС Волги | 30-2012 от 18.10.2012 | II 2016 | Утвержден | |
31 | 24 | МЭС Северо-Запада | 30-2012 от 18.10.2012 | II 2016 | Утвержден | |
32 | 22 | МЭС Западной Сибири | 30-2012 от 18.10.2012 | II 2016 | Утвержден | |
33 | 21 | МЭС Сибири | 30-2012 от 18.10.2012 | II 2016 | Утвержден | |
34 | 20 | МЭС Юга | 30-2012 от 18.10.2012 | II 2016 | Утвержден | |
35 | 19 | МЭС Центра | 30-2012 от 18.10.2012 | II 2016 | Утвержден |
HTML5 data-* attributes and jQuery.data() in examples
HTML5 data-* attributes and jQuery.data() в примерах:
1) загруженная страница содержит
2) на Vanilla JS
видим результат, с помощью jQuery можем легко воспользоваться сохраненным объектом
но эти данные не появляются в dataset, они сохраняются в кэше jQuery, при первой же попытке получить значение data элемента, jQuery создаст свойство в DOM структуре этого элемента «jQuery + $.now()» и присвоит ему уникальный идентификатор (или ранее), который и будет использоваться как ключ для доступа к кэшу, а так же, скопирует атрибуты data в свой кэш.
1) загруженная страница содержит
2) на Vanilla JS
document.getElementById("test").dataset.data1 "qwer" document.getElementById("test").dataset.data2-test NaN document.getElementById("test").dataset.data2Test "asdf" -- для IE 10- dataset не доступен >> document.getElementById("test").dataset.data1 "Не удалось получить свойство "data1" ссылки, значение которой не определено или является NULL" >> document.getElementById("test").getAttribute("data-data1") "qwer" >> document.getElementById("test").getAttribute("data-data2-test") "asdf"используем jQuery для чтения, все универсально, и главное, в IE тоже работает как надо
$('#test').data('data1') "qwer" $('#test').data('data2-test') "asdf" $('#test').data('data2Test') "asdf"а сейчас попробуем сохранить данные используя jQuery.data(), и более того сохраним объект содержащий функцию
видим результат, с помощью jQuery можем легко воспользоваться сохраненным объектом
но эти данные не появляются в dataset, они сохраняются в кэше jQuery, при первой же попытке получить значение data элемента, jQuery создаст свойство в DOM структуре этого элемента «jQuery + $.now()» и присвоит ему уникальный идентификатор (или ранее), который и будет использоваться как ключ для доступа к кэшу, а так же, скопирует атрибуты data в свой кэш.
$('#test').data('data3', {tt: 10, fn1: function(n){ return this.tt * n + n } }) $('#test').data('data3').fn1(5) 55 document.getElementById("test").dataset.data3 undefined
jQuery1113024019371896630481: 63 jQuery.cache[63] Object {data: Object, parsedAttrs: true} jQuery.cache[63].data Object {data2Test: "asdf", data1: "qwer", data3: Object}
$('#test').data() Object {data2Test: "asdf", data1: "qwer"} $.cache[63].data Object {data2Test: "asdf", data1: "qwer"} $('#test').attr('data-data1', 'qazwsx')Итоги:[] $('#test').data() Object {data2Test: "asdf", data1: "qwer"} $('#test')[0].dataset DOMStringMap {data1: "qazwsx", data2Test: "asdf"} $('#test').attr('data-data3', 'qazwsx')[] $('#test')[0].dataset DOMStringMap {data1: "qazwsx", data2Test: "asdf", data3: "qazwsx"} $('#test').data() Object {data2Test: "asdf", data1: "qwer"} $('#test').data('data1', 123)[] $('#test').data() Object {data2Test: "asdf", data1: 123} $('#test')[0].dataset DOMStringMap {data1: "qazwsx", data2Test: "asdf", data3: "qazwsx"} $('#test')[0].dataset.data1 = 777 777 $('#test')[0].dataset DOMStringMap {data1: "777", data2Test: "asdf", data3: "qazwsx"} $('#test').data() Object {data2Test: "asdf", data1: 123}
- data атрибуты загружаются в свойство attributes элемента
- если браузер поддерживает DOMStringMap, то в свойство dataset дублируются все атрибуты data? имена приводятся в верблюжью нотацию, если в имени присутствуют «-«
- jQuery сохраняет копию data атрибутов и более их не обновляет, ни в одну из сторон, jQuery использует javascript для хранения данных, а не DOM, вот тут то плагины jQuery и хранят свои экземпляры
Change the color of address bar in mobile Chrome for Android browser
Select a particular option in a SELECT element in jQuery
Выбрать элемент списка с помощью jQuery, столько разных усложнений, а ведь на то она и библиотека, чтобы сделать код проще.
$("#selId").val("val1").change(); -- или если с мультивыбором $("#selId").val(["val3", "val5"]).change();а можно и всяко разно
$('#selId option[value="val1"]').attr('selected', 'selected'); $('#selId option').filter(function(i, o) { return $(o).val() == "val1"})по этому поводу часто идут холивары, но можно заглянуть в код jQuery и увидеть что присвоение значения списку установит свойство selected = true для элемента списка с равным значением.
jQuery.fn.extend({ val: function( value ) { var hooks, ret, isFunction, elem = this[0]; ...................... return this.each(function( i ) { var val; ...................... hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ]; // If set returns undefined, fall back to normal setting if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) { this.value = val; } }); ...................... jQuery.extend({ valHooks: { option: { get: function( elem ) { var val = jQuery.find.attr( elem, "value" ); return val != null ? val : // Support: IE10-11+ // option.text throws exceptions (#14686, #14858) jQuery.trim( jQuery.text( elem ) ); } }, select: { get: function( elem ) { var value, option, options = elem.options, index = elem.selectedIndex, one = elem.type === "select-one" || index < 0, values = one ? null : [], max = one ? index + 1 : options.length, i = index < 0 ? max : one ? index : 0; // Loop through all the selected options for ( ; i < max; i++ ) { option = options[ i ]; // oldIE doesn't update selected after form reset (#2551) if ( ( option.selected || i === index ) && // Don't return options that are disabled or in a disabled optgroup ( support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null ) && ( !option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" ) ) ) { // Get the specific value for the option value = jQuery( option ).val(); // We don't need an array for one selects if ( one ) { return value; } // Multi-Selects return an array values.push( value ); } } return values; }, set: function( elem, value ) { var optionSet, option, options = elem.options, values = jQuery.makeArray( value ), i = options.length; while ( i-- ) { option = options[ i ]; if ( jQuery.inArray( jQuery.valHooks.option.get( option ), values ) >= 0 ) { // Support: IE6 // When new option element is added to select box we need to // force reflow of newly added node in order to workaround delay // of initialization properties try { option.selected = optionSet = true; } catch ( _ ) { // Will be executed only in IE6 option.scrollHeight; } } else { option.selected = false; } } // Force browsers to behave consistently when non-matching value is set if ( !optionSet ) { elem.selectedIndex = -1; } return options; } ......................
Difference between decodeURIComponent and decodeURI
Различия в decodeURI и decodeURIComponent, в последнем нет исключений он декодирует все символы.
tt1 = encodeURI(" ; / ? : @ & = + $ , # ") "%20;%20/%20?%20:%20@%20&%20=%20+%20$%20,%20#%20" tt2 = encodeURIComponent(" ; / ? : @ & = + $ , # ") "%20%3B%20%2F%20%3F%20%3A%20%40%20%26%20%3D%20%2B%20%24%20%2C%20%23%20" tt3 = decodeURI(tt1) " ; / ? : @ & = + $ , # " tt4 = decodeURI(tt2) " %3B %2F %3F %3A %40 %26 %3D %2B %24 %2C %23 " tt5 = decodeURIComponent(tt1) " ; / ? : @ & = + $ , # " tt6 = decodeURIComponent(tt2) " ; / ? : @ & = + $ , # "
const jschar js_uriReservedPlusPound_ucstr[] = {';', '/', '?', ':', '@', '&', '=', '+', '$', ',', '#', 0}; static JSBool str_decodeURI(JSContext *cx, uintN argc, jsval *vp) { JSString *str; str = ArgToRootedString(cx, argc, vp, 0); if (!str) return JS_FALSE; return Decode(cx, str, js_uriReservedPlusPound_ucstr, vp); } static JSBool str_decodeURI_Component(JSContext *cx, uintN argc, jsval *vp) { JSString *str; str = ArgToRootedString(cx, argc, vp, 0); if (!str) return JS_FALSE; return Decode(cx, str, js_empty_ucstr, vp); }
Web Worker многопоточность в JavaScript
Рассчитаем число Pi в 5000 знаков воспользовавшись Web Worker, setTimeout, и без использования разбора очереди setTimeout или многопоточности(Multithreading) Web Worker, цикл в основном (и единственном) потоке JavaScript. Сравним время выполнения, ощущения по блокировки графического интерфейса (UI).
Воспользуемся формулой Джона Мачайна John Machin
Код под капотом.
Варианты тестов на разных браузерах и машинках.
π=16arctan(15)−4arctan(1239)
arctanx=x−x33+x55−x77+x99−⋯
Web Worker | setInterval(0) (на каждую итерацию) | цикл while |
---|---|---|
Pi | ||
— | — | — |
Мои итоги, плюс Web Worker? работа в отдельном потоке, никакого влияния на основной поток, отсутствие задержки setTimeout, на каждый вызов порядка 10мс, и это если в это время очередь не занята еще чем-либо, например, визуальными эффектами jQuery, да и при setTimeout приходится модифицировать код задачи, итерации делить по вызовам setTimeout. Минус, хотя это и не минус, по другому быть и не может, отсутствие доступа к не потокобезопасным ресурсам DOM, window, document, parent. Где же использовать практически, однооконные веб-приложения с некими относительно тяжелыми расчетами, мне решать такую задачу пока не приходилось.
И еще, FF тормоз, см. скрин, все три теста на одной машинке.
Варианты тестов на разных браузерах и машинках.
Center bootbox vertically
Выравниваем алерты, промпты и диалоги Bootbox.js по вертикали если указан класс v-center
bootbox.alert({message: "Прежде необходимо утвердить реестр по всем предприятиям!", className: 'v-center'}); bootbox.alert("Прежде необходимо утвердить реестр по всем предприятиям!");
$(function() { $(window).on('show.bs.modal resize', function(e){ var setVpos = function() { $(this).find('.modal-dialog').css("margin-top", function() { return Math.max(0, ($(window).height() - $(this).height()) / 3) } ); }; if ($.isWindow(e.target)) $('.modal.v-center:visible').each(setVpos); else if ($(e.target).hasClass('v-center')) $(e.target).each(setVpos); }) });
General callback for multiple actions, jQuery
Ставим общий колбэк завершению нескольких асинхронных действий, воспользуемся «промисом» .promise().
1
2
3
4
jQuery( "#test" ).on( "click", "button", function() { var _this = jQuery(this); _this.prop( "disabled", true ).text( "Работаем" ); _this.closest( "div" ).find( "div" ).each(function( i, o ) { jQuery( o ).slideToggle( 1000 * ( i + 1 ) ); }).promise().done(function() { _this.prop( "disabled", false).text( "Жмем" ); }); });