Показаны сообщения с ярлыком javascript. Показать все сообщения
Показаны сообщения с ярлыком javascript. Показать все сообщения

четверг, 21 декабря 2006 г.

Обзор Drag&Drop библиотек для JavaScript

В данной статье приведен обзор наиболее известных Drag&Drop библиотек.
Dragable RSS boxes (сайт, пример)

Этот скрипт использует Ajax для того чтобы читать данные из внешних RSS источников и показывать их содержимое в перетаскиваемых блоках. Также вы можете создать новый блок динамически прямо на странице. Т.к. библиотека выпущена недавно, ждите появление новго функционала в ближайшее время.



DOM Drag (сайт, пример)

DOM Drag - это легкое и простое в использование API для всех современных DHTML браузеров. На данный момент проект находится в стадии более экспереметнального, поэтому не рекомендую его использовать в профессиональных приложениях. С другой стороны, эта библиотека может быть полезна для использования в простых проектах, где нужны минимальные возможности Drag&Drop.



Walterzorn Drag&Drop (сайт, пример)

Кросс-браузерная JavaScript библиотека, которая добавляет функциональность Drag&Drop для любых слоев или к изображениям. Вы можете ограничить наличие элементов, которые можно передвигать, изменить курсор или указать сразу несколько картинок доступных для перемещения. Скрипт работает практически во всех браузерах, не считая нескольких наиболее редко используемых.



X Library (сайт, пример)

Ничем не примечательная Drag&Drop библиотека



Drag-and-Drop extension for Prototype (сайт, пример)

Эта библиотека позволит не только использовать технику Drag&Drop, но еще позволит сортировать перемещаемые элементы. Укажите какие элементы можно использовать в качестве перемещаемых, а также элементы которые можно вставлять в требуемые блоки. Используйте сортировку (элементы, дети которых могут быть отсортированы внутри своего родителя).



Toolman DHTML (сайт, пример)

Используйте эту простую библиотеку если захотите создать простую по функциональности свою собственную



Rico (сайт, пример)

Одна из самых богатых по возможностям библиотека для расширенной функциональности ваших приложений. Rico предоставляет полную поддержку Ajax, полное управление перемещаемыми объектами и поддержку кинематических эффектов.



DragLib (сайт, пример)

Полезен, если хотите быстро создать какой-либо элемент на странице перемещаемым.



Yahoo User Interface Library (сайт, пример)

Позволяет все внимание сконцентрировать на логике ваших приложений, т.к. для использования API вам часто понадобится всего лишь пар строк кода. Поддерживает широкий набор стандартных элементов для перетаскивания.


Оригинал: http://www.ajaxpath.com/drag-and-drop



Смотрите также:
Anatomy of a Drag and Drop




среда, 20 декабря 2006 г.

Редактирование на месте при помощи Ajax и Prototypes

В этой статье я покажу вам как использовать популярный файл Prototype.js чтобы использовать Ajax-технику, называемую "редактирование на месте", но для начала, давайте подробно рассмотрем саму технику. Редактирование на месте, как и множество других Ajax функций, использует XmlHttpRequest объект для того чтобы вызвать внешнюю страницу, отправить и получить от нее информацию. Первым делом я познакомлю вас с архитектурой этого приложения. Т.к. мы используем базу данных и PHP для создания слоя обмена данными, начнем так:

Самый первый слой - MysqlDB класс, который содержите необходимые методя для работы с базой данных. В то время как наша статья ставит основной целью объяснение техники редактирования на месте, и, в частности, использование Ajax, мы сконцентрируем наше внимание на brains.php, который содержит Ajax_Interface PHP класс (который, как вы могли уже заметить, наследет MysqlDB класс). На верхнем уровне происходит вызов index.php, который включает в себя brains.php, а так же functions.js и prototype.js. Когда brains.php включается в файле index.php, происходит инициализация методов, которые теперь могут быть использованы в index.php.

Давайте продолжим, обращая наше внимание на следующие PHP файлы: Ajax_Interface.php и brains.php. Вообще в этом приложении я решил не пользоваться классами. Для начана взглянем на функцию print_records() - она устанавливает значения для страницы после загрузки, показывая что сейчас хранится в базе данных.

function print_records() {

$this->get_records();
$products = $this->rs;
$id = $products['product_id'];
$name = $products['name'];

do {
$id = $products['product_id'];
$name = $products['name'];
$field = 'field_'.$id;

echo '<input type="text" name"?" id="'.$id.'" value="'.$name.'"
onClick="changeClass(\''.$id.'\', \'show\')"
onBlur="changeClass(\''.$id.'\', 'hide\')"
onKeyPress="checkLength(this)" class="text" maxlength="60" readonly />';
echo "\n";
} while ($products = $this->fetch_array($this->result));
}


Здесь мы использовали цикл чтобы выывести каждую строку из базы данных.Обратите внимение, что события onBlur и onClick - это основа нашей техники. Когда происходит событие onClick функция изменяет текст на поле для ввода (changeClass). Событие onBlur заканчивает процесс обновления текста, используя ту же самую функцию. Давайте взглянем на changeClass:

function changeClass(id, action) {
if (action=="hide") {
$(id).className = "text";
save(id);
} else {
$('status').innerHTML ='';
$(id).className = "input";
$(id).readOnly = false;
}
}


Нажимая на тексте, мы изменяем CSS класс и получаем поле для ввода. Когда мы теряем фокус (событие onBlur), мы переключаем наше поле обратно в не-редактируемому виду. Обратите внимание на функцию save(), которая вызывается после того как произошло событие onBlur:

function save(id){
var new_content = $F(id);
var success = function(t){
$('ddiv').innerHTML = t.responseText + 'supposed to be here';
}
var failure = function(t){ alert('update failed'); }
var url = 'http://localhost/ajax/prototype/include/brains.php';
var pars = 'edit=go&content='+new_content+'&product_id='+id;

var myAjax = new Ajax.Request(
url,
{
method: 'get',
parameters: pars,
onComplete: update_page
} );
}


Обратите внимание на функции S() и $F(). Эти функции служат для более короткого и удобного обращения к элементам DOM. Если вы не еще не знакомы с этими функциями и хотите больше узнать о возможностях Prototype.js, рекомендую прочитать основы работы с Prototypes на русском или ознакомиться с документацией по этой библиотеке.

Теперь давайте взглянем на переменные url и parts. Url - адрес, который будет вызван, parts - параметры, переданные по этому адресу. После создания Ajax-запроса (функция из Prototypes), мы устанавливаем для события onComplete функцию, которая вызовет обновление страницы. Давайте глянем как будет обработан наш запрос со стороны PHP:

if ($_GET['edit'] == 'go')  {
$result = $ai->save();
header('Content-Type: text/xml');
// создаем XML заголовок
echo '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>';
echo "<response>";
echo $result;
echo "</response>";
}


Когда мы получаем уведомление о необходимости изменить данные через $_GET переменную, мы вызываем метод $ai->save(). Этот метод просто получает текущий элемент для редактирования и обновляет базу данных на основе данных, полученных из вызова объекта XmlHttpRequest. Затем мы возвращаем данные полученные из базы данных в виде xml:

function save() {
$query = 'update product SET name="'.$_GET['content'].'"
where product_id = '.$_GET['product_id'].' LIMIT 1';

$this->query($query);
$output = '<pID>'.$_GET['product_id'].'</pID>.
<value>'.$_GET['content'].'</value>';

return $output;
}


Последнее, что я хотел бы вам показать - как происходит обновление div-а, который будет содержать обновленную информацию из базы данных:

function update_page(originalRequest) {
var rXML = originalRequest.responseXML;
var pIDs = rXML.getElementsByTagName('pID').item(0);
var pID = pIDs.firstChild.data;

//предупреждаем('i have ' + pID + ' to update');
var values = rXML.getElementsByTagName('value').item(0);
var value = values.firstChild.data;
//предупреждаем('i have ' + value + 'as a return value');

$(pID).innerHTML = value;
$('status').innerHTML = 'update complete';
}


Первым делом я разделил xml информацию по названиям нод. Я так же обновил div, который при первой загрузке страницы был пустым (div select), для того, чтобы вы могли увидеть текст "обновление завершено" после завершения обновления. Но самое главное - я обновил содержание измененного элемента.

Скачать полный исходный код примера.

Оригинал: phpbuilder.com


вторник, 19 декабря 2006 г.

Введение в Prototype

JavaScript продолжает завоевывать популярность во всем интернете, и на сегодняшний день мы можем быть уверены в скорости, надежности и удобстве его использования. Разумным решением было бы использовать некую основу, которая пригодилась бы нам в наших проектах. Именно за это мы благодарны Сэму Стефенсону - человеку, создавшего Prototype.js - потрясающую библиотеку функций, которая упростит нашу работу в JavaScript.

Данное руководство затрагивает только азы этой библиотеки и сопровождается простыми примерами ее использования.

Приступим!

После того как вы скачали нужные файлы и положили их в нужную директорию, все что вам нужно, чтобы включить Prototype в ваш html-код, например так:

<script src="/scripts/prototype.js" type="text/javascript"></script>


Обратите внимание, только что программирование на javascript стало в 10 раз легче! Давайте же поскорее узнаем что за возможности появилось в наших руках!

Функция $()

Наиболее используемая функция, предоставляет простой путь для получения дескриптора DOM элемента. Обычно, если вы хотите получить доступ к DOM элементу, вы делаете что-то вроде:

node = document.getElementById("elementID");


Использование $() поможет делать это проще:

node = $("elementID");


Другая замечательная сторона этой функции - то что она более мощная нежели document.getElementById(), т.к. в функцию встроена возможность получать доступ к нескольким элементам сразу:

allNodes = $("firstDiv", "secondDiv");
for(i = 0; i < allNodes.length; i++) {
alert(allNodes[i].innerHTML);
}


В этом примере мы использовали функцию $() для получения массива элементов, который затем может быть обработан, скажем, в цикле.

Работа с формами

Работа с формами - полное д_рьмо не только со стороны HTML/CSS, но и в JavaScript. Prototype.js предоставляет удобные методы работы с формами, которые сделают вашу жизнь более веселой.

Функция $F() возвращает значение элемента формы по его ID. К примеру возьмем простую форму:

<input type="text" id="textfield" name="textfield" />
<textarea rows="5" cols="5" id="areafield" name="areafield"></textarea>
<select id="selectfield" name="selectfield">
<option value="1" selected>One</option>
<option value="2">Two</option>
</select>
<input type="checkbox" id="checkfield" name="checkfield" value="1" checked />


Для того, чтобы получить значения элементов, воспользуемся $F():

$F("textfield");      // возвращает значение text input
$F("areafield"); // возвращает значение textarea
$F("selectfield"); // возвращает выбранное значение select
$F("checkfield"); // возвращает null если не установлена, иначе значение


В большинстве случаев получать значение элемента формы через эту удобнее, чем напрямую. Но есть пара "заморочек" которые я обнаружил:
- как и прежде, нет простого способа получить значени radio group элемента (только конкретное значение каждого radio элемента)
- нельзя передать сразу несколько ID, как вы это делали в $()

Другая функция, Form.getElements() вернет в массиве значение каждого элемента формы, не обращая внимания на тип элемента:

allNodes = Form.getElements("myform");
for(i = 0; i < allNodes.length; i++) {
//делаем что-то для каждого элемента формы
}


В этом примере мы получили все значения формы c id="myform". Если вы хотите обработать событие onclick для каждого элемента или показать вспывающее окно, вы можете это сделать как указано выше.

Следующий метод, который мы рассмотрим - Form.serialize(). Когда вы строите Ajax запрос, часто вам приходится приводить к нужному формату вашу POST строку, чтобы передать данные. Когда вы жмете submit строка уже построена. serialize() сделал этот процесс удивительно простым:

allNodes = Form.serialize("myform");

// возвращает field1=value1&field2=value2&field3=value3 и т.д...


Построение строки для нас - бесспорно удобно, но что делает эту функцию поистине замечательной, то что она работает со всеми типами элементов. Выше мы видели, что $F() имеет некоторые проблемы с использованием radio groups, но serialize() делает работу с элементами, независимо от типа, полностью корректной.

getElementsByClassName()

Не могу понять, почему до сих пор в JavaScript не реализована эта функция. Но Prototype.js добавляет getElementByClassName(), расширяя объект document. Функция работает практически так же, как document.getElementsByTagName(). Различие в том, что нашей функции как параметр надо передать название класса:

allNodes = document.getElementsByClassName("red");
for(i = 0; i < allNodes.length; i++) {
alert(allNodes[i].innerHTML);
}


В массиве возвращаются все элементы, которые соответствуют указанному классу. Функция работает даже в том случае, если для элемента определено несколько классов. getElementByClassName() используется во многих проектах, в основном для того чтобы задействовать нужное DOM событие. Я верю, что вы найдете ее полезной!

Работа с элементами

Объект Element предоставляет богатый набор вспомогательных функций (возможности которых расширяются с каждым релизом), практика использования которых весьма похожа на практику использования DOM. Некоторые из них не сильно облегчают ваш код, другие позволяют заменить 10 (и более) строк кода в один вызов. Давайте взглянем на несколько примеров.

Получение высоты элемента без дополнительных функций:

$("first").offsetHeight


А теперь воспользуемся ими:

Element.getHeight("first")


В этом примере новая функция не предоставила никаких преимуществ. Но что если мы хотим, скажем, убрать className из элемента? Это обычный путь (взято из Prototype.js):

element = $(element);
if (!element)
return;
var newClassName = '';
var a = element.className.split(' ');
for (var i = 0; i < a.length; i++) {
if (a[i] != className) {
if (i > 0)
newClassName += ' ';
newClassName += a[i];
}
}
element.className = newClassName;


А теперь с помощью вспомогательной функции:

Element.removeClassName("elementID", "red");


Круто, не правда ли? Не беря во внимание первый пример, вспомогательные функции позволяют экономить море времени, делая общие задачи проще. Для простоты и удобства я рекомендую использовать эти функции на протяжении написания всего проекта. Посмотреть полный список функций, и информацию об их использовании вы можете на странице документации Prototype от Sergio (англ. версия).

Функция Try.This()

Try.This() - замечательная функция, которая помогает разработчикам создавать код, работающий независимо от реализации JavaScript в различных браузерах. Чтобы вам не пришлось самостоятельно определять тип объекта или браузера, эта функция будет пробовать выполнять часть кода пока не произойдет ошибка, а затем переходить дальше:

return Try.these(
function() {
alert("первый");
jkgjhgjhg //преднамеренная ошибка
alert("первая ошибка");
return 1;
},
function() {
alert("второй");
return 2;
}
);


В этом примере первая часть кода перестанет выполняться в месте где мы создали преднамеренную ошибку. Зная это, очень важно быть внимательным к нашему коду, т.к. до места ошибки все будет выполнено. Вцелом, Try.This() используется в проектах не часто, но порой весьма полезно знать что такая функция есть и знать, как она работает.

Поддержка Ajax

Сейчас я покажу вам как мы можем создавать Ajax-приложения при помощи Prototypes.js. В соответствии с документацией обычный Ajax-запрос может быть реализован так:

var myAjax = new Ajax.Request(
url,
{method: 'post', parameters: data, onComplete: ajax_response}
);


Где используемый метод post или get, а параметры - пары имя/значение объединенные в строку и onComplete() - функция, которая будет вызвана когда вызов закончится. Один раз разобравшись с работой этого метода легко сделать повторяющиеся Ajax-вызовы путем создания ваших собственных функций. Для начала просто пример, который создает Ajax-запрос:

function ajax_request(url, data) {
var myAjax = new Ajax.Request(
url,
{method: 'post', parameters: data, onComplete: ajax_response}
);
}


И после того как запрос закончится, отправим его ответ в ajax_response().

function ajax_response(originalRequest) {
if(!bHasRedirect) {
//process originalRequest.responseText;
}
else {
bHasRedirect = false;
ajax_request(originalRequest.responseText, "");
}
}


После того как вы создали Ajax-запрос, ответ всегда будет получен в ajax_response(). В дальнейшем будет выполнен другой Ajax-запрос, если bHasRedirect установлен (true), или будет запущен код на основе глобального массива функций и метода originalRequest.responseText() (возвращаемое значение).

PeriodicalExecuter

Этот объект после инициализации повторно вызывает требуемую функцию с заданным интервалом времени. Удобно, когда вы хотите автоматически обновить часть сайта.

function periodicalUpdate() {
new PeriodicalExecuter(refreshNews, 10);
}

function refreshNews() {
//Ajax код для слива новостей и обновления DOM
}


Конструктор PeriodicalExecuter получает название функции для выполнения как первый параметр и интервал выполнения в качестве второго. Обратите внимание, наша функция получает промежуток времени в секундах (стандартная функция setInterval() использует миллисекунды в качестве параметра). Хочу заметить, что этот пример может использоваться для любых целей - не только в связке с Ajax. Для использования вместе с Ajax удобнее пользоваться классом Ajax.PeriodicalUpdater.

В данном руководстве вы найдете все методы или функции, которые предоставляет Prototype.js, но есть некоторые функции, которые тоже хотелось бы упомянуть (Все они могут быть найдены в документации):

observe - функции этого метода подобны addEvent(), но используются для того чтобы аккуратно присоединять события к DOM

User Iteraction - вы можете обнаружить встроенные глобальные значения, такие как KEY_TAB, для того чтобы понять какую клавишу нажал пользователь. Так же вы можете получить координаты мыши и информацию о нажатых на ней кнопках.

Class Creation - зачем останавливаться на функциональности Prototype.js? Используя похожий синтаксис и функции мы можем построить свой собственный класс, чтобы держать все по полочкам. Добавление конструктора и дополнительных методов еще никогда не было столь простым. Смотрите Class.Create() в документации.

Обобщая вышесказанное

Разве допустимо использование публичного кода/библиотек, если вы не знаете автора и досконально не разбираетесь в том, что творится "за кулисами"? Мой ответ - да, до тех пор пока вы более или менее тестируете код и доверяете человеку/сообществу, которые стоят за разработкой всего этого. В случае Prototype.js такая уверенность складывается из двух частей. Во-первых Ruby on Rails интегрировали поддержку Prototype.js. С тех пор как Ruby on Rails имеет надежную команду разработчиков, было найдено и исправлено огромное количество багов, за счет чего Prototype.js стала еще более стабильной. Во-вторых - разработчик работающий на 37signals. Я доверяю не только практике разработки программ какой-либо фирмы, но я верю что в дальнейшем Prototype.js будет и дальше тестироваться и становиться лучше. Вдобавок ко всему, я сам продолжаю тестировать эту библиотеку и теперь уже использую практически во всех своих проектах.

Prototypes.js это намного большее, чем описано в этой статье, и его действительно стоит попробовать! Если вас возмущает размер файла (30 кб, примерно как этот текст), помните, что вы всегда можете убрать классы, которые вы не используете или сжать JavaScript при помощи PHP перед отдачей пользователю. Prototypes.js совсем не сложен при изучении. И не забудьте - это всего лишь вводная статья, если вы хотите узнать побольше информации, посетите неоффициальную документацию Prototype и script.aculo.us wiki-документацию.

Оригинал статьи: http://particletree.com/features/quick-guide-to-prototype


понедельник, 18 декабря 2006 г.

Кросс-браузерный перехват событий Javascript и утечка памяти

В "старой школе" вы обычно регистрировали событие путем установки соответствия свойству onevent DOM элемента.

elem.onclick = function() {
alert("You clicked me");
}

Проблема кроется в том, что вы можете назначить только одну функцию для указанного события. Но все современные браузеры поддерживают более продвинутые механизмы регистрации, т.о. вы можете регистрировать несколько функций на одно и то же событие. Но сам процесс регистрации таких событий обычно зависит от браузера. Следующий код позволит регистрировать/удалять события для всех современных браузеров:

function addEventListener(instance, eventName, listener) {
var listenerFn = listener;
if (instance.addEventListener) {
instance.addEventListener(eventName, listenerFn, false);
} else if (instance.attachEvent) {
listenerFn = function() {
listener(window.event);
}
instance.attachEvent("on" + eventName, listenerFn);
} else {
throw new Error("Event registration not supported");
}
return {
instance: instance,
name: eventName,
listener: listenerFn
};
}

function removeEventListener(event) {
var instance = event.instance;
if (instance.removeEventListener) {
instance.removeEventListener(event.name, event.listener, false);
} else if (instance.detachEvent) {
instance.detachEvent("on" + event.name, event.listener);
}
}

Пример использования вышеуказанных функций:

var elem = document.getElementById("elem");
var listener = addEventListener(elem, "click", function() {
alert("You clicked me!");
});
removeEventListener(listener);


Несмотря на то, что этот рецепт работает во всех браузерах, Internet Explorer имеет в своем арсенале огромное количество багов, связанных с утечкой памяти и наше использование регистратора событий только обостряет ситуацию. Сама по себе проблема эта комплексная (тонкие взаимодействия между закрытиями функции и COM), но мы можем дополнить вышеуказанный рецепт при помощи глобальной функции де-регистрации, которая устранит проблему утечки памяти в большинстве случаев:

var __eventListeners = [];

function addEventListener(instance, eventName, listener) {
var listenerFn = listener;
if (instance.addEventListener) {
instance.addEventListener(eventName, listenerFn, false);
} else if (instance.attachEvent) {
listenerFn = function() {
listener(window.event);
}
instance.attachEvent("on" + eventName, listenerFn);
} else {
throw new Error("Event registration not supported");
}
var event = {
instance: instance,
name: eventName,
listener: listenerFn
};
__eventListeners.push(event);
return event;
}

function removeEventListener(event) {
var instance = event.instance;
if (instance.removeEventListener) {
instance.removeEventListener(event.name, event.listener, false);
} else if (instance.detachEvent) {
instance.detachEvent("on" + event.name, event.listener);
}
for (var i = 0; i < __eventListeners.length; i++) {
if (__eventListeners[i] == event) {
__eventListeners.splice(i, 1);
break;
}
}

}

function unregisterAllEvents() {
while (__eventListeners.length > 0) {
removeEventListener(__eventListeners[0]);
}
}


Функция unregisterAllEvents удаляет события глобально, удаляя связи между DOM объектом и слушающей функцией и тем самым решает проблему в большинстве случаев. Чтобы воспользоваться дополнительным преимуществом этой функции, вызывайте ее при возникновении события onunload:

<body onunload="unregisterAllEvents()">

Пример перехвата событий

Источник: http://ajaxcookbook.org/