Category Archives: технология

Исландия

от ElectriClub
лиценз

Исландия е една от страните с бързо приемане на електромобилите. И това не е, защото климатът ѝ е най-подходящият за експерименти с батерии, пробег и зареждане навън. 🙂 Малко статистика: през 2014г. по пътищата в Исландия са се движили 90 електромобила. В момента са 6 000. Както казва Jón Björn Skúlason от исландската компания New Energy, която координира национални инициативи между правителството, индустрията и проучващи институции: “В началото хората бяха скептични, но сега виждат електромобили на пътя и разбират, че те са тук, за да останат”.

Този растеж в броя на електромобилите се дължи на активна правителствена политика. Нищо изненадващо, нали? Имат стимули: не плащат такса при покупка на електромобил, не плащат годишен данък, не плащат ДДС (24% в Исландия), могат да паркират безплатно до 2 часа в центъра на Рейкявик и дори имат облекчения при зареждане. Това поставя страната на второ място в света по дял на продажби на електромобили (11,7% пазарен дял за 2017г.) след Норвегия, където близо всяка трета продажба на кола е на електромобил.

Освен тези стимули обаче, в Исландия имат и подходящата нагласа: 80% от енергията при тях е от собствени възобновяеми източници (хидро и геотермална енергия). Искат да преминат на 100% собствена енергия, за да са независими от външни доставчици.

Естествено, работят и по осигуряване на зареждане, което при техните условия е пълно с предизвикателства. ABB е изградила 20 бързи зарядни станции (може да презаредите за 15-30 минути) по линия на най-голямата магистрала в страната Route 1. Тя е с дължина над 1300км и обикаля целия остров. Температурите падат до под -30 градуса, има много сол, морска мъгла, влага и – да не забравяме – бури. От АВВ казват обаче, че успяват да разрешат 60% от възникналите грешки, без да се налага ходене на място чрез отдалеченото си мониториране на зарядните. Така компанията може и да насочва в реално време потребителите си към работещи станции. Със сигурност опитът, натрупан при тези условия, ще е полезен и за други места. А наличието на подходяща инфраструктурата е едно от условията за по-лесно приемане на електромобилите.

За да си представите как е в Исландия, ето едно видео, от което направо повява хлад: 🙂





Според ВсичкоТок ние сме почти като Исландия: имаме 16 DC (бързи) зарядни и 84 AC зарядни станции. Звучи оптимистично, нали?

Audi с големи инвестиции в електромобилността

от ElectriClub
лиценз

На годишната си среща миналата сряда Audi са обявили плановете си за инвестиция на стойност 40 милиарда евро в електрифициране, автономно шофиране и дигитализация.

По-конкретно смятат да представят над 20 електрифицирани модела до 2025г. “За да може всеки трети купувач да избере е-модел, трябва да има електрифициран вариант на всеки модел до тогава”.  Плановете са през 2025г. да имат продажби от 800 000 броя изцяло електрически или хибридни модели.

Като първа стъпка на 30 август предстои официалното представяне на новия електрически e-tron SUV.

Обявен е с пробег от 300 мили (483км), а зареждането му се очаква да е сред най-бързите на пазара. До 2020г. се очакват общо 4 изцяло електрически модела, а през 2021г. планират да представят и автономен модел на базата на прототипа Audi Aicon.

Според CleanTechnica този бърз напредък не е достатъчно бърз – до тогава Тесла ще са представили модела си Y, ще са изградили фабрики на няколко места (очаква се още една в САЩ, а също в Китай и в Европа). По прогнози може да стигнат до продажба на 2 милиона електромобила на година още през 2024г.

А вие какво мислите?

Пивоварите минават на водородно задвижване

от ElectriClub
лиценз

Nikola Motor Company са обявили, че имат поръчка от 800 камиона за Anheuser-Busch.

Сделката е за 720 милиона долара, като включва изграждането на инфраструктура за зареждане на камионите на 28 места по основни маршрути на компанията.

Защо ви го разказвам? Защото става въпрос за електрически камиони, задвижвани от водородни клетки, осигуряващи пробег между 500 и 1200 мили. В километри това са внушителните от 805 до 1931км. С поставените на подходящи места станции може да презаредите за по-малко от 20 минути.

Очаква се първите тестови камиони за Anheuser-Busch да бъдат доставени в края на 2019г., а през 2020г. да бъде доставена цялата поръчка. Компанията е декларирала желанието си да премине към “задвижване от възстановяеми източници” до 2025г.

Според изпълнителния директор на Никола Trevor Milton “водородно-електрическата технология е бъдещето на доставките”. Обявяват планове да изградят мрежа от 700 зарядни в САЩ и Канада до 2028г., съвместно с партньори като Anheuser-Busch.

Как да използваме Autoptimize с HTTP/2

от Гонзо
лиценз CC BY-NC-SA

В по-новите версии на Autoptimize има възможност чрез филтър да съставите списък с разрешени за обединяване скриптове. Това позволява да обедините скриптовете, които са задължителни за всички страници в сайта и да оставите скриптовете, които се зареждат само на определени страници извън пакета. Това решава и един друг проблем с Autoptimize – когато различни скриптове се зареждат на различни страници, пакетите, които се генерират са различни. Това води до безконтролно увеличаване на кеша на Autoptimize и до забавяне на зареждането за потребителите, защото вместо да заредят кеширан файл, всеки път теглят различен.

И така, да започнем с обединяването на задължителните скриптове:

/**
 * Whitelist scripts to autoptimize
 *
 * @return: whitelist
 */
function gonzo_js_whitelist() {
  $whitelist = array(
    'jquery.js',
    'jquery-migrate.min.js',
    'wp-embed.min.js'
  );
  return join( ',', $whitelist );
}
add_filter( 'autoptimize_filter_js_whitelist', 'gonzo_js_whitelist' );

След като вече имаме пакет с най-важните скриптове, нужни за сайта, трябва да се погрижим за две неща:

  • Да зареждаме обединените скриптове преди останалите, защото пакетът съдържа jQuery, а някои от останалите скриптове най-вероятно разчитат на него.
  • Да зареждаме скриптовете асинхронно, за да не блокират изобразяването на страницата.

Генерираният от Autoptimize скрипт елемент може да поставим веднага след елемента title така:

/**
 * Where in the HTML optimized JS is injected.
 *
 * @param array $replacetag, containing the html-tag and the method (inject "before", "after" or "replace")
 * @return array with updated values
 */
function gonzo_override_js_replacetag( $replacetag ) {
    return array( '</title>', "after" );
}
add_filter( 'autoptimize_filter_js_replacetag', 'gonzo_override_js_replacetag', 10, 1 );

За да зареждаме всички скриптове асинхронно, и в същото време последователно, ще добавим атрибут defer към тях. Така скриптовете не само се зареждат асинхронно, но и не блокират изобразяването на страницата когато се изтеглят. Освен това атрибута defer кара скриптовете да се изпълнят по реда в документа.

/*
 * Defer all javascripts
 */
function gonzo_defer_js($tag, $handle) {
  if( ! is_admin() ){
    $tag = str_replace( ' src', ' defer="defer" src', $tag );
  }
  return $tag;
}
add_filter( 'script_loader_tag', 'gonzo_defer_js', 10, 2 );

/**
 * Change flag added to Javascript.
 *
 * @param $defer: default value, "" when forced in head, "defer " when not forced in head
 * @return: new value
 */
function gonzo_override_defer( $defer ) {
  return "defer ";
}
add_filter( 'autoptimize_filter_js_defer', 'gonzo_override_defer', 10, 1 );

И на края, за да гарантираме, че скриптовете ще се кешират правилно от браузърите и прокситата, ще премахнем GET променливата с версията, която WordPress добавя към адресите на всички ресурси:

/*
 * Remove query string from static assets
 */
function gonzo_remove_script_version( $src ){
  return remove_query_arg( 'ver', $src );
}
add_filter( 'script_loader_src', 'gonzo_remove_script_version' );

Естествено, подобен подход можем да приложим и към CSS файловете, които сайта зарежда. На края ще имаме бърз сайт за удоволствие на потребителите и печалба на клиента.

Експортиране на заглавия, съдържащи HTML, от WordPress

от Гонзо
лиценз CC BY-NC-SA

WordPress позволява да се въвежда HTML на много места, на които не бихте си помислили да го направите. Например заглавията на публикациите – например за да откроите някои думи, да маркирате правилно абревиатура или по друга причина. Например повечето статии в „Как се пише“ съдържат HTML, за да откроят думите, за които се отнася статията. Обаче ако ви се наложи да експортирате това съдържание, ще откриете, че заглавията са изчистени от всякакъв HTML и форматирането е загубено. Така стандартният експорт на WordPress става безполезен за пазене на архив на съдържанието или за прехвърлянето му на друга инсталация. Обаче има лесно решение.

Ако поровите в кода на функцията export_wp(), ще видите две интересни неща:

  1. Там е дефинирана функцията wxr_cdata(), която затваря подадения стринг в CDATA блок.
  2. Заглавията на публикацитиите се филтрита през филтъра the_title_rss.

Значи за да можем да експортираме заглавията заедно с HTML-а, трябва да махнем от този филтър функцията, която чисти HTML-а (strip_tags естествено, както и esc_html()) и да добавим wxr_cdata(). Всъщност това второ няма да стане, защото функцията е дефинирана само в контекста на export_wp(), така че ще трябва просто да я клонирате.

function htr_cdata_post_title ( $title ) {
	$title = '<![CDATA[' . $title . ']]>';
  return $title;
}
add_filter( 'the_title_rss', 'htr_cdata_post_title' );

remove_filter( 'the_title_rss', 'strip_tags' );
remove_filter( 'the_title_rss', 'esc_html' );

Това е всичко, при… опа, това беше от друго шоу.

Установяване на правилен локал на формите, създадени с Contact Form 7

от Гонзо
лиценз CC BY-NC-SA

Наскоро ми се наложи да правя сайт с WordPress на Иврит. За незапознатите с особеностите на близкоизточните езици ще напомня, че се пишат от дясно на ляво и нямат главни букви. Освен това чуждите думи, изписани на латиница (или друга писменост, която се пише от ляво на дясно), както и числа, изписани с арабски цифри, се пишат както си трябва – от ляво на дясно. WordPress поддържа достатъчно добре всякакви писмености и езици, правилната локализация също е важно условие за одобряване на темите в wordpress.org. Аз обаче се сблъсках с един проблем на разширението Contact Form 7, който не е очевиден, когато сайтът е на език, изписван от ляво на дясно. В случая с Иврит обаче, въпреки че всичко останало по сайт сменяше посоката на подравняване на текста и елементите, полетата във формата оставаха подравнени вляво. Бърз преглед на генерирания HTML показа наличието на атрибути lang и dir на елемента, който съдържа формата, за манипулиране на които атрибути няма настройка. Проблемът е, че в моя случай тези атрибути имаха стойности като за английски локал, което не само, че обръщаше подравняването на текста, но би имало неприятни последици и за потребителите на екранни четци – ако екранният четец превключи на друг език, това би било най-малкото доста объркващо.

След кратко търсене в сайта на разширението и в Гугъл намерих въпрос, зададен от потребител, използващ Contact Form 7 в многоезичен сайт на английски и арабски. Неговият проблем беше подобен на моя – формите на арабски си оставаха подравнени вляво. Отговорът за мен изглежда доста нелепо: локала на формата се установява на базата на локала на администрацията по време на създаване на формата и се наследява при клониране на формата. При условие, че често в многоезичните (а и не само) сайтове администраторите на сайта използват локал, различен от този на публичния сайт, и като имаме предвид, че новите версии на WordPress дават възможност в администрацията потребителите да избират локал, различен от основния локал на сайта, това поведение на Contact Form 7 има сериозни последствия върху достъпността на сайта. Проблемът може да се отрази не само на потребителите, използващи екранни четци, но и на всички останали – въпреки, че разширението блокира валидирането на формите в браузъра, това може да бъде отменено от други разширения, и тогава съобщенията на браузъра ще са на езика, установен от локала на формата, а не на езика на сайта.

Понеже не намерих конкретно решение на проблема, освен да си сменям езика в администрацията – това не беше решение в случая – се зарових в кода на разширението. И намерих точно каквото ми трябваше – кука за действие, чрез което могат да се манипулират свойствата на обекта, отговарящ за генерирането на формата, точно преди превръщането ѝ в HTML. Ето и кодът, който написах:

function gonzo_fix_cf7_locale( $cf7 ) {
  $cf7->set_locale( get_locale() );
}
add_action( 'wpcf7_contact_form', 'gonzo_fix_cf7_locale' );

Това, което правя е просто – пренаписвам локала на формата с основния локал на сайта. Решението е универсално и ще работи винаги, когато формата е на същия език като сайта.

WannaCry, Windows?

от Ясен Праматаров
лиценз CC BY

Години наред им казваш да не ползват Windows и всякакъв несвободен софтуер, а сега пищят от поредния вирус… ами как да кажа, не че съм доволен, но не ми е неприятно. Яд ме е само на хорската глупост.

Флекс в неделя сутрин: заглавие с линии от ляво и дясно

от Гонзо
лиценз CC BY-NC-SA

Не знам дали ще има и други публикации, че да се превърне това в рубрика, но ми хареса идеята да си поиграя с флекса в неделя сутрин. И така, искаме на направим заглавка, която има от ляво и от дясно линии до края на блока със съдържание и искаме да го направим с минимален брой елементи. С флексбокс става с точно един елемент. С помощта на двата псевдоелемента ще нарисуваме линиите, а флексбокс ни е нужен, за да подравним нещата. Тайната е в това, че ако флекс контейнера съдържа текст, около него се създава анонимен елемент, който да служи като флекс елемент, и така не ни е необходим допълнителен елемент около текста. Най-добре да ви покажа кода:

HTML:

<h1>Флекс в неделя сутрин</h1>

CSS:

h1 {
  display: flex;
  flex-flow: row nowrap;
  align-items: center;
}

h1:before, h1:after {
  content: '';
  flex: 1;
  height: 0;
  border-top: 1px solid currentColor;
}

h1:before {
  margin-right: .5em;
}

h1:after {
  margin-left: .5em;
}

Резултата:

Флекс

Ако има нещо неясно, питайте!

Невидимо вграждане на външно съдържание с iframe

от Гонзо
лиценз CC BY-NC-SA

Поради различни съображения понякога се налага да използваме външни услуги за част от съдържанието в сайта. В един точно такъв случай ми се наложи да вградя външното съдържание в сайта с iframe и решението трябваше да отговаря на следните изисквания:

  • Височината на iframe-а винаги да отговаря на височината на вградената страница, за да няма втори скролбар.
  • При навигация във вградената страница да се променя и адреса в основната, като промененият адрес да зарежда съответната страница от външната услуга.
  • Заглавието на документа да се променя заедно със навигацията във вграденото съдържание.

Особеното е, че при зареждане на съдържание от друг домейн в iframe JavaScript от едната страница няма достъп до другата. Поради тази причина оразмеряването на iframe според съдържанието изглежда на пръв поглед проблемно. След малко търсене на най-доброто решение се оказа, че то лесно ще ми помогне за изпълнението и на другите две изисквания. Добре де, за втората точка пипнах малко и бекенда на основния сайт, но няма да навлизам в подробности, защото там не съм в свои води.

И така, най-разумното решение за изравняване на височината на iframe с неговото съдържание, когато то се зарежда от друг домейн, е чрез postMessage. Всеки път, когато се зареди страница в рамката, тя праща съобщение към родителската страница с височината на съдържанието. Родителската страница съответно като получи такова съобщение оразмерява рамката.

Вътре в рамката имаме това:

window.addEventListener('load', function(e){
  if(window.parent && window.parent.postMessage){
    var height = document.body.scrollHeight;
    window.parent.postMessage(height, '*');
  }
}, false);

А в основния сайт имаме това:

window.addEventListener('message', function(e) {
  var data = e.originalEvent.data;
  if (!data) return;
  document.getElementById('theframe').style.height = data + 'px';
}, false);

И след като можем да си изпратим някакви данни от единия прозорец към другия, тогава защо не си изпратим всички данни, от които имаме нужда? Какво ни трябва още? Адреса на страницата в рамката и заглавието на страницата. Всъщност няма да ни трябва целия адрес на страницата, а само пътя. Решението ми за синхронизиране на адресите на двете страници беше да добавя пътя от рамката като параметър към адреса на основната страница, и да го използвам за формиране на атрибута src на рамката при зареждане на страницата. Естествено, включих параметър като част от пътя в адреса на основната страница чрез URL Rewrite.

Това, което пропуснах е как точно ще променим адреса на основната страница като получим съобщението от рамката? В първия момент опитах да използвам history.pushState() – имаме навигация и искаме да дадем възможност потребителя да се върне назад и после напред и… имаше обслужване на събитието popstate и се увъртех като пиле в кълчища. Стана така, защото не взех предвид факта, че навигацията вътре в рамката прави записи в историята на браузъра и чрез pushState аз ги дублирам. Много по-лесно се оказа да използвам history.replaceState() – бутоните на браузъра за навигиране в историята управляват рамката, а чрез събитието popstate и postMessage данните за това се пращат към основната страница. Крайният код придоби следния вид:

iframe.js

function sendParent(e){
  if(window.parent && window.parent.postMessage){
    var height = document.body.scrollHeight,
        path = document.location.pathname,
        title = document.title;
    window.parent.postMessage({height: height, path: path, title: title}, '*');
  }
}
window.addEventListener('load', function(e){
  sendParent();
}, false);
window.addEventListener('message', function(e){
  var data = e.data || e.originalEvent.data;
  if(data == 'get') {
    sendParent();
  }
}, false);
window.addEventListener('popstate', function(e){
  setTimeout(sendParent, 0);
}, false);
document.addEventListener("page:load", function() {
  sendParent();
}, false);

parent.js

var theframe = document.getElementById('theframe');
window.addEventListener('message', function(e) {
  var data = e.originalEvent.data;
  if (!data) return;
  theframe.style.height = data.height + 'px';
  window.history.replaceState(null, '', '/help' + data.path);
  window.scroll(0, 0);
  document.title = data.title;
}, false);
window.addEventListener('resize', function(e) {
  theframe.contentWindow.postMessage('get', '*');
}, false);

На края на кода на рамката сигурно сте забелязали събитието page:load – оказа се, че услугата, която вграждаме използва turbolinks и това е събитието, което се случва когато turbolinks зареди съдържанието на нова страница. А на края на кода на основната старница трябва да ви е направило впечатление обработката на resize на прозореца – ако се промени размерът му е много вероятно да се промени и височината на съдържанието в рамката и тогава питаме рамката за размера на съдържанието. Сигурно първото нещо, което си мислите е „А що не го закачим направо на resize на рамката?“ – ами щото resize на рамката се случва и когато ѝ зададем нов размер, което ще изпрати още веднъж съобщение към прозореца, той пак ще сложи нов размер на рамката… Е, на втория – третия път спира тоя пинг-понг, ама кому е нужно…

Та те така, получи се съвсем невидимо за потребителя – зарежда се съдържание, линковете в рамката сменят като че ли цялата страница, бутоните „напред“ и „назад“ на браузъра работят както се очаква… Идилия! Бих ви го показал, но още не сме готови с някои други неща, ще сложа линка когато му дойде времето. Вервайте ми!

SVG filters and CSS animations don’t play together well in WebKit

от Гонзо
лиценз CC BY-NC-SA

There is one particular day in my life that went into reading everything I could find about applying SVG filters on HTML content in Webkit/Blink and pulling my hair why didn’t my code work. See, I had an element with a SVG filter applied as a URI reference and the filter didn’t appear in Chrome and Opera. I tryed embedding the filter definition into the HTML – didn’t work, I tryed recreating the filter with the filter functions available in CSS – could’t create the same effect, but filters did work. Thet I noticed that the filters shows up while the JavaScript is loading, and after disabling JS throu DevTools the filter was there. And after toggling every single piece of JavaScript on the website on and off I managet to pinpoint the cause of my trobbles – a function that applied a class to the body that triggered an animation on a element that is siblink to the one with the SVG filter applied. Then I remembered reading about Chrome not using the GPU for SVG filters applied with URI, but using it for the shortcut functions in CSS. And then I knew – when applying the animation, Chrome rendered the whole container with the GPU and the SVG filter disappeard. And I did try to use 2d functions for the animation, but Chrome still used the GPU and broke the filter. So, if you ever try to use complex SVG filters together with CSS animation, be prepared for trouble!