Самая лучшая книга по JavaScript всех времён и народов! Лучше неё ничего нет!
O`Reilly - Девид Фленаган, «JavaScript. Definitive Guide, 6th edition»(2011) - туда вошли все новшества от HTML5 и ECMAScript 5! :))))
Вот тут она есть - http://uploading.com/files/3735d769/Oreilly.j
Фленаган пишет очень подробно, для профессионалов.
Искал в электронном виде уже месяца два, кучу времени убил – нигде не было, хотя куча вирья всякого пыталась под её видом пролезть на манер файлов «JavaScript_Definitive_Guide,6th_edition.pdf.exe» с иконкой pdf`а... И вот, наконец, она – вот она!!!)
четверг, 21 июля 2011 г.
вторник, 31 мая 2011 г.
__proto__ во всех браузерах
Ссылка "
Так что остаётся только ссылка "
Но если чего-то нету, то можно это недостающее создать самим. Для того, что бы всё заработало везде, надо вставить конструкцию
__proto__
", как известно, указывает на прототип объекта в браузерах FireFox, Google Chrome и Safari. Обычно ссылку на прототип можно получить комбинацией ссылок constructor и prototype, но когда используется классическое для JavaScript наследование:function A(){/*...*/};
function B(){/*...*/};
B.prototype = new A();
var b = new B();
, то в этом случае вызовb.constructor.prototype
укажет на прототип конструктора A, а не на созданный объект конструктора A, который передан прототипу:alert(b.constructor.prototype === A.prototype);//'true'
. Как же в этом случае можно обратиться именно к прототипу объекта b (естественно, не зная, каков его конструктор)? Можно переопределить ссылку constructor у объекта, созданного по конструктору A, указав ей на B:B.prototype.constructor = B;
, но тогда мы потеряем возможность добраться до прототипа конструктора A, что может так же понадобиться.Так что остаётся только ссылка "
__proto__
" - больше никак. Но этой ссылки нет в некоторых браузерах - например, в IE и в Opera`е.Но если чего-то нету, то можно это недостающее создать самим. Для того, что бы всё заработало везде, надо вставить конструкцию
if (!this.hasOwnProperty('__proto__'))
/** @type A */ this.__proto__ = arguments.callee.prototype;
внутрь нашего конструктора-наследничка. И тогда всё получится:function A(){/*...*/};
function B() {
/*...*/
if (!this.hasOwnProperty('__proto__'))
/** @type A */ this.__proto__ = arguments.callee.prototype;
};
B.prototype = new A();
var b = new B();
alert(b.__proto__ === B.prptotype);//'true'
alert(b.constructor.prototype === A.prototype);//'true'
Навигация в Google Cache
Интернет - это целый мир. Сайты в нём как люди в реальном мире - рождаются, живут и умирают. Иногда то, что они умирают, может кому-то не понравиться. Тогда на помощь тем, кто "хотел, но не успел" сохранить те или иные материалы у себя, приходит Google Cache.
При поиске тех или иных страниц в интернете Вы наверняка замечали под каждой ссылкой с результатами поиска ссылочку "Сохранённая копия". Видели? Это и есть Google Cache. Если страницы уже и след простыл, она может всё ещё оказаться в этом хранилище.
Точно не знаю, сколько живут страницы в Кэше`e Google, прежде чем окончательно проститься с Internet`ом, но если хотелось их сохранить, то искать их можно там. Но вот незадача - отдельную страницу найти-то можно, но вот если пропал целый сайт и хочется погулять по этому сайту, покликать на ссылочки почитать много страниц в правильном порядке, то Вас ждёт неприятный сюрприз - все внутренние ссылки будут битые. Т.е. страницы-то в Google Cach`е есть, но вот навигация по ним очень неудобная - нужно каждую из них искать с помощью поисковика Google`а и переходить по ссылке "Сохранённая копия".
Буквально сегодня я столкнулся с тем, что великолепный сайт, посвящённый реальной медицине (а не этой дурацкой официальной, которая не лечит, а наоборот - медленно убивает людей) - http://www.revici.ru/ - исчез и теперь при наборе его адреса попадаешь на какую-то дурацкую рекламу фильмов.
На этом сайте было большое количество интересных материалов, соединённых ссылками. И при его сохранении из этого Кэша передо мной встала проблема перемещения по этим ссылкам.
Но, т.к. я программист, я быстро нашёл удобное решение. Дело в том, что страница из кэша google подгружается, если перед её адресом в адресной строке браузера вставить строку: "http://webcache.googleusercontent.com/search?q=cache:"
Так что я быстренько написал следующий коротенький скриптик:
При поиске тех или иных страниц в интернете Вы наверняка замечали под каждой ссылкой с результатами поиска ссылочку "Сохранённая копия". Видели? Это и есть Google Cache. Если страницы уже и след простыл, она может всё ещё оказаться в этом хранилище.
Точно не знаю, сколько живут страницы в Кэше`e Google, прежде чем окончательно проститься с Internet`ом, но если хотелось их сохранить, то искать их можно там. Но вот незадача - отдельную страницу найти-то можно, но вот если пропал целый сайт и хочется погулять по этому сайту, покликать на ссылочки почитать много страниц в правильном порядке, то Вас ждёт неприятный сюрприз - все внутренние ссылки будут битые. Т.е. страницы-то в Google Cach`е есть, но вот навигация по ним очень неудобная - нужно каждую из них искать с помощью поисковика Google`а и переходить по ссылке "Сохранённая копия".
Буквально сегодня я столкнулся с тем, что великолепный сайт, посвящённый реальной медицине (а не этой дурацкой официальной, которая не лечит, а наоборот - медленно убивает людей) - http://www.revici.ru/ - исчез и теперь при наборе его адреса попадаешь на какую-то дурацкую рекламу фильмов.
На этом сайте было большое количество интересных материалов, соединённых ссылками. И при его сохранении из этого Кэша передо мной встала проблема перемещения по этим ссылкам.
Но, т.к. я программист, я быстро нашёл удобное решение. Дело в том, что страница из кэша google подгружается, если перед её адресом в адресной строке браузера вставить строку: "http://webcache.googleusercontent.com/search?q=cache:"
Так что я быстренько написал следующий коротенький скриптик:
javascript:
var l=document.getElementsByTagName('a'),
e=l.length;
for(var i=0;i<e;)
l[i].href=
'http://webcache.googleusercontent.com/search?q=cache:'+
l[i++].href.replace(/http:\/\//gi,'');
void(0);//Писать всё нужно в одну строчку, здесь я разбил для удобства восприятия
Вбил его в панель закладок Google Chrome`а и стал нажимать на эту кнопку каждый раз, как перейду на какую-то страницу с висящими ссылками. Всё заработало! Теперь спокойно могу гулять по ссылкам и сохранять страничку за страничкой :)
четверг, 5 мая 2011 г.
Список используемых программ, которые нужно купить
Приветствую!
Как и многие другие, грешен: пиратствую. Не во всём, конечно - Windows давно лицензионный (а Вы попробуйте сейчас купить ноутбук без лицензионной Wind`ы!), от MS Office`а в виду его большой дороговизны, отказался, перейдя на Open Office (ломка уже прошла))). Но другой хороший софт стоит дорого, а бесплатного на некоторые специфические задачи найти не удаётся.
Однако зарабатываю достаточно много и уже просто неприлично этим делом продолжать заниматься. И совесть всё больше по этому поводу свербит...
Решил опубликовать план по приобретению программ - вдруг кому-то пригодится:
Как и многие другие, грешен: пиратствую. Не во всём, конечно - Windows давно лицензионный (а Вы попробуйте сейчас купить ноутбук без лицензионной Wind`ы!), от MS Office`а в виду его большой дороговизны, отказался, перейдя на Open Office (ломка уже прошла))). Но другой хороший софт стоит дорого, а бесплатного на некоторые специфические задачи найти не удаётся.
Однако зарабатываю достаточно много и уже просто неприлично этим делом продолжать заниматься. И совесть всё больше по этому поводу свербит...
Решил опубликовать план по приобретению программ - вдруг кому-то пригодится:
- ABBYY FineRider - уже купил. Стоила в р-не полутора-двух тысяч, вроде. Распознавание отсканированных текстов на ура! Вобщем-то по-моему вообще монополист - по крайней мере для русского языка то уж точно. Нужна мне для сканирования некоторых редких старых книг, которые мне попались и теперь их нужно отсканировать и разместить в интернете.
- ABBYY Lingvo - нужна, http://translate.ru значительно менее удобен в повседневном использовании, да и обладает менее богатыми библиотеками, которые не всегда выдают нужный результат.
- Kaspersky Cristal - до конца года обеспечила контора-производитель, откуда я ушёл месяц назад. Продлять не буду, скорее куплю KIS - Kaspersky Internet Security.
- Sparx Systems Enterprise Architect 8.0 Professional. Хоть и не поддерживает JavaScript, для которой я его в основном использую, но прога незаменимая, подсел на неё, ещё когда работал в Лаборатории Касперского и теперь сложные объёмные решения без неё получается сильно дольше планировать и обдумывать, чем с ней - все аналоги либо намного дороже, либо намного хуже, либо и то и другое.
- SPKet IDE - плагин к Eclipse, платный для коммерческого использования. Очень удобная штука для JavaScript-программирования - лучшая, что я видел.
- Altova XMLSpy. Непревзойдённый XML-редактор, как без рук без него - все аналоги, которые видел, намного хуже.
- Saxon. Часто не хватает возможностей XSLT 1.0 для текущих задач, а бесплатных удобных библиотек XSLT 2.0-преобразований найти не удалось. Saxon - практически единственная полноценная библиотека для XSLT 2.0 преобразований.
- IntelliJ IDEA Corporate. Лучше среды для Java-разработки придумать, по-моему, просто невозможно.
среда, 12 января 2011 г.
JBoss 6 - final?
Ребята из Red Hut, конечно, жгут!.. Выпустили перед самым новым годом (28 декабря) final-версию JBoss`а 6. Подарок типа на новый год людям! А Tomcat 7, который входит в него как сервлет-контейнер, всё ещё beta!!! Нормальный "подарочек", а?.. :))))
среда, 16 декабря 2009 г.
Планы на будущее
Давно не писал, потому что был несколько нагружен работой и не успевал, а халтуру писать тоже не хочется.
То, о чём я пишу, но ещё не дописал и что, соответственно, в этом блоге будет:
То, о чём я пишу, но ещё не дописал и что, соответственно, в этом блоге будет:
- "Дополняем "include в JavaScript`е"". Переработанная статья Володи Колесникова "Инклюд в яваскрипте" на "Техногрете" - сайте для web-разработчиков от студии Артемия Лебедева.
- "Хитрость с finally-блоком" - отличный приём кодинга на JS, который, в частности, позволит немного упростить "Базовую модель" приведённую в статьях цикла "Особенности инкапсуляции на основе замыканий".
- "Cookies API" - удобный API для работы с Cookies.
- "URL advanced parsing" - переработанный в соответстви с серией статей "JavaScript: Особенности инкапсуляции на основе замыканий" вариант реализации парсинга, предложенный Kottenator`ом в статье "Парсим URL")
- "Targeter pattern" - придуманный мной приём для динамического создания и подцепки статических блоков контента на странице. Я не раз использовал его в своих проектах и нахожу весьма ценным.
- "SPKet IDE - советы". Переработанный вариант статьи и видео-лекции С.Чикуенка "Eclipse: редактирование JavaScript в Spket IDE"
- "JSDoc - советы". Дополнения и критика статьи А.Старшинова - "Документирование JS-кода"
- "Rhino и scripting API в Java SE 6 - способы применения в Java-программах (на примере JSDoc Toolkit)"
- "Универсализированная Обработка событий" - рабор того, что можно сделать с несовместимостью браузеров в области продвинутых моделей обработки событий.
- "Универсализированный метод создания DOM-узлов". Представлю свои библиотеки для создания узлов DOM-дерева. Хочу сосредоточиться на нахождении компромиса между максимальной производительностью и удобством работы с API.
- "Работа с замыканиями". Распишу, что представляют собой замыкания и как правильно их использовать.
- "Примитивы и объекты в JavaScript". Вопреки распространённому мнению, примитивы в JS есть, но они присутствуют в этом языке неявно и преобразуются на лету при попытке обратиться к ним как к объектам. Это может создать путанницу и привести к задержкам в работе кода (что явно и происходит, по моим наблюдениям, в коде у многих). В статье постараюсь подробно изложить отличия одних от других и показать верный путь для тюнинга JS-скриптов в этом отношении.
- "Работа с XPath на JavaScript". Описание стандартного механизма поддержки XPath в браузерах и наилучшей с моей т.з.библиотеки, которая заменяет его в браузерах, не поддерживающих данный стандарт.
- "Работа с XSLT на JavaScript". Описание работы с библиотекой AJAXSLT от Google.
- "Технологии XUL и HTA/HTC". Описание работы с данными технологиями, позволяющими создавать полноценные приложения при помощи Web-технологий.
- "ServerSide JavaScript". Когда-то давным-давно, впечатлившись успехом JavaScript, фирма Netscape создала и серверный вариант этого языка, но он по ряду причин не получил должного распространения, упустив рынок приложений на стороне сервера таким языкам, как Perl и PHP. Сейчас, на основе Rhino и Scripting API Java 6 можно использовать Java-сервера для программирования серверной логики на JS. В статье я постараюсь продемонстрировать, как это можно реализовать.
- "Технология компонентов". Дальнейшее развитие идеи паттерна Targeter, к которому добавляется аналогичный GUI-библиотекам Java (Swing) механизм обработки событий.
понедельник, 1 июня 2009 г.
JavaScript: Drag and Drop - библиотека
В данной статье я представлю свою небольшую JavaScript-библиотечку для работы с Drag&Drop (Скачать).
В более сложном варианте нам необходимо вносить те или иные ограничения на этот процесс, по-этому API библиотеки должно позволять гибко настраивать перенос в соответствии с задачей. Сразу обратим внимание на три фазы перемещения:
Эта библиотека довольно простая и может оказаться полезной вам и для других ваших сценариев - если вы будете её использовать ещё для чего-то (как это делаю я), то имеет смысл её загрузить один раз и больше не загружать - тогда удобно отделить её от других файлов библиотек и загружать отдельно - один раз, что бы потом грузить другие библиотеки, которые её используют (исходный код данной библиотеки лежит там же, в директории "./lib"). Для тестирования (файлы в директории "./test/") выбран именно этот способ, для такой сборки в Ant предназначен target по-умолчанию "build".
Если же вы не собираетесь использовать библиотеку "commons.js" где-либо ещё, то имеет смысл для сокращения количества загружаемых файлов, объединить её с библиотекой dnd в один оптимизированный файл. Такой объединённый файл и лежит в корне архива (он собирается с помощью действия "build-complex" в Ant).
Второй метод объекта
В этом примере мы видим работу двух методов объекта DnD - это методы
Для этого предусмотрен простой API, регламентирующий Drag&Drop-перемещения для элемента страницы. В основе его лежит событийная модель - для элемента, регистрируемого в объекте
Можно переопределить любой из обработчиков, все вместе или любые их комбинации - каждый из них будет вызываться только в том случае, если будет присутствовать.
Все три метода могут возвращать значения типа
В общем случае возвращение
На уровне API это означает, что нам нужно заблокировать поведение по-умолчанию при возникновении события mouseMove и заменить его на перемещение по горизонтали, не трогая вертикальной координаты объекта.
Делается это примерно так:
Значит, нам нужно перегрузить обработчик события окончания передвижения элемента с тем, что бы проверять, находится ли курсор над областью, в которую разрешено перемещение и, в случае, если нет - возвращать
Кроме того, было бы полезно в процессе перемещения сразу показывать пользователю, что в данный момент элемент находится не над приемлемой для помещения в неё зоной. Традиционно это делается путём присвоения курсору такого значения, которое выглядит как знак запрета. К сожалению, такое значение для CSS-свойства 'cursor' на сегодняшний момент не стандартизовано, однако, несмотря на это, поддерживается последними версиями всех достаточно популярных браузеров, за исключением, разве что, Opera`ы (будем надеяться, что это временно). Это значение - 'no-drop'.
Допустим, что область карзины представлена объектом SquareArea, которому в конструкторе передаются её координаты и размеры, и у неё есть один метод -
Вставьте этот код перед регистрацией слоя в объекте
Введение
Для начала немного теории. Drag&Drop предполагает, что вы, как разработчик, даёте возможность пользователю перемещать те или иные графические объекты (будем по старинке называть их слоями) по странице, нажав на них левой кнопкой мыши и, не отжимая её, передвигая курсор мыши до пункта назначения.В более сложном варианте нам необходимо вносить те или иные ограничения на этот процесс, по-этому API библиотеки должно позволять гибко настраивать перенос в соответствии с задачей. Сразу обратим внимание на три фазы перемещения:
- Нажатие левой кнопки мыши на элементе
- Перетаскивание элемента с помощью перемещения курсора при нажатой левой кнопке мыши
- Отжатие левой кнопки мыши после перемещения
DnD
с двумя методами.Подключение библиотеки
Архив содержит библиотеку DragAndDrop в 2-х вариантах.- Оптимизированный код - в файлах "./lib/common.js" и "./build/dnd.js".
- Комплексный оптимизированный код - в файле "./dnd.js"
Эта библиотека довольно простая и может оказаться полезной вам и для других ваших сценариев - если вы будете её использовать ещё для чего-то (как это делаю я), то имеет смысл её загрузить один раз и больше не загружать - тогда удобно отделить её от других файлов библиотек и загружать отдельно - один раз, что бы потом грузить другие библиотеки, которые её используют (исходный код данной библиотеки лежит там же, в директории "./lib"). Для тестирования (файлы в директории "./test/") выбран именно этот способ, для такой сборки в Ant предназначен target по-умолчанию "build".
Если же вы не собираетесь использовать библиотеку "commons.js" где-либо ещё, то имеет смысл для сокращения количества загружаемых файлов, объединить её с библиотекой dnd в один оптимизированный файл. Такой объединённый файл и лежит в корне архива (он собирается с помощью действия "build-complex" в Ant).
Что ещё есть в архиве
- "./doc/" - документация
- "./test/" - демонстрационные тесты
- "build.xml" - сценарий сборки Ant
Первый пример
Если у Вас на странице есть некоторый объект, который Вам хотелось бы сделать передвигаемым по ней, то Вам достаточно зарегистрировать его в объекте DnD:var /** @type {HTMLElement} */ layer = document.createElement('div');
layer.appendChild(document.createElement('img')).setAttribute('src', 'pic.gif');
document.body.appendChild(layer);
DnD.register(layer);
В результате выполнения этого кода картинка "pic.gif" появится на экране и станет возможным её передвижение по окну браузера.Второй метод объекта
DnD
служит обратной задаче - отмены регистрации. Например, если после пердыдущего участка кода вставить следующий:setTimeout('DnD.unregister(layer)', 6000);
, то передвижение слоя будет доступно только в течении 6 секунд - затем он зафиксируется и больше не будет доступен для перемещений.В этом примере мы видим работу двух методов объекта DnD - это методы
register
и unregister
. Как нетрудно догадаться из их названий, один регистрирует объект как DragAndDrop, второй - отменяет эту регистрацию, возвращая его в нормальное состояние (но не отменяя его перемещения, которое уже совершено, а так же текущего перемещения - если метод unregister
был вызван в момент перемещения. Если быть более точным, метод unregister
блокирует у слоя возможность начать его новое перемещение пользователем). Оба эти метода возвращают ссылки на объект DnD
, так что их вызовы можно выстраивать в цепочки любой длинны:DnD.register(layer1).register(layer2).unregister(layer3).register(layer4);//...
Перемещать можно только слои, у которых свойство 'position' установлено в значение 'absolute' или 'relative'. По-этому при регистрации слоя происходит проверка на то, какое значение выставлено у него в этом css-свойстве. Если оно не выставлено в одно из этих двух - библиотека сама выставляет для него значение 'absolute'.Установка ограничений
Однако, читатель наверняка согласится с тем, что в реальных задачах редко нужны просто свободно перемещаемые по окну браузера мышкой элементы. Как правило, нужно как-либо ограничить возможности производить перемещения - например, оставить перемещения лишь по заданным траекториям или ограничить те места в браузере, где перемещения можно было бы завершить.Для этого предусмотрен простой API, регламентирующий Drag&Drop-перемещения для элемента страницы. В основе его лежит событийная модель - для элемента, регистрируемого в объекте
DnD
, можно определить обработчиков трёх событий. Для каждого из событий в объекте DnD
определено поведение по-умолчанию, но если обработчик данного события вернёт булево значение false
, то это поведение не будет выполнено. Значение true
можно и не возвращать - всё, что угодно, кроме значения false
будет командой выполнить действие по-умолчанию (обратите внимание на то, что значение false
должно быть иименно примитивным, объект new Boolean(false)
будет интерпретирован как true
, так же будет интерпретированы и значения null
и undefined
- только примитив false
заблокирует поведение для объекта по-умолчанию).Событие | Сигнатура обработчика | Описание параметров | Поведение по-умолчанию |
---|---|---|---|
Нажатие пользователем левой кнопки мыши в момент нахождения курсора над слоем - инициализация перемещения элемента. | function mouseDown(/*Object*/ offset) | В качестве парамметра принимает объект offset , содержащий информацию о начале перетаскивания - поля 'x' и 'y' этого объекта содержат разницу между позицией курсора мыши и левым верхним краем элемента, а поле 'startPos' содержит объект с полями 'x' и 'y', содержащими координаты левого верхнего угла элемента. | Перемещение стартует. Форма курсора мыши по всему документу выставляется в значение 'move'. |
Изменение координат курсора мыши при нажатой левой кнопке мыши. | mouseMove(/*number*/ x, /*number*/ y) | /*number*/ x - координата по горизонтали, /*number*/ y - координата по вертикали левого верхнего края курсора мыши. | Передвижение элемента, по вертикали и горизонтали соответствующее перемещению курсора. |
Отпускание левой кнопки мыши после перетаскивания элемента. | mouseUp(/*number*/ x, /*number*/ y) | /*number*/ x - координата по горизонтали, /*number*/ y - координата по вертикали левого верхнего края курсора мыши. | Фиксация слоя в текущей позиции в окне браузера и изменение формы курсора мыши на всём документе на значение 'auto'. В случае отмены данного действия производится возврат слоя к координатам, с которых началось его передвижение. |
Можно переопределить любой из обработчиков, все вместе или любые их комбинации - каждый из них будет вызываться только в том случае, если будет присутствовать.
Подробности
Начинается перетаскивание для нас с того, что вызывается методmouseDown
и ему передаётся параметр offset
- смещение. Дело в том, что координатой элемента у нас считается координата его верхнего левого угла, а мышка может быть нажата, находясь не только в левой верхней точке, но и в любой другой точке элемента, по-этому для того, что бы корректно перемещать объект в зависимости от будущих координат мыши, нам нужно знать, на сколько пикселов правее и ниже "взялся мышкой" за элемент пользователь, когда начал его перетаскивание, что бы потом корректировать координаты так, что бы курсор мышки при перетаскивании был именно над этой самой точкой, а не над левым верхним углом, как это было бы, если бы мы не учитывали смещения. Именно эту информацию и несёт объект offset
. Так же в нём содержится информация о стартовом положении элемента в момент до начала перетаскивания, по-этому может быть удобно запомнить этот объект и использовать эту информацию в дальнейшем - при обработке других событий.Все три метода могут возвращать значения типа
boolean
(обратите внимание - с маленькой буквы, т.е. речь идёт о примитиве, а не об обёртке Boolean
). Любое другое значение, а так же отсутствие возвращаемого значения интерпретируется как возвращение значения true
.В общем случае возвращение
true
означает разрешение на проделывание действий по-умолчанию, false
- отказ от этих действий. Действия по-умолчанию для событий приведены в таблице №1.Пример: Перетаскивание только по горизонтали
Допустим, перед нами стоит задача создать интерфейс, управляющий какой-либо количественной величиной, скажем, уровнем громкости в динамике или задержкой по времени при автодозвоне. Тогда нам нужно создать некоторый бегунок, который бы перемещался только по горизонтали, по нужной нам шкале, а мы бы отслеживали это перемещение и, в соответствии с ним, меняли бы ту величину, за изменение которой был бы ответственнен наш компонент.На уровне API это означает, что нам нужно заблокировать поведение по-умолчанию при возникновении события mouseMove и заменить его на перемещение по горизонтали, не трогая вертикальной координаты объекта.
Делается это примерно так:
(function() {
var /** @type {number} */ offsetX;
layer.mouseDown = function(offset) {
offsetX = offset.x;
}
layer.mouseMove = function(x) {
this.style.left = (x - offsetX) + 'px';
return false;
}
layer.mouseUp = function() {
offsetX = null;
}
})();
Вставьте этот код перед регистрацией слоя в объекте DnD
в первом примере (в начале статьи) - и он придаст слою нужную функциональность. Послоностью пример можно увидеть, посмотре исходные коды тестов (директория "./test/") - там этот пример соответствует примеру №3. Запустите файл "./test/test.html" и проверьте его работу в своём браузере.Пример: перетаскивание в заданную область
Допустим, у нас есть интернет-магазин и мы хотим сделать возможность перемещения товаров в корзину. Тогда мы имеем задачу обеспечить перетаскивание элемента в ограниченную область экрана (корзину) и нас не устроит, если пользователь переместит слой, соответствуюдий товару, куда-либо ещё.Значит, нам нужно перегрузить обработчик события окончания передвижения элемента с тем, что бы проверять, находится ли курсор над областью, в которую разрешено перемещение и, в случае, если нет - возвращать
false
с тем, что бы вернуть элемент назад, отменив результат перемещения.Кроме того, было бы полезно в процессе перемещения сразу показывать пользователю, что в данный момент элемент находится не над приемлемой для помещения в неё зоной. Традиционно это делается путём присвоения курсору такого значения, которое выглядит как знак запрета. К сожалению, такое значение для CSS-свойства 'cursor' на сегодняшний момент не стандартизовано, однако, несмотря на это, поддерживается последними версиями всех достаточно популярных браузеров, за исключением, разве что, Opera`ы (будем надеяться, что это временно). Это значение - 'no-drop'.
Допустим, что область карзины представлена объектом SquareArea, которому в конструкторе передаются её координаты и размеры, и у неё есть один метод -
isInside(/*number*/ x, /*number*/ y)
, который возвращает результат типа boolean
, говорящий, соответственно, входит или не входит точка с переданными ему координатами в его область. Тогда наш код для этой ситуации может быть примерно таким:(function() {
var /** @type {Object} */ offset,
/** @type{SquareArea} */ toArea = new SquareArea(450, 450, 100, 100);
layer.mouseDown = function(_offset) {
offset = _offset;
}
layer.mouseMove = function(x, y) {
this.style.cursor =
document.body.style.cursor = toArea.isInside(x, y) ? 'move' : 'no-drop';
}
layer.mouseUp = function(x, y) {
offset = null;
this.style.cursor = 'move';
return toArea.isInside(x, y);
}
})();
Наверное, нужно особо остановиться на том, почему в обработчике mouseMove
значение курсора присваивается сразу же двум стилям элементов - и самого элемента и документа. Дело в том, что при перемещении, резко дёрнув мышь, можно на долю секунды поймать момент, когда элемент ещё не успел перерисоваться и подтянуться к курсору мыши - и тогда, если документу не присвоен тот же курсор, что и элементу, курсор изменит форму, а потом вернёт старую форму обратно. Это может смотреться довольно раздражающе - именно для того, что бы избежать этого эффекта, рекомендуется в процессе DragAndDrop-передвижения выставлять необходимую форму курсора не только над элементом, но и на всём документе.Вставьте этот код перед регистрацией слоя в объекте
DnD
в первом примере (в начале статьи) - и он придаст слою нужную функциональность. Полоностью пример можно увидеть, посмотре исходные коды тестов (директория "./test/") - там этот пример соответствует примеру №4. Запустите файл "./test/test.html" и проверьте его работу в своём браузере.
Подписаться на:
Сообщения (Atom)