Фев 03

Видео: Firefox developer tools

Скачать новый Firefox (beta): http://blog.mozilla.com/futurereleases/2011/12/23/firefox-beta-with-new-developer-tools-and-enhanced-sync-is-ready-for-testing/

Теги:
Янв 30

http://pimpmyjs.com/ – Uglify or Beautify your JavaScript, it’s your choice… (minify js online)

На jquery.min.js выдал ошибку, но в общем работает, и причём быстро.

Теги:
Янв 28

Основная идея – проверять перед сохранением данных значение navigator.onLine и слушать события online (для сохранения на сервере), offline (для сохранения в localStorage) и load (для загрузки несохранённых данных на сервер при загрузке страницы после подключения к сети).
Continue reading »

Теги:
Янв 26

The Top 10 Javascript MVC Frameworks Reviewed
Лучшим признан Ember.js. Надо поковырять)

UPD: поковырял. В принципе, более стройная архитектура, чем у того же backbone, у которого часть логики контроллера во вью. Но из коробки нет router и не так просто с pushState, так что не стал использовать серьёзно. Возможно, через полгода-год этот фреймворк будет интереснее.

Теги:
Янв 24

http://videojs.com/

Теги:
Янв 24

https://github.com/bartaz/impress.js.
Вот что получается: http://bartaz.github.com/impress.js/#/bored.
Кстати, есть и описание на хабре – http://habrahabr.ru/blogs/css/136505/

Теги:
Янв 23

http://popcornjs.org/ – позволяет показывать видео и другой контент пользователю без использования flash.
Есть большой каталог примеров:
http://popcornjs.org/Demo/semantic-video, http://popcornjs.org/Demo/popcorn-remote

Теги:
Ноя 25

Использовали мы на проекте одну лебедевскую библиотеку – include.js. Умеет она интересные вещи, вроде последовательной загрузки зависимых библиотек в нужном порядке. Нужно в яваскрипте написать js.include( ‘my/coolwiidget’ );. Работает она, если на пальцах, следующим образом: делается ajax-запрос, которым грузится текст нужного скрипта, потом ищутся в тексте все js.include, делается их подгрузка, после чего делается eval полученных текстов в обратном порядке. При этом ещё и отсекаются попытки по несколько раз грузить один и тот же яваскрипт.
Работал он очень неплохо, хотя и неудобно было в firebug-е искать скрипт по его имени.
Основная проблема встала, когда стало нужно вынести все яваскрипты на отдельный домен. Вот тут-то и проявились проблемы – ajax-ом нельзя грузить код с других доменов. Помогает заголовок Access-Control-Allow-Origin, но его понимают только современные браузеры (к примеру, firefox с версии 3.5), а на проекте критична максимально возможная совместимость (как обычно и бывает). Так что этот способ может быть актуален года через 3-5.
Посмотрели на другие способы, в итоге пришли к динамическому добавлению тега script в head, но особого смысла в этом нет, т.к. зависимости, для которых и городился изначально огород, при этом способе не отслеживаются (JSONP с колбэками не подошёл, т.к. в проекте много legacy-кода, который использует глобальные переменные, причём даже не как константы).
В итоге было принято гениальное в своей простоте решение – отказаться от всех этих изысков нафик и грузить скрипты как раньше – при загрузке страницы.

Ноя 16

Выбирал между backbone (habrahabr.ru/blogs/javascript/118782/) и knockout (http://habrahabr.ru/blogs/javascript/121926/).
Для выбора полезно почитать stackoverflow.com/questions/5112899/knockout-js-vs-backbone-js-vs.
В итоге выбрал knockout – менее монструозный и лично мне показался понятнее, к тому же не навязывает REST и не требует дополнительных библиотек.
Он реализует паттерн MVVM, который, думаю, больше подходит для клиентской части web-приложения, чем MVC.
На сайте есть подробные доки и очень удобный интерактивный туториал.
Пока в проектах не использовал, так что писать особо нечего(

Теги:
Ноя 11

Сегодня из-за очередных проблем с sol.adbureau.net было решено реализовать ленивую загрузку баннеров.
Начальное решение было использовать iframe, но идея была не очень удачной, т. к. могут быть проблемы с подсчётом кликов, да и модные картинки, увеличивающиеся при наведении, будут вести себя странно. А как этот iframe смотрится в разных браузерах – это вообще сказка)
В итоге родилась идея: при генерации страницы размещать в нужных местах, к примеру, пустые дивы с id с нужным префиксом (<div id=»js-advert-place-{num}»></div>), а сами баннеры загружать в футер вот в такую, к примеру, разметку:

<div id="js-all-advert-block" class="all-advert-block">
	<div class="js-advert-block-content" data-number="1">
		{баннер}
	</div>
	<div class="js-advert-block-content" data-number="5">
		{баннер}
	</div>
	<div class="js-advert-block-content" data-number="15">
		{баннер}
	</div>
</div>
{здесь грузится счётчик показов}

После загрузки страницы размещаем все баннеры на нужных местах:

	(function( $ ) {
		function moveAdvert() {
			$( '#js-all-advert-block' ).find( '.js-advert-block-content' ).each( function() {
				var $oldContent = $( this );

			// в ие перемещаем
				if ( $.browser.msie ) {
					$( "#js-advert-place-" + $oldContent.data( "number" ) ).append( $oldContent );
				}
			// в других браузерах убираем лишнее и вставляем заново
				else
				{
					var cleanedContent = $oldContent.html().replace( /document\.write/gi, 'function a__(){}' );

					$( "#js-advert-place-" + $oldContent.data( "number" ) ).html( cleanedContent );
					$oldContent.remove();
				}

			// этот вариант менее хороший - глюки в ие и проблемы с яндекс.директ

			//	var $newContent = $.browser.msie ? $( $oldContent.html() ) : $oldContent.clone( true );

			//// не надо заново создавать скрипты - они заново выполнятся, а там document.write
			//	$newContent.find( "script, link" ).each( function() {
			//		$( this ).remove();
			//	} );

			//// вставляем
			//	$( "#js-advert-place-" + $oldContent.data( "number" ) ).html( $newContent );

			//// на старом месте нужно убить всё, кроме скриптов
			//// (в скриптах могут быть необходимые для правильного подсчёта кликов переменные)
			//	$oldContent.find( '*' ).each( function() {
			//		var $el = $( this );
			//		if ( ! $( 'script, link', $el ).length && this.tagName.toLowerCase() != 'script' && this.tagName.toLowerCase() != 'link' ) {
			//			$el.remove();
			//		}
			//	} );
			} );
		}

		$( document ).ready( function() {
			moveAdvert();
		} );
	}( jQuery ));

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

UP:
Всё-таки проблем оказалась куча. К примеру, opera 10.10 (хотя у меня 11.52) некорректно понимает тег script при .html( cleanedContent ), поэтому приходится чистить все теги script, но тогда умирает yandex.direct. К сожалению, на проекте нет нормальной возможности отделить директ от остальной рекламы (нет возможности объяснить тем людям, как что нужно настраивать), поэтому этот способ подходит с большими оговорками.
UP2: Наткнулся на гениальное решение – переопределить document.write, потом немного доработал и вот что получилось:

(function ( $ )
{
	// для собирания тега script
	var previousValue = '',
	// для проверки, собрали ли уже полный тег script
		reTestIfScript = new RegExp( '<\/scr' + 'ipt>$', 'i' ),
	// чтобы найти id дива, куда вставлять код соли
		reGetSolId = new RegExp( "sol\\.adbureau\\.net[^>]+aamsz=(\\d+x\\d+)", 'i' ),
	// для проверки, что это относится к яндекс-директу
		reYandexDirect = new RegExp( "an\\.yandex\\.ru", 'i' );

// заменяем стандартные методы
	document.writeln = document.write = function(value)
	{
	// если последовательно пишут в документ для получения тега script (document.write( '<SCR' ); document.write( '<IPT src="...' );)
		try {
			$( value );
		}
		catch ( e )
		{
			var joinedValue = previousValue + value;
		// сли собрали полный тег скрипт, то вставляем его, куда надо
			if ( reTestIfScript.test( joinedValue ) )
			{
				value = joinedValue;
				previousValue = '';
			}
		// если начали писать тег скрипт, продолжаем до сбора всего тега
			else if ( joinedValue.toLowerCase().indexOf( '<sc' ) == 0 )
			{
				previousValue = joinedValue;
				return;
			}
		// непонятно что это - ничего не делаем
			else {
				return;
			}
		}

		var parentNodeId,
			matches;
	// если в строке есть упоминание яндекса - вставляем в яндекс
		if ( reYandexDirect.test( value ) ) {
			parentNodeId = 'adv_media';
		}
	// если в строке есть упоминание соли - ищем id и вставляем в нужный div
		else if ( matches = value.match( reGetSolId ) ) {
			parentNodeId = 'sol' + matches[1];
		}

	// скрипт вставляем только в нужный элемент
		if ( $( value )[0].tagName == "SCRIPT" && parentNodeId )
		{
			var js = document.createElement( 'SCRIPT' );
			var obj = document.getElementById( parentNodeId ).appendChild( js );

		// подгрузка внешнего скрипта
			if ( $( value ).attr( 'src' ) !== "undefined" ) {
				$( obj ).attr( {type: 'text/javascript', 'src': $( value ).attr( "src" )} );
			}
		// выполнение скрипта
			else
			{
				var reReplaceWrite = new RegExp( '(document\\.write[a-zA-Z]{0,2}\\([^)]+)(\\))', 'ig' );
				eval( $( value ).text().replace( reReplaceWrite, "$`$1, '" + parentNodeId + "'$2$'" ) );
			}
		}
	// стили ставим в head
		else if ( $( value )[0].tagName == "LINK" )
		{
			var js = document.createElement( 'LINK' );
			var obj = document.getElementsByTagName( 'head' )[0].appendChild( js );
			$( obj ).attr( {rel: 'stylesheet', 'href': $( value ).attr( "href" ) , type: 'text/css'} );
		}
		else if ( $( value )[0].tagName == "STYLE" )
		{
			if ( $.browser.msie ) {
				var css = document.createElement( 'STYLE' );
				document.documentElement.firstChild.appendChild( css );
				$( obj ).attr( {type: "text/css"} );
				css.styleSheet.cssText = $( value ).html();
			}
			else {
				$( value ).appendTo( $( "head" ) );
			}
		}
	// любой другой элемент вставляем в DOM, только если поняли, в какой элемент вставлять
		else if (  parentNodeId ) {
			$( value ).appendTo( $( "#" + parentNodeId ) );
		}
	};
}( jQuery ));

Всё бы ничего с этим решением, и даже знает, как собирать тег script из кусочков, но всё-таки мы не можем знать, в какое место DOM должна была производится запись, так что там есть костыли с определением места по контенту, и это решение не универсально.

preload preload preload