Постове 1 - 5 от 11 с таг Control Depo

Feb 07

Като цяло тази седмица мина под знака на Rails 3, на който излезе бета версия.

Понеделник 01.02.2010

SafeBuffers and Rails 3.0 – в Rails 3 има вградена xss защита, и Yehuda Katz обяснява последните промени по тази система и защо са се наложили.

8 Chrome Extensions For Web Developers – Напоследък Firefox започва да се държи все по зле и леко да изостава от браузъри като Chrome и Safari. И докато в Safari все още ми липсват 2-3 малки неща, то Chrome може в много скоро време да стане предпочитания ми браузър.

Вторник 02.02.2010

Google Apps Drop IE6 Support – Е време беше. След скорошната атака срещу Google извършена с IE6, Google решиха да дръпнат шалтера на това нещо. В Германия вече го забраниха, така че още малко живот му остава. И усещам как скоро ще се вдигнем мерника към IE7.

One-click Minifier Gadget (OMG) – initial checkin – Българското Yahoo! гуру Стоян Стефанов пусна много полезен инструмент за минимизиране. Кода го има в github. ( Статията е от 31 Януари, но чак във Вторник я видях )

Basic Cappuccino Tutorial - Добър на урок за Cappuccino. Което е добре защото, един от най-големите проблеми на Cappuccino, според мен, е липсата на добра документация и уроци.

How Internet Explorer 8 document mode affects JavaScript – Оказва се че в IE8 имало доста промени по самия JavaScript.  Nicholas C. Zakas разяснява голяма част от тях.

The touch action – В България до голяма степен сме 1-2 години назад в IT отношение. Така че е доста лесно да се предскаже че в следващите години и у нас както навън ще навлязат все повече “умни телефони” и особено такива с touch screen (то май всички са такива). Затова е важно да се знае как може да се работи със touch събитието. В Quirksmode имаше цяла серия за тези събития през седмицата.

an HTML5 offline image editor and uploader application – Наскоро започнах да правя първите залежи за новата ни cms система ControlDepo 4. И мисля в нея да вградя нещото такова в една или друга степен.

HipHop for PHP: Move Fast – Това беше новината на деня. Facebook пуснаха HipHop, което компилира (или по-точно трансформира) PHP кода до оптимизиран C++ код, който след това се компилира с g++. От което е излишно да казвам какви са ползите като скорост и CPU. За повече подробности самия пост и това видео.

Явно вторник е бил много “натоварен” ден. :)

Сряда 03.02.2010

YUI Theater — Douglas Crockford: “Crockford on JavaScript — Volume 1: The Early Years” – Когато Douglas Crockford, говори и Чък Норис слуша :) . В случая говори за история на JavaScript и програмните езици като цяло. Първите 10-15 са необичайно скучни. Главно защото говори за първите компютри и темата е повече насочена към хардуера от колкото към софтуера. Но после нещата се оправят.

Stop Being an Idiot – Колкото пъти сме се оправдавали с това че потребителите са “идиоти”, е време е да спрем.

Четвъртък 04.02.2010

The Rails Module (in Rails 3) -  Rails 3 идва с доста променен Rails module, в който има доста полезни методи. От тази статия може да се научат доста странични неща за Rails като цяло.

Също интересен факт е и че Basecamp стана на 6 години. Като един ден преди това стори и Facebook.  Което като се замисли човек е много странно съвпадение. Защото никои не може да се отрече че и двата продукта косвено или директно промениха мрежата.

Петък 05.02.2010

SD Ruby – Episode 077: Building Your Own Hosting Environment – това стои във readera ми от доста време, но чак в Петък имах време и повод да го гледам. Доста добро ми се стори и ако някои мисли сам да си хоста Rails приложенията ( и даже каквото и да е друго сам да си хоства) е много добра начална точка.

Преч седмица най-сетне намерих една от най-запомнящите реклами, който съм гледал (незнайно защо бях останал с впечатлението  че е за Ferrari, а тя била за Porsche ):

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.

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

May 02

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

Първо започнах да правя малки промени по дизайна

  • сложих да се виждат таговете към даден пост
  • промених (с малко помощ от колега) изцяло извеждането на коментарите
  • формата за добавяне на коментар претърпя малки графични промени
  • тема вече е изцяло на български език (тук таме може да е останало нещо чуждоезично, но малко по-малко що променям)
  • доста по-добра 404 страница, за която използвах от Google Webmaster Tools - Enhance 404 pages
  • промени извеждането на постовете при търсене.

Аз в мрежата

После започнах промени по секциите

  • Добавих нова страница “Аз в мрежата“, в която има информация за част от различните ми регистрации из мрежата. Скоро ще има още връзки, просто на този етап нямам подходящи лога за тази страница (трябваше да има и страница “Аз съм”, но за нея не остана време :( )
  • Добавих “Подобни постове” към всеки пост, като за него използвам плъгина Contextual Related Posts
  • Изтрих от sidebar-a мета информацията и на нейно място сложих таговете в сайта
  • Преминах през Google Webmaster Tools и пооправих някой връзки в сайта, които не работеха, също така промених и няколко meta description-и и други дребни неща

Промени по кода

И след това започнах да работя по интересната част. Докато оправях темата забелязах, че колкото и да е красива от долу като код е просто … ужасна. Още повече самия WordPress не използва нещо като Smarty, и го кара на голо php (в този пост – “Be smart with smarty“, съм си казал мнението за Smarty). Всички шаблони на темата общо взето изглеждаха така:

<?php get_header(); ?>
	<div id="content">
		// кода за съответния шаблон
	</div>
	<div id="footer">
		<a href="...">WP Theme</a> &amp;
		<a href="...">Icons</a> by <a href="...">N.Design Studio</a>
	</div>
</div>
<?php get_sidebar(); ?>
<?php get_footer(); ?>

след малко refactoring в шаблон кода стана така, като преместих общите части в хедъра и футера:

<?php get_header(); ?>
	// кода за съответния шаблон
<?php get_footer(); ?>

Мина ми през главата, дали да не направя някои плъгин за WordPress, който позволява ползването на Smarty и/или layout файлове, подобни на тези които използвам от години в ControlDepo и които ги има в Rails, но в крайна сметка реших, че през лятото най-вероятно ще мина на някое мое блог решение.

След като подредих  и пренаписах шаблоните, се насочих към самата html структура, в която беше пренебрегнато ползването на ul елементи и други дребни неща който ме дразнеха. Но най-големия проблем от който най-вероятно страда доста SEOто на NeXt е че липсваше h1 елемент (т.е. имаше го но просто винаги беше просто NeXt), а той трябва все пак да е заглавието на самата страница.

JavaScript / CSS / Images

Поради използването на много плъгини се беше натрупало огромно количество външни javascript и css файлове, което много вреди на цялостното зареждане на сайта. Така че минах и събрах всичките css файлове в един all.css (останаха само print.css и css файловете от Highlight Source Pro плъгина, но там още не искам да пипам).

С JavaScript нещата седяха малко по сложно поради това че използвах plugin за live търсенето и за още 2-3 малки неща, решението беше да се отърва от всички плъгини и да си напиша собствени версии използвайки ControlDepo 3 Widgets.  От него използвах тези компоненти:

Отделих javascript-a в два файла – all.js и frontend.js ( както права във всичките си проекти напоследък ), Във all.js са библиотечните файлове – Prototype, Script.aculo.us, no.ie6.js, ControlDepo 3 Widgets а във frontend.js са скриптовете специално за блога ми livesearch, widgets и други малки javascript глезотии. По-важното е в случая е това че вече имам стабилна основа върху която да надграждам в бъдеще.

Всички javascript файлове са най-долу, така че няма смисъл да правя dom:loaded а мога директно да изпълнявам кода си. Също така вече и целия код е unobtrusive, и поне на този етап ако даден посетител няма javascript или му е изключен, всичко в сайта ще си работи.

Последната стъпка беше оптимизацията на снимките за това използвах просто ruby gem-a – smusher, който прекарва всяка снимка през smush.it. Така отстраних с около 40 KB размера на всички картинки от блога.

Финални думи

Като цяло за себе си съм си доволен от работата, която свърших по блога. Останаха някои неща за бъдещето:

  • live comment preview
  • най-сетне да имам about страница
  • да взема под IE да видя как се вижда NeXt
  • да се по съберат снимките в css spirites
  • почистване на css файловете, т.е. изтриване на излишните стилове и оптимизация
  • gzip на css / javascript файловете

п.п. от цялото тази работа около WordPress, ми хрумнаха две идеи за plugin, първия да е Smarty, а втория да е нещо подобно на sprockets което събира всички css / javascript във един файл gzip-ва го, добавя му etags и т.н. Незнам дали е възможно да се направи такова нещо с WordPress, ако някой има желание за нещо такова, с удоволствие бих му помагал.