Постове 6 - 10 от 17 с таг code

Jan 31

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

Понеделник 25.01.2010

Yehuda’s – evented programming with jQuery – това се явява като (макар и само косвено) продължение на Creating UI Elements With Low-Coupling And Conditional Event Handling, за което писах миналата седмица. Което за пореден път ми показва, че май javascript компонентите на там са се насочили.

In praise of git’s index – много добра статия за git index-ите.

Вторник 26.01.2010

The Path to Rails 3: Approaching the upgrade и rails-upgrade: Automating a portion of the Rails 3 upgrade process. Rails 3 е почти готов след малко повече от година разработка. И от където и да го погледнеш си е огромна стъпка на пред, даже няколко. В постовете се обяснява за проблеми и съвети при преминаването към Rails 3.

JRuby за Аndroid – време беше. Как ви се струва едно ruby приложение за телефон през JRuby за Android, през MacRuby за iPhone и … (не че някой ще ползва windows mobile), но IronRuby за Windows Мobile. Преди време си бях говорил с познати за такава идея и че на теория е възможно (а според тях на практика не). Но това е още една стъпка в тази посока. Въпреки че анатомиите на iPhone / Android приложенията са доста различни, все повече си мисля, че е възможно да стане нещо такова.

Answering Baranovskiy’s JavaScript quiz – Явно Вторник е бил доста мързелив ден.  Nicholas C. Zakas показва отговорите на js теста на Dmitry  Baranovskiy. Аз с радост мога да се похваля, че само за единия въпрос се подвоумих малко (на този с arguments[2] = 10).

Сряда 27.01.2010

Put that data-* attribute away, son…You might hurt someoneDan Webb е страшно уважаван от мен дивелопър. Беше част от PrototypeJs Core и беше работил по един от първите Rails плъгини за Unobtrusive JavaScript. Да не говорим колко идеи почерпих от неговата LowPro за моя CD3.Behaviors.  За нещастие, доколкото разбрах, вече работи главно с jquery.

Но да се върнем на темата, че малко се отнесох. Тук той обяснява за data-атрибутите и че колкото и да са яки, не трябва да се използват прекомерно. Поста му се явява като отговор на Yehuda’s – evented programming with jQuery.

Четвъртък 28.01.2010

Emile.js talk (video & slides)Thomas Fuchs обяснява неговия mini css animation framework – Emile.js. Който е само 51 реда (+ празните редове и Copyright-а :) ). Много полезно и абсолютно задължително за тези, които не искат цял живот само да ползват неща, които не разбират.

Why Arel – ActiveRecord 3.0 ( който е част от Rails 3 ) е изграден върху Аrel. Като наскоро  излезе и Active Record Query Interface 3.0. Но какво е Arel, ами Relational Algebra (и моята първа реакция като го чух беше – ЪЪъъ). В поста се обясняват мотивите за написването на Аrel. Важно е да се каже, че Arel е напълно отделно от Rails и може се ползва независимо.

The HTML 5 sandbox Attribute Improves iFrame Security – Една от критиките към html5 е, че не помага на този етап за сигурността на мрежата. Това е една малка стъпка напред. Жалко, че май никой не е чувал за <module> тага предложен от Douglas Crockford още в далечната вече 2006.

New ActionMailer API in Rails 3.0 – Голямото пренаписване в Rails 3 върви с пълни сили и сега ActionMailer си намери майстора. (Все пак май ActionMailer си е като недоносеното дете в Rails пакета).

Петък 29.01.2010

По-рано през седмицата Apple обявиха така дългоочаквания iPad. И общо взето никой не го харесва. Като за мен си е просто играчка. На който ако и бяха сложили просто MacOsX щяха да разбият всички, но такъв е живота. Общо взето в Петък имах много работа и нищо интересно не ми попадна. Само 2-3-4… статии за iPad. Всичките еднакви от една страна Apple хейтърите го нареждат от всякъде, Аpple феновете леко разочаровани, поради големите очаквания и само неутралните наблюдатели с положителни оценки (леко резервирани, но положителни като цяло).

Бонус

Седмицата беше много изморителна и затова нямах много време да си прегледам Google Reader-a (все още имам към 200 не прочетени статии). Затова чак днес видях серия от 3 поста от Amix, създателят на Todoist и Plurk, и първият блог, който започнах да следя.

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

Jan 24

Преди една година (ехе толкова ли много време мина от тогава) бях започнал да пиша за интересни неща, които съм видял през изминала седмица и които според мен не са получили подобаващото им се медийно представяне. Само че с времето спрях тази традиция, още преди да се превърне в такава даже. Но тъй като съм решил тази година да отделям малко повече на блога. Ще започвам да по съживявам някои стари идеи и да видим какво ще стане :)

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

Понеделник 18.01.2010

A successful Git branching modelОт доста време вече ползвам само git и съм супер доволен от него. Въпреки това все още ползвам само една малка част от възможностите му.  Затова този пост ми беше много полезен.

Jemini – В Понеделник попаднах и на Jamini това е (J)Ruby famework за правене на игри. Нещо което ми беше мечта когато за пръв път започнах да пиша код.

Вторник 19.01.2010

Creating UI Elements With Low-Coupling And Conditional Event Handling – Не използвам jQuery, но понякога от там излизат доста полезни неща. Този пост на Ben Nadel като цяло е много полезен. Основната идея да се използва нещо като MCV и event архитектура и така да се правят компоненти които взаимодействат по между си, но без да знаят, че го правят. Като от личен опит мога да кажа, че правенето на компоненти които взаимодействат само с custom event-и по между си е страшно яко.

За развитие на темата бих препоръчал и да се гледа Satyen Desai — A Widget Walkthrough, от yahoo винаги са правили страхотни видеота.

Cappuccino On Rails – това не е от Вторник, но тогава го видях. А Cappuccino ( и  SproutCore ) са два проекта, който следя с особен интерес. Още повече интеграцията им с Ruby става все по-лесна :)

Сряда 20.01.2010

Stanford’s Entrepreneurship Corner: David Heinemeier Hansson -  От Stanford Entrepreneurship Corner винаги са вадили интересни материали ( все пак са Stanford ). Забавно беше и началото, един монотонен глас съобщи – “Този запис, може да съдържа език не подходящ за всеки” :D

Интересно беше да го слушаш това и да учиш за поредния безсмислен изпит.

Четвъртък 21.01.2010

Четвъртък го прескочих, все пак учих за изпит, или поне се опитвах. Въпреки това:

Firefox 3.6 is here! – новата версия е тук. Като потребител това което ми харесва е че се усеща колко по-бърза. Също така все повече почва да свиквам с това че като дадеш “open in new tab”  табулацията се отваря до сегашния ти там. Като разработчик няма как да не се зарадвам на CSS3 градиентите, Drag and Drop и File API -то.

Петък 22.01.2010

Fuseboxjdalton направи серия от четири видеота за това какво представляват sandboxed natives и как той ги е реализирал. Като в края на седмицата пусна и самия Fusebox, което е част от от FuseJs, за която все още няма много информация освен че скоро ще се появи. И като гледам списъка с хората които работят ще е нещо добро.

И на края искам да сложа едно видео на Louis CK – “Everythings amazing nobody is happy” ( което го видях от презентацията на Dion Almaer от JSConf – Future of the Web )

Aug 09

В един от последните ми проекти ми се налагаше да генерирам много html елементи с javascript. Като за това основно използвах new Element() и Element#insert от Prototype. Като въпреки че като цяло двата метода са много изчистени и правят кода доста добре четим, винаги може и по-добре.

В началото написах един прост builder, но като малко го поизползвах тук и там, се оказа , че като код е доста по-малко, но не и като четимост. Затова написах и тези две малки добавки към Element#insert които ми спестиха доста писане и направиха кода още по-четим и добър. И същевременно показаха (за пореден път) няколко от добрите страни на Prototype.

Element.insert(element, { into: content });
Element.insert(element, [content, content, content]);

Element#insert(element, { into: content });

Тук просто добавих нов insert position, into. Общо взето е ясно какво прави той добавя елемента в друг елемент. Защото поне на 20 места имах нещо такова(или много подобно:

var element = new Element('div', {/* атрибут */});
document.body.appendChild(element);

// като с into това просто става
var element = new Element('div', {/* атрибут */}).insert({into: document.body });

За тези, които са запознати как работи точно от вътре Element#insert, няма да е никак трудно да разберат как съм добавил ‘into’. Prototype използва един object, който да съхранява всички insert функции – before, after, top, bottom. Той е
Element._insertionTranslations, и когато бива извикан Element#insert(element, {position: content}) се вика грубо казано Element._insertionTranslations[position](element, content). Заради това добавянето на нов insert метод е много лесно и става просто така:

Element._insertionTranslations.into = function(element, node){
	node.appendChild(element);
};

Внимание! Element._insertionTranslations не е част от Public Api-то на Prototype и затова може да се промени в бъдещи версии!

Страничен ефект

Element#insert(element, { into: content }) има много интересен ефект, за който не се бях сетил когато го писах. Но когато случайно “открих” бях много доволен.
Element#insert може да приема не само html елементи, но и нормални javascript обекти, които имат метод toElement ( тои трябва да връща html елемент). И така примерно имам клас подобен на Custom Select класа ми от ControlDepo 3 Widgets, който има един контейнер, към когото може да се добавят елементи. Чрез into могат да се правят такива неща:

var list = new (Class.create({
	initialize: function(ul){
		this.element = $(ul);
	},
	toElement: function(){
		return this.element;
	}
}))('some');

Тук, за декларацията на класа, ползвам прост номер описан, по-добре тук.

Element.insert(element, [content, content, content]);

Идеята тук е да може да се предава масив от елементи, които да се добавят в element.

var ul = new Element('ul');
ul.insert(li1);
ul.insert(li2);
ul.insert(li3);
// ... и т.н.

// като това понякога го пиша и така
[li1, li2, li3].each(Element.insert.curry(ul));

// с новата версия става просто
ul.insert([li1, li2, li3]);

Такава функционалност може да стане по 2 начина. Първо като пиша директно в кода на Element#insert ( или си направя мой си fork на Prototype). И втория вариянт е Function#wrap.

Колкото и да се изкушавам от първия вариант реших само да пусна един билен ( ticket ) на Prototype и да се надявам да го добавят като функционалност.  И след това си написах каквото ми трябваше чрез Function#wrap:

Element.addMethods({
    insert: Element.insert.wrap(function(insert, element, insertation){
        if (!Object.isArray(insertation)) return insert(element, insertation);

        element = $(element);
        insertation.each(insert.curry(element));
        return element;
    })
});

Тези двете добавки ги има в git.github – http://gist.github.com/164751. Там ще ги актуализирам ако правя промяна.

Ако някой има предложение или идея как може да се доразвият тези добавки или за други подобни, може да драсне някои коментар :)

Jul 18

В по-голямата част от PHP кода ми е OOP. Но все пак имам и няколко функции, като три от тях бих искал да споделя тук. Те са tag / func_array_cut / profile.

Функцията tag

Както се и казва функцията tag генерира html тагове. Тъй като в 99% от времето PHP връща html, е много важно да имам нещо с което бързо и лесно да си създавам тагове. Основно тази функция я използвам в различни помощни методи:

function tag($tag, $options, $content = null){
    if (is_string($options) && !is_string($content)){
        list($content, $options) = array($options, $content);
    }

    $attributes = '';

    if (is_string($options)){
        $attributes = ' ' . $options;
    } else if (is_array($options)){
        foreach($options as $key => $value){
            $attributes .= ' ' . $key . '="' . htmlspecialchars($value, ENT_COMPAT, 'utf-8') . '"';
        }
    }

    return '<' . $tag . $attributes . (is_string($content) || strlen($content) > 0 ? ">{$content}</{$tag}>" : ' />');
}

Таg може да се извиква по няколко начина, като основната ми идея беше да не се налага да се замислям кои аргумент какъв е – атрибут или текст.

// <input type="text" value="text" />
tag('input', array('type' => 'text', 'value' => 'text'));

// <input type="text" value="&quot;qoute&quot; text" />
tag('input', array('type' => 'text', 'value' => '"qoute" text'));

// <div>content in div</div>
tag('div', 'content in div');

// 3 начина за генериране на
// <a href="http://www.pixeldepo.com">Pixeldepo</a>
tag('a', array('href' => 'http://www.pixeldepo.com'), 'Pixeldepo');
tag('a', 'Pixeldepo', array('href' => 'http://www.pixeldepo.com'));
tag('a', 'href="http://www.pixeldepo.com"', 'Pixeldepo');

Функцията array_cut

Едно нещо което е изключително досадно в STRICT режима на PHP, е непрекъснатите проверки isset / empty за това дали в даден масив има даден ключ. Затова създадох array_cut, тя проверява дали в дадения масив го има ключа и ако го има му връща стойността, ако я няма връща $default стройност. Като същевременно ключът се изтрива от оригиналния масив.
Това като се замисля е първата функция която написах за PHP framework-а който използвам ControlDepo 3.

function array_cut(array &$array, $key, $default = null){
    if (!isset($array[$key])){
        return $default;
    }

    $value = $array[$key];
    unset($array[$key]);

    return $value;
}

Тази функция е изключително полезна и може да се използва в редица случаи, ето два примера:

// това може да се напише така:
$name = isset($_POST['name']) ? $_POST['name'] : '[no-name]';
// може да се напише така:
$name = array_cut($_POST, 'name', '[no-name]');

// използване на array_cut за примерна функция за генериране на url-та
function url($options){
    $url = '/' . join('/', array_filter(array(
        array_cut($options, 'controller'),
        array_cut($options, 'action', 'index'),
        array_cut($options, 'id')
    )));

    if ($query = http_build_query($options)){
        $url .= '?' . $query;
    }

    return $url;
}
// използване
// -> /products/view/1
url(array('controller' => 'products', 'action' => 'view', 'id' => 1));

// -> /users/index?page=1
url(array('controller' => 'users', 'page' => 1));

// -> /index?sort=name
url(array('sort' => 'name'));

Преди време си мислех, че в PHP5.3/6 смисълът от функцията ще се намали след като се добавиха ?: и  ifsetor. Но просто ?: не е толкова мощен колкото ми се искаше, а ifsetor няма да го има.

Функцията profile

Докато другите 2 функции ги използвам много (и също така цялото ControlDepo 3 ги ползва). Функцията profile() е просто бърз начин за замерване, докато работя. В действителност тази функция се използва чрез чрез друга моя функция p(), която просто вика profile(), но записва резултата в лога на request-a и така малко по-лесно може да го анализирам резултата:

function profile($scope = '__default__'){
    static $time = array();

    if (isset($time[$scope])){
        return microtime(true) - array_cut($time, $scope, 0);
    }

    $time[$scope] = microtime(true);
}

Тя се ползва просто така:

// имаме 2 нива на profile
profile('test');
sleep(1);

profile();

sleep(1);

echo profile(), "\n";
echo profile('test');

Надявам се тези 3 функции да са полезни на някои и ако някои има идеи как може да се подобри някоя от тях, ще се радвам да го сподели.

Jun 15

Доста често напоследък ми се налага да правя динамични страници изцяло задвижвани от javascript, като при тях постоянно се добавят и махат dom елементи. Което значи непрекъснато да се добавят и махат event хандлъри, което е меко казано досадно и води до много грешки. Но с вградените в CD3.Behaviors event delegation функции (за тях специално ще има поне един цял пост) тази работа е много лесна, просто делегирам всички действия към елементи които няма да се променят.

До тук всичко звучи много добре, но както винаги IE се появява на сцената с бъг, който е, че submit действието няма bubbling (т.е. не се делегира към родителските елементи на формата). Което е в пълен разрез със спецификация, но какво да се прави свикнали сме.

Този проблем го знам от много време и винаги го заобикалях по един или друг начин. Но наскоро на колега му трябваше бързо решение, което да може да ползва на 2 – 3 места затова за няколко минути написах това за Prototype.js:

Element.addMethods({
    delegateSubmit: function(element, callback){
        return $(element)
            .observe('click', function(e){
                if (e.findElement('form') && e.findElement('input[type=submit],input[type=image]'))
                    callback.call(this, e);
            })
            .observe('keyup', function(e){
                if (e.keyCode  == Event.KEY_RETURN && e.findElement('input') && e.findElement('form'))
                    callback.call(this, e);
            })
        }
});

Като цяло това, което прави тази функция е, че наблюдава за натискане на submit или image бутони или за натискане на enter върху някои input. Лошото в случая е, че страдат и нормалните браузъри като Firefox или Safari.

Затова направих нова версия, която засича дали submit се делегира (за начина, по който разбирам пише по-подробно в тази статия – Detecting event support without browser sniffing)

Element.addMethods({
    delegateSubmit: (function(){
        var el = document.createElement('div'), isSupported = 'onsubmit' in el;

        if (!isSupported){
            el.setAttribute('onsubmit', 'return;');
            isSupported = typeof el.onsubmit == 'function';
        }

        return isSupported ? function(element, callback){
            return Event.observe(element, 'submit', callback);
        } : function(element, callback){
            return $(element)
                .observe('click', function(e){
                    if (e.findElement('form') && e.findElement('input[type=submit],input[type=image]'))
                        callback.call(this, e);
                })
                .observe('keyup', function(e){
                    if (e.keyCode  == Event.KEY_RETURN && e.findElement('input') && e.findElement('form'))
                        callback.call(this, e);
                    })
        };
    })()
});

Това е доста по-добро решение което оправя проблема със submit само, когато има такъв проблем.

Тук бих могъл примерно да използвам Function.wrap върху Event.observe, но нещо не съм фен такива monkey patching неща. А и по-скоро това и хака за делегиране на focus/blur под IE ще са част от моята Event.delegate, която ако имам късмет ще е част от Prototype.js.

Ако някой има по-елегантно решение, няма да му се разсърдя ако го сподели.