Aug 21

Преди 2 дни видях в Ajaxian - A simple solution to the “other” problem with select boxes, което представлява решение на “другия” проблем, както би се превело буквално. Всъщносто там е представен jquery код с който когато от даден html select избереш “друг(other)” ти се появява input поленце където да кажеш какво точно е това другото. Вижте демо-то, защото май не го обясних добре.

Като идея е добре, но нещо jquery кода не ми се вижда много читав:


$(document).ready( function () {
	$('.leader').each( function () {
		var name = $(this).attr('name');
		if ($(this).val()!='other') {
			$(this).next().removeAttr('name').hide();
		 }
	});

	$('.leader').change(onChange);

	function onChange(){
		var desiredName = $(this).attr('name');
		if ($('#'+desiredName).val()=='other') {
			$('#'+desiredName).next().attr('name',desiredName).fadeIn('fast');
		} else {
			$('#'+desiredName).next().removeAttr('name').fadeOut('fast');
		}
	}
});

Много бях изненадан, че това стигна до Ajaxian (въпреки че доста са свалили летвата напоследък). В този код има няколко неща, които не ми харесват:

  1. 2 пъти прави почти едно и също,  избира всичките елементи с клас “leader” и проверява дали е избрана като стойност “other”, за да покаже/скрие следващия елемент.
  2. 2 пъти прави $(’.leader’), като явно е забравил, че едно от най-яките неща в jquery e changing-a. Спокойно е можел да направи просто $(’.leader).each( … ).change( … )
  3. на 3тия ред ( var name = $(this).attr(’name’) ), защо го има това и какво прави така и не разбрах, никъде в този scope не ползва name променливата, а и аз лично бих ползвал getAttribute за извличане на атрибута.
  4. в each-a се вика 3 пъти $() за един и същ елемент ( this в случая), по-добре е добре да се вземе jQuery инстанцията и да се запише в променлива - ще бъде доста по-бързо, когато се ползва.
  5. аз лично нямаше да сложа скобите на if-a в each-a, защото когато се пише javascript всеки байт е важен
  6. така и не ми стана ясно защо декларира функция onChange като може да ползва директно анонимна функция при $(’.leader’).change( … ).
  7. тук добре е направил, че е взел desiredName и го сложил в променлива, но ако някой ми каже защо при положение, че има this му трябва цели 3 пъти да вика jquery css selector с #id (и даже да не го записва в поменлива) ?!?
  8. малко ме подразниха и излишните празни редове и разстояния

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


$(document).ready(function(){
	$('.leader').change(function(
		var select = $(this);
		if(select.val() == 'other')
			select.next().attr('name', select.getAttribute('name')).fadeIn('fast');
		else
			select.next().removeAttr('name').fadeOut('fast');
	)).triggerHandler('change');
});

естествено и моята версия не е перфектна, даже davecardwell е написал доста по-добра версия.  Даже John-David Dalton е направил и Prototype версия : http://pastie.org/255119, от която най-много ми хареса допълнението на Element.fire, която я очаквам в новата версия на Prototype :)

п.п. Някои хора виждат и проблем, че само при стойност “other” се появява полето “други” и ако имаш два или повече езика би било проблем. Обаче аз виждам нещата така - това би бил селекта за български език например:


<select name="language">
	<option>Български</option>
	<option>Английски</option>
	<option value="other">Друг ...</option>
</select>

т.е. value може и да е “other” но за потребителя да е всеки избран език ;)

Aug 09

Наскоро, един приятел ме помоли да му направя проста програмка, няма да изпадам в подробности за това какво точно трябваше да има в програмката. И аз реших да я направя по най-простия начин, за който се сетих - Adobe AIR( винаги ми е било странно защо му викат Adobe AIR, защото до колкото знам AIR e Adobe Integrated Runtime…). Някой хора биха се сетили за нещо от типа на JAVA или Flash/Flex подобни, но за мен някак си AIR-a е доста по-интересен и удобен.

Та реших още и да не ползвам стандартната си JavaScript библиотека Prototype, още повече че малко през зъби бих казал че за момента Prototype и AIR не се разбират на 100% (което до версия 1.6.1, да се надявяме, ще се оправи). И така ми останаха 2 избора - jQuery и Mootools. Предпочетох Mootools защото ми е някак си по-близо до сърцето, а и Prototype и Mootools за мен са като 2 разклонения на една идея, така че почнах.

Програмката стана доста бързо и доста добре :) и като цяло Mootools-a се оказа доста удобен, въпреки че имахме някои пререкания. Като например:

  • addEvent в Mootools e observe в Prototype
  • addClass, removeClass, hasClass в Mootools са addClassName, removeClassName, hasClassName в Prototype
  • new Class({ … }) в Mootools e Class.create({ … }) в Prototype
  • getNext, getPrevious, getParent, getFirst, getChildren в Mootools са горе-долу next, previous, up, down, select
  • …. общо взето такива са разлики

Естествено има неща който в Mootools ги има а в Prototype ги няма, но те не са толкова сложни, че да не може да се добавят от Prototype в Mootools и обратно. Например нещата който най-много ми харесаха в Mootools бяха:

  • Class.Extra - наистина страхотна идея, много полезни и даже си мисля да си ги вложа във версията на Prototype, която ползвам
  • Assets.image - това не го ползвах в AIR, но просто е безценно, защото не мога да кажа колко пъти аз и колеги сме имали проблеми с не заредени снимки (под IE6 главно)
  • Array.link - наистина интересен метод, който доста ми помогна във функциите с “неясни” аргументи
  • DomReady - и това в AIR не го ползвах, а и в Prototype си имаме dom:ready но той под IE6 не работи добре
  • FX - ефектите в Script.aculo.us са доста повече и са ми по-удобни, но тези са по-бързи и доста по “стабилни” като се говори за preformance. Това ще се промени със Script.aculo.us 2.0 / Scripty, … но то още не е готово, а и поне за сега ги няма стандартните ефекти и трябва да се правят ръчно.

Поне това са основните неща който настина ми харесаха в Mootools (сигурно и други щеше да има ако бях работил повече).

Но и доста неща с който бях свикнал в Prototype, а в Mootools ги нямаше. Няма да ги изреждам защото не са малко. Но както казах по-горе и Mootools и Prototype позволяват да се добавят extendet и то по доста лесен начин и за това си port-нах 2-3 неща:

Тъй като много ми липсваше Enumerable модула от Prototype и особено invoke метода реших да си го добавя:


Array.implement({
	invoke: function(method){
		var args = $A(arguments).slice(1);
		return this.map(function(value) {
			return value[method].apply(value, args);
		});
	}
});

Тук искам да кажа само, че много ми харесаха implement методите който са вградени към по-голямата част от Mootools Native обектите, за което в Prototype се използва Оbject.extend и prototype атрибута на съответния обект.

Mootools има Element.inject(el[, where]) и Element.grab(el[, where]), но Prototype има Element.insert което според мен е доста по-добра от 2те функции който са в Mootools


Element.implement({
	insert: function(insertions){
		if ($type(insertions) == 'element' || insertions.toElement)
			insertions = { bottom: insertation };

		for(var insert in insertions){
			var element = insertions[insert];
			Element.Inserters.get(insert, this, $(element.toElement ? element.toElement() : element, true));
		}

		return this;
	}
});

Това е само елементарта форма на Protoype фунцията защото в истинската Element.insert се приемаха и само html елементи и класове, и чист html код. Но, това не ми се наложи да го ползвам и за това не си играх да го port-вам.

Други две малки “подобрения”, който сложих бяха:


Event.implement({
	findElement: function(pattern){
		return this.target.match(pattern) ? this.target : this.target.getChildren(pattern)[0];
	}
});

function $w(string){
	if ($type(string) != 'string') return [];
	string.trim();
	return string ? string.split(/\s+/) : [];
}

Общо взето това са моите наблюдения (малко по-дълги се оказаха от колкото си мислех :) ). Поне за сега за мен Prototype си е номер 1, но и Mootools е много добра алтернатива (особено ако Prototype, не си оправят Adobe AIR съпорта ). А и Mootools ми е някак си твърде “лъскав”, докато prototype ми се струва по “hardcore”, но това си е мое мнение.

То дефакто дали човек избере Mootools, jQuery, Prototype, YUI, ExtJS, …. все ще е прав :)

п.п. ако някой има намерение да се занимава със Adobe AIR и Mootools непременно да погледне Snippely от кода му и от него като цяло могат да се научат безценни неща :)

Mar 10

Наскоро ми се наложи в едни проект да има малко каре където се сменят през определен период от време няколко div елемента. По принцип съм фен на Prototype, но за този проект това щеше да е всичкия JavaScript и малко безсмислено ми се виждаше да слагам целия Prototype. И затова реших да пробвам йQuery, която е доста популярна напоследък. И затова, написах това парченце код, целта беше да е малко, затова е малко неразбираемо.


$(document).ready(function(){
	var interval = setInterval(function(){
		var next = $('#news .current').css('display', 'none').removeClass('current').next();
		(next.length  ? next : $('#news .article').eq(0))
			.css('display', 'block').addClass('current');
	}, 5000);
});

Синтаксиса е на JQuery е доста интересен и лесно се свиква с него, въпреки че има 2-3 места където се различава от Prototype.

След като направи JQuery версията си викам: “Я да видим колко ще е различна Prototype версията “, и написах това:


document.observe('dom:loaded', function(){
	new PeriodicalExecuter(function(){
		var news = $('news');
		(news.down('.current').hide().removeClassName('current').next() || news.down('.article'))
			.show().addClassName('current');
	}, 5);
});

Няма голяма разлика като PeriodicalExecuter можи да си е прост setInterval. Разликите който усетих най-осезателно са че JQuery обекта е колекция от обекти и всички операции който се правят се правят за колекцията. Докато Prototype просто допълва native обектите и прави кода да изглежда като все едно се работи със стандартното API на JS.

Кое ви се вижда по-нормално според мен е въпрос на навик и стил.

p.s. Тази статия от Дъстин Диаз, доста добре нагледно показва как работи JQuery от вътре. Въпреки че статията не за jquery, основния принцип на работа на jquery е подобен (До колкото знам).