Posts Tagged ‘javascript’

Rails: store dates in UTC and display them in local time onto client side

Понедельник, Июнь 27th, 2011

In the Rails all timestamps stored in database in UTC by default. UTC is an improved version of wide-known GMT.

Previously, I have kept the timezone for each individual user for computing local date using UTC and user timezone. Well, you know, when you are asked to specify your timezone, choosen it from a huge drop-down list. Some developers, of course, make smarter, they determine the current user’s timezone with javascript and then send it to the server via AJAX.

Now I come to the conclusion that in most cases I do not necessarily user’s timezone to know (I can’t think where it may be necessary to me.) I decided that will be easier to display all the dates on my site in UTC, then on the client side bring them to local time and format using javascript. As a result, I got a helper and a piece of code in javascript.

Here is rails helper, without any frills:

def utc_date(date)
  raw %Q(<time class="utc-date" title="#{date}">#{date}</time>)
end

This helper just display passed date object and display it wrapped by time HTML5 tag.

And here is a javascript code that convert UTC date to local time and format time:

var Application = {
    processUtcDates: function() {
        $$('.utc-date').each(function(wrapper) {
            wrapper.set('html', Application.utcToLocal(wrapper.get('html')))
        })
    },

    utcToLocal: function(value) {
        var a = /^(\d{4})-(\d{2})-(\d{2})\s(\d{2}):(\d{2}):(\d{2})\sUTC$/.exec(value);

        if (a) {
            return (new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4], +a[5], +a[6]))).format("%d/%m/%Y %H:%M");
        }

        return null;
    }
};

Application.processUtcDates();

This example is written using mootools framework, but I think similar method like format is also available in your favorite framework. If not - it’s easy to write this method yourself.
The script simply looks for all the containers with the class .utc-date and convert contained date to local time with formatting.

In general, this is a simple way to remove yourself from a headache to support multiple time zones in your application. I’m waiting for comments about where method I described does not work.

Хранение дат в UTC, отображение и форматирование на клиенте

Четверг, Июнь 23rd, 2011

В Rails по-умолчанию все даты в БД хранятся в UTC. UTC - это, можно сказать, улучшенная версия знакомого всем GMT.

Раньше я хранил часовой пояс для каждого отдельного пользователя, чтобы потом считать локальную дату, основываясь на UTC и временной зоне пользователя, которую он указал. Ну, вы знаете, когда вас просят указать ваш часовой пояс, выбрав нужный из огромного выпадающего списка. Некоторые разработчики, конечно, делают умнее, они определяют текущий часовой пояс пользователя или посетителя при помощи javascript и отправляют его на сервер при помощи AJAX.

Теперь же я пришел к выводу, что мне вообще не обязательно, в большинстве случаев, знать часовой пояс пользователя (навскидку не могу придумать, где это может мне понадобиться). Я подумал, что проще все даты на сайте выводить в UTC формате, затем на клиенте приводить их к локальному времени и форматировать при помощи javascript. В результате, я получил один хелпер и один кусочек кода на javascript.

Вот хелпер. Он пока что без особых изысков:

def utc_date(date)
  raw %Q(<time class="utc-date" title="#{date}">#{date}</time>)
end

Этот хелпер просто получает объект даты в UTC формате и выводит его в HTML5 теге time (я использую HTML5 в своих проектах).

А вот и кусок джаваскрипта, который приводит дату к локальной, а так же форматирует её:

var Application = {
    processUtcDates: function() {
        $$('.utc-date').each(function(wrapper) {
            wrapper.set('html', Application.utcToLocal(wrapper.get('html')))
        })
    },

    utcToLocal: function(value) {
        var a = /^(\d{4})-(\d{2})-(\d{2})\s(\d{2}):(\d{2}):(\d{2})\sUTC$/.exec(value);

        if (a) {
            return (new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4], +a[5], +a[6]))).format("%d/%m/%Y %H:%M");
        }

        return null;
    }
};

Application.processUtcDates();

Этот пример javascript-кода написан с использованием фреймворка mootools, но я думаю, аналог метода format есть и в вашем любимом фреймворке. Если же нет - его легко написать самому.
Скрипт просто ищет все контейнеры с классом .utc-date и приводит содержащуюся в них дату к локальному времени, с форматированием.

В общем, вот таким простым способом можно снять с себя головную боль по поддержке разных часовых поясов в вашем приложении. Жду комментариев о том, где описанный мною способ не подходит.

Как должен выглядеть идеальный WYSIWYG

Понедельник, Январь 31st, 2011

В студии Артемия нашего Лебедева выпустили визуальный редактор на JS под названием Реформатор. Именно так в моем понимании должен выглядеть WYSIWYG.
Мне для моих проектов нужен визуальный редактор, чтобы удобно было возиться с текстами на странице. Так вот, я решил написать собственный. Пока у него будет поддержка только FF > 3, мне этого пока достаточно. Я уже написал немного кода и скоро выложу его на github.

Список того, что должно и не должно быть в моём визуальном редакторе:

  • Никаких возможностей для изменения цвета текста или бэкграунда
  • Все стили берем из стилей css файла для контент-зоны сайта, т.е. того места, где располагается текст.
  • В редакторе все должно выглядеть именно так, как будет выглядеть на сайте.
  • Редактор увеличивает свою высоту по мере набора текста.
  • Удобное боковое меню со стилями (как в Реформаторе).
  • Картинки можно перетаскивать с рабочего стола прямо в редактор и сразу изменять их размер при помощи курсора мыши. Не нужно будет сначала загружать картинку на сайт,а потом вставлять ее в текст.
  • Не будет кучи кнопок, в которых легко запутаться.
  • Не будет выравнивания текста. У нас же будут стили. Если стиль предполагает выравнивание текста по правому краю - то пожалуйста. Это - как задал дизайнер. Редактор сайта не должен хотеть сделать того, чего не задумал дизайнер.
  • По-умолчанию будут: выделение (полужирный, италик, зачеркивание), нумерованный и ненумерованный списки, добавление гиперссылки.
  • Будет undo, redo, очистка форматирования, вставка из word (пока не знаю, как сделать такую вставку наиболее удобно).
  • Текст будет автоматически заворачиваться в параграфы. Озаглавленные параграфы будут заворачиваться в тег section.
  • Поддержка только HTML5.
  • Никаких тебе спелл-чекеров, таблиц спец-символов и прочей ненужной блуды.
  • Все это будет написано на mootools, как расово верном фреймворке.
  • Специальная парсилка для стилей контент-зоны.
  • Мануал, как правильно работать с визуальным редактором.
  • … может - чето забыл, напишу, если вспомню.

Еще одна очень важная фишка, которую хочу выделить:

Предполагается, что визуальный редактор будет использоваться прямо на странице со статьёй. Посмотрите на статью, которую сейчас читаете. Представьте, что если бы вы были прямо сейчас наделены админскими правами то, кликнув (гипотетический клик) на статью вы бы смогли ее прямо здесь же редактировать. Что бы произошло при клике на статью? Примерно это:

  1. Вокруг текста статьи появилась бы рамка - признак того, что мы можем редактировать статью. Или нет - еще лучше: все остальное на странице, кроме статьи, затемнилось бы.
  2. Сбоку бы появилось плавающее меню с кнопками. И это меню можно было бы перетаскивать в любую часть вьюпорта по своему усмотрению, а так же сворачивать.
  3. При ухода фокуса со статьи плавающее меню бы исчезало.
  4. Если мы попытаемся закрыть окно, то появляется диалог с прогрессбаром, в котором отображается процесс сохранения статьи. Только после этого окно закрывается.
  5. Где-то будет расположена кнопка принудительного сохранения статьи. Или ее совсем не будет. Тут подумаю еще.

Ждите ссылку на проект, кому это интересно. А от вас жду предложений по улучшению.

Javascript: текущий элемент списка

Четверг, Январь 13th, 2011

Навеяно работой. Давно хотел об этом написать.

Часто приходится видеть извращение, когда разрабы пытаются реализовать на JS поведение, что нужно выбрать один элемент из списка.

Опишу подробней в виде кода. Итак, даны стили и список:

<style type="text/css">
    ul li.current { color: red; }
</style>

<ul>
  <li>First</li>
  <li class="current">Second</li>
  <li>Third</li>
</ul>

Как обычно делают разрабы:

$().ready(function() {
    var ul  = $('body ul');

    ul.find('li').click(function() {
        ul.find('li.current').removeClass('current');
        $(this).addClass('current');
    })
})

При таком подходе приходится обходить все элементы списка, что негативно сказывается на производительности, особенно, если списки огромные.

Как нужно делать:

$().ready(function() {
    var ul  = $('body ul');
    var cur = ul.find('li.current');

    ul.find('li').click(function() {
        if (cur.length) {
            cur.removeClass('current');
        }

        cur = $(this);
        cur.addClass('current');
    })
})

Тут мы просто запоминаем текущий элемент. Вроде бы все просто, но чаще всего, почему-то встречается первый подход. Да, кода получилось больше (хотя тут можно его уменьшить), но зато мы меньше теребим DOM.

Некий Karneds написал комментарий, как по его мнению стоит решить этот вопрос. Я было засомневался и убрал пост с главной, чтобы проверить, так ли это на самом деле. Догадка была такая, что сначала при обработке дерева DOM находятся все указанные в селекторе таги и только потом происходит поиск по атрибутам найденных тагов. Чтобы проверить мою догадку я обратился к небезызвестному Сергею Чикуёнку:

Есть список:

<ul>
  <li>First</li>
  <li class="current">Second</li>
  <li>Third</li>
</ul>

Если мы напишем обработчик (jquery):

$('ul li.current').click(function() { ... })

то будет ли это означать, что селектор ul li.current проверит сначала первый элемент списка (First) на наличие класса current, прежде чем совпасть со вторым элементом?

И вот что он ответил:

зависит от браузера. В новых используется встроенный querySelectorAll(), в старых (например IE) будет бегать по элементам, и в данном случае будут проверены все LI-элементы (насколько я знаю, поиск идёт справа налево, то есть сначала выберутся все LI элементы на странице, а потом отфильтруются те, которые находятся внутри UL).

То есть для старых браузеров — да, сначала проверит First (порядок элементов сохраняется)

Так что, догадка подтвердилась. Это, кончно, не касается новых браузеров, которые умеют искать и по атрибутам. Хотя, если текущий элемент будет помечен не атрибутом, а свойством объекта, то всё же касается.

Мораль сей басни - лучше всегда “сохранять” текущий элемент списка в отдельной переменной, а не искать его каждый раз заново.

P.S: Для Тормоза - извиняй, специально для тебя публикую пост с новым адресом, дабы он отметился в RSS ленте.

Собираюсь писать клиентскую библиотеку для работы с XMPP на JS

Воскресенье, Октябрь 31st, 2010

Да, есть такое желание. Объясню, зачем мне захотелось такого извращения.

Я посмотрел все существующие библиотеки на JS для работы с XMPP. Все эти библиотеки стремятся отсылать запросы через BOSH и похожие технологии, но ни в одной из них не реализованы вебсокеты.

Я же хочу простого: пусть у меня будет имплементация jabber-мессенджера на сайте, которая будет работать в реальном времени. Я не хочу отсылать xmpp-запросы с сайта прямо на Jabber-сервер. Вместо этого я хочу написать ретранслятор, который был бы посредником между клиентом (то есть веб-страницей) и jabber-сервером. Эта штука всего лишь будет передавать запросы от клиента jabber-серверу, а от jabber-сервера получать ответы и передавать их клиенту. Мой ретранслятор должен быть выполнен в виде вебсокет-сервера, потому что это обеспечивает наивысшую скорость и убирает весь оверхед, в отличие от того же BOSH.

Кстати, вебсокет-сервер я уже написал, прикрутить туда ретрансляцию на jabber-сервер думаю, не займет много времени.

Вернемся обратно к клиентской части на JS. От нее мне хочется простого - чтобы она умела парсить XMPP, а так же формировать его. Она не будет ничего передавать - только парсить и генерировать. Как дополнение - можно сделать обсервер, который бы реагировал на определенные события, чтобы можно было удобно обновлять интерфейс клиента - но это в виде отдельного компонента.

Я планирую все обдумать и, если мое решение не изменится - открыть проект на Github. Посему, мне требуются помощники, возможно - контрибуторы. Люди нужны такие - те, кто разбираются в XMPP, javascript-разработчики, ruby-разработчики, понимающие в создании socket-серверов.

Немного расскажу о том, почему та штука, которую я хочу сделать, будет прикольна. Достаточно в недалеком будущем мы увидим нечто новое в веб: веб-приложения начнут себя вести совсем как десктопные и даже круче - интерфейс будет обновляться в реальном времени без перезагрузки страницы. Добавил кто-то товар - хоп - в списке товаров появился новый. И так далее. Я считаю, что XMPP подходит для этого весьма и весьма хорошо. Достаточно посмотреть вон там, чтобы убедиться, как будет в скором времени круто.

Так что чуваки. Давайте объединяться. Если возникло желание, отписывайтесь в комментах, там разберемся. Ну и вообще, жду всяческих комментариев по данной теме - может я где-то неправ?

Ссылки:

  1. RFC 3920 — Протокол XMPP: Ядро
  2. XMPP Libraries

Путешествие по Губке Менгера. Javascript + Canvas.

Суббота, Апрель 10th, 2010

Наткнулся на пост у блоггера avva:

Совершенно замечательное демо трехмерного путешествия по губке Менгера. Смотреть в любом браузере, кроме Эксплорера. Весь код укладывается в 512 байт!

Там используется интересный алгоритм, который называется ray-marching. Должно быть не очень сложным и поучительным упражнением сделать unobfuscation всему этому коду и подробно объяснить, как он работает.

Я рекомендую смотреть демо в Google Chrome или Opera. Особенно рекомендую почитать комментарии к записи - там рассказывают, как работает код.

Кода всего ничего (512 байт):

<body bgcolor=0 text=snow onload=N=[K=R.getContext('2d')];for(t=B=127,I=K.getImageData(0,0,q=64,q);t--;$=Math.cos)N[t]=t/43&1;setInterval("t++;for(i=y=-1;y<1;y+=A)for(x=-1;x<1;x+=A=1/32,I.data[i+=4]=h+h)for(m=C=$(a=t/86),S=$(a+8),c=$(b=t/B),s=$(b+8),u=x*C+S,v=y*c-u*s,u=u*c+y*s,w=C-x*S,X=q+9*$(a+b),Y=q+9*$(b-a),Z=t,h=B;--h&&m<q;X+=u,Y+=v,Z+=w)for(m=1;N[X*m&B]+N[Y*m&B]+N[Z*m&B]<2&&m<q;m*=3);K.putImageData(I,0,0)",9)>JSpongy by p01<br><canvas id=R width=64 height=64 style=width:3in;height:3in;background:#fff>

LibCanvas - фреймворк для работы с canvas

Четверг, Апрель 8th, 2010

Месяц назад я написал заметку “Перспективы клиентских технологий в веб“, о том, как на мой взгляд будут развиваться клиентские технологии. Вот выдержка из заметки:

Как думаю я, не будет хватать именно какого-то фреймворка для построения интерфейсов, лайотов и создания векторной анимации.

Такой фреймворк скорее всего появится, и будет основан на технологиях Javascript, SVG и canvas. Возможно, он уже разрабатывается кем-то, но вот я пока об этом не знаю.

Сегодня на хабре один человек разместил статью http://habrahabr.ru/blogs/javascript/90339/, в которой он описал разрабатываемый их фреймворк как раз для тех целей, которые описывались мною в заметке про перспективы клиентских технологий. Так что я был прав в том, куда стремится веб.
Продолжаю следить за сабжем.

Скачать библиотеку LibCanvas можно здесь: http://code.google.com/p/libcanvas/

Перспективы клиентских технологий в веб

Среда, Март 17th, 2010

Откушав чаю, я тут подумал, что в связи со всеми этими новыми технологиями и фишками, такими как HTML5, canvas, SVG и скоростью выполнения JS в современных браузерах, а так же постепенным выпиливанием IE6-7 (а скоро и 8-го), будет, как мне кажется, отход от технологий flash и silverlight.

Спрашивается, почему?

А что - сейчас флэш обычно используют для анимации, видео и аудио. Всё то же самое уже сейчас можно делать на html5, но пока это будет работать не во всех браузерах, а в тех, в которых будет работать, например видео еще работает не так как надо. Но все равно чего-то будет не хватать в HTML5 по сравнению с флэшем. Как думаю я, не будет хватать именно какого-то фреймворка для построения интерфейсов, лайотов и создания векторной анимации.

Такой фреймворк скорее всего появится, и будет основан на технологиях Javascript, SVG и canvas. Возможно, он уже разрабатывается кем-то, но вот я пока об этом не знаю.

Я думаю, будущее именно за такой открытой технологией, в отличие от flash и silverlight - нужно ждать только появления фреймворка и развития технологий в браузерах.

UPD: Действительно, такой фреймворк уже разрабатывается. Подробнее здесь: LibCanvas - фреймворк для работы с canvas

Javascript в nginx

Вторник, Февраль 16th, 2010

Игорь Сысоев, создатель веб-сервера nginx, написал заметку об идее встраивания javascript в nginx, наподобие того, как встроен perl.

Но, как рассказывает Игорь, пока нет возможности правильно встроить V8 в nginx из-за особенностей реализации.
Я вот что-то не могу понять, как тогда появилась такая вещь, как nodejs, которая, при всем при этом, держит огромную кучу запросов (я где-то видел тесты, не помню у кого)?

Или он просто плохо смотрел (в чем я не уверен)?

Короче, буду рад, если мне кто-нибудь разъяснит, чем так кардинально отличается nginx от nodejs, что в nginx пока нельзя корректно встроить v8?

Микрофреймворк fab для nodejs

Среда, Январь 13th, 2010

Наткнулся на замечательный микрофреймворк fab, который позволяет легко создавать простые серверные приложения на языке javascript, для веб-сервера nodejs.

Fab очень похож на ruby-фреймворк Sinatra, который является довольно популярной штукой в среде ruby-девелоперов, так как позволяет сделать легкое приложение, без использования тяжеловесов, таких, как Rails.

Например, так выглядит простейшее приложение в Sinatra:

require 'rubygems'
require 'sinatra'
get '/' do
  'Hello world!'
end

А вот так выглядит точно такое же приложение в fab:

fab = require( "./fab" ).fab;

( fab )
  ( "/", function(){ return 'Hello world!' })
.deploy();

Многословнее, но всё равно круто, да? Единственное там пока нету разделения запросов по REQUEST_METHOD, первой нужнейшей штуки для удобной реализации REST-сервиса.