Есть у меня такая забава — «велосипед». Нет, речь не о экологически чистом виде транспорта. Люблю придумывать, что-то новое. Но когда тема уже заезженная, и задача уже была решена до того множество раз во всевозможных вариациях, поиск пусть и нового, но очередного решения — «велосипед». Ну, вы понимаете. Очередной велосипед… На практике, для меня, это один из основных способов обучения.
Решил основательно разобраться с JavaScript (до того употреблял его часто, но исключительно по нужде, с биодобавками и витаминами, в виде блюда под названием JQuery). Результат мне показался интересным, а, в связи с прочтением о ElementTraversal — решил, что возможно он будет интересен и еще кому-то…
О том, как я до этого дожил…
Есть у меня такая забава — «велосипед». Нет, речь не о экологически чистом виде транспорта. Люблю придумывать, что-то новое. Но когда тема уже заезженная, и задача уже была решена до того множество раз во всевозможных вариациях, поиск пусть и нового, но очередного решения — «велосипед». Ну, вы понимаете. Очередной велосипед… На деле, для меня, это один из основных способов обучения.
Первое, что хочется сказать, я не являюсь программистом (хотя и имею высшее образование в сфере компьютерных технологий). Я дизайнер (официально сейчас называюсь арт-директор, но суть та же), в самом широком смысле этого слова (а не художник-оформитель, с которыми у нас в стране принято ассоциировать данную профессию, хотя, опять же, имею среднее художественное образование и порядка двадцати сертификатов по различным народным промыслам, которым обучался в школьные годы). Говоря проще, основным своим профессиональным навыком я считаю способность находить оригинальное, а в идеале оптимальное, решение поставленной задачи. И, «велосипед» — неотъемлемая часть процесса. И целью этого лирического отступления является попытка обратить ваше внимание, не на характеристики прилагаемого кода, а именно на характеристики предлагаемого подхода.
Изначально, конечно в связи с необходимостью в лото и гимназистках (чтоб кроссбраузерно и при необходимости еще можно было использовать и в других языках, после минимальной модификации), принял решение использовать для этих целей DOM (можно подумать были еще варианты). После утилизации соответствующей макулатуры, на тему «как другие живут», понял, что подходов, помимо использования DOM в чистом виде, что довольно утомительно, не много: пять соответствующих функций из книги Джона Ресигна «ProJavaScript», уже упомянутый ElementTraversal (по сути, те же пять функций плюс еще одна, для получения количества дочерних элементов), ну или попытки вида XML Simple в PHP. Как по мне, так либо можно и понагляднее, либо менее монструозно.
Далее были творческие муки (как неотъемлемая часть творческого же процесса), периодически прерываемые возгласами: «Сссссс…а! Да почему же не работает!». И прочее, что вряд ли представляет для вас интерес. Итак, наконец-то, результат.
Класс для хранения ссылки на элемент и необходимых функций для работы с ним (по умолчанию задается корневой элемент документа):
Метод для нахождения элемента, предшествующего текущему (либо элмементу переданному методу в качестве параметра), с той поправкой, что множество считается цикличным, то есть последний элемент в множестве считается предыдущим по отношению к первому:
Метод для нахождения элемента, следующего за текущим (либо переданному методу в качестве параметра), по своему действию обратный описанному ранее:
Метод для нахождения родительского (внешнего) элемента, по отношению к текущему (либо переданному методу в качестве параметра):
Метод для нахождения первого дочернего (внутреннего) элемента, по отношению к текущему (либо переданному методу в качестве параметра):
Методы меняют ссылку внутри экземпляра класса значение которой можно получить, как видно из кода посредством метода get() и установить методом set(). Возвращают в качестве своей работы сам объект (о да JQuery травмировал мою психику, да и не только мою я думаю).
Результат:
Потом после использования на практике (в последующих экспериментах с JavaScript, а позднее и с переносом этой механики на Ruby и PHP, где использовал ее в парсинге XML документов), появился еще один метод, который как мне видится (а точнее формат шаблона передаваемый ему в качестве параметра) и является тем что может представлять для вас интерес (следовательно и причиной написания этой статьи на Хабре). Методу для выполнения последовательности действий согласно шаблону (аналогичный «первый вагон из центра, налево, налево, до столба, там справа и будет»), в котором переход к родительскому элементу соответствует символ «<», первому дочернему «>», предшествующему «-», следующему «+» (пример: цепочке .outer().next().inner().previous().previous() соответствует шаблон “<+>--”):
Предыдущий пример можно переписать так:
Послесловие: есть мысль добавить возможность указания в шаблоне количества итераций (чтобы можно было вместо “>>>++++++” писать “>3+6”), но пока не реализовал.
Еще одно послесловие: вообще интересуют кого подобные эпосы, стоит писать подобное впредь или на Хабре не место подобной лирике?
Решил основательно разобраться с JavaScript (до того употреблял его часто, но исключительно по нужде, с биодобавками и витаминами, в виде блюда под названием JQuery). Результат мне показался интересным, а, в связи с прочтением о ElementTraversal — решил, что возможно он будет интересен и еще кому-то…
from = new Target;
// получить предпоследний дочерний элемент для следующего за текущим
node = from.next().inner().previous().previous().get();
О том, как я до этого дожил…
Есть у меня такая забава — «велосипед». Нет, речь не о экологически чистом виде транспорта. Люблю придумывать, что-то новое. Но когда тема уже заезженная, и задача уже была решена до того множество раз во всевозможных вариациях, поиск пусть и нового, но очередного решения — «велосипед». Ну, вы понимаете. Очередной велосипед… На деле, для меня, это один из основных способов обучения.
Первое, что хочется сказать, я не являюсь программистом (хотя и имею высшее образование в сфере компьютерных технологий). Я дизайнер (официально сейчас называюсь арт-директор, но суть та же), в самом широком смысле этого слова (а не художник-оформитель, с которыми у нас в стране принято ассоциировать данную профессию, хотя, опять же, имею среднее художественное образование и порядка двадцати сертификатов по различным народным промыслам, которым обучался в школьные годы). Говоря проще, основным своим профессиональным навыком я считаю способность находить оригинальное, а в идеале оптимальное, решение поставленной задачи. И, «велосипед» — неотъемлемая часть процесса. И целью этого лирического отступления является попытка обратить ваше внимание, не на характеристики прилагаемого кода, а именно на характеристики предлагаемого подхода.
Изначально, конечно в связи с необходимостью в лото и гимназистках (чтоб кроссбраузерно и при необходимости еще можно было использовать и в других языках, после минимальной модификации), принял решение использовать для этих целей DOM (можно подумать были еще варианты). После утилизации соответствующей макулатуры, на тему «как другие живут», понял, что подходов, помимо использования DOM в чистом виде, что довольно утомительно, не много: пять соответствующих функций из книги Джона Ресигна «ProJavaScript», уже упомянутый ElementTraversal (по сути, те же пять функций плюс еще одна, для получения количества дочерних элементов), ну или попытки вида XML Simple в PHP. Как по мне, так либо можно и понагляднее, либо менее монструозно.
Далее были творческие муки (как неотъемлемая часть творческого же процесса), периодически прерываемые возгласами: «Сссссс…а! Да почему же не работает!». И прочее, что вряд ли представляет для вас интерес. Итак, наконец-то, результат.
Класс для хранения ссылки на элемент и необходимых функций для работы с ним (по умолчанию задается корневой элемент документа):
// Target
Target = function ( element ) {
var _element = element || document.documentElement;
this.get = function () { return _element }
this.set = function ( element ) { _element = element || document.documentElement }
}
Метод для нахождения элемента, предшествующего текущему (либо элмементу переданному методу в качестве параметра), с той поправкой, что множество считается цикличным, то есть последний элемент в множестве считается предыдущим по отношению к первому:
// previous
Target.prototype.previous = function ( element ) {
var element = element || this.get();
if( element != document.documentElement.parentNode ) {
element = element.previousSibling || element.parentNode.lastChild;
while( element && element.nodeType != 1 ) { element = element.previousSibling }
}
this.set( element );
return this;
}
Метод для нахождения элемента, следующего за текущим (либо переданному методу в качестве параметра), по своему действию обратный описанному ранее:
// next
Target.prototype.next = function ( element ) {
var element = element || this.get();
if( element != document.documentElement.parentNode ) {
element = element.nextSibling || element.parentNode.firstChild;
while( element && element.nodeType != 1 ) { element = element.nextSibling }
}
this.set( element );
return this;
}
Метод для нахождения родительского (внешнего) элемента, по отношению к текущему (либо переданному методу в качестве параметра):
// outer
Target.prototype.outer = function ( element ) {
var element = element || this.get();
if( element.parentNode != document.documentElement.parentNode ) { element = element.parentNode }
this.set( element );
return this;
}
Метод для нахождения первого дочернего (внутреннего) элемента, по отношению к текущему (либо переданному методу в качестве параметра):
// inner
Target.prototype.inner = function ( element ) {
var element = element || this.get();
if( element.childNodes.length != 0 ) {
for( var i = 0; i < element.childNodes.length; i++ ) {
if( element.childNodes.item( i ).nodeType == 1 ) {
element = element.childNodes.item( i );
break;
}
}
}
this.set( element );
return this;
}
Методы меняют ссылку внутри экземпляра класса значение которой можно получить, как видно из кода посредством метода get() и установить методом set(). Возвращают в качестве своей работы сам объект (о да JQuery травмировал мою психику, да и не только мою я думаю).
Результат:
from.next().inner().previous().previous().get();
Потом после использования на практике (в последующих экспериментах с JavaScript, а позднее и с переносом этой механики на Ruby и PHP, где использовал ее в парсинге XML документов), появился еще один метод, который как мне видится (а точнее формат шаблона передаваемый ему в качестве параметра) и является тем что может представлять для вас интерес (следовательно и причиной написания этой статьи на Хабре). Методу для выполнения последовательности действий согласно шаблону (аналогичный «первый вагон из центра, налево, налево, до столба, там справа и будет»), в котором переход к родительскому элементу соответствует символ «<», первому дочернему «>», предшествующему «-», следующему «+» (пример: цепочке .outer().next().inner().previous().previous() соответствует шаблон “<+>--”):
// select
Target.prototype.select = function ( path ) {
var steps = path.split( "" );
for( var i = 0; i < steps.length; i++ ) {
if( steps[ i ] == "-" ) { this.previous() }
if( steps[ i ] == "+" ) { this.next() }
if( steps[ i ] == "<" ) { this.outer() }
if( steps[ i ] == ">" ) { this.inner() }
}
return this;
}
Предыдущий пример можно переписать так:
from = new Target;
// a, гулять, так гулять (инновации, так инновации), аналог первой записи
node = from.select( “+>--” ).get();
Послесловие: есть мысль добавить возможность указания в шаблоне количества итераций (чтобы можно было вместо “>>>++++++” писать “>3+6”), но пока не реализовал.
Еще одно послесловие: вообще интересуют кого подобные эпосы, стоит писать подобное впредь или на Хабре не место подобной лирике?