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

вторник, 4 марта 2008 г.

Javascript ошибки

Сейчас разруливаю jQuery framework - отличная разработка! Много готовых и расширяемых инструментов. Не мог разобраться с одной ошибкой около часа. В итоге понял, в чем дело... поэтому пишу заметку в блог: если ищешь javascript ошибку больше, чем полчаса - посмотри в правильном ли порядке ты подключаешь скрипты !!!

четверг, 10 января 2008 г.

Перехват нажатия Enter в IE

Вот так уж повелось, что IE не дает спокойно жить всем web-developerам. И меня он не устает удивлять.

Ситуация следующая: в текстовое поле вводится числовое значение, по нажатию Enter это значение передается на сервер (при помощи AJAX). Что может быть проще? Я привязал функцию обновления на событие onchange элемента input (текст). Как обычно, все идеально сработало в FireFox и Safari. А этот IE... При нажатии Enter - вообще ничего не происходило.

Объясняю: в IE Enter вызывает событие "onsubmit" формы.

Решение: input должен находиться в форме. На событие onsubmit ставим return false;
И добавляем следующий код:

processKeyEvent = function(eventType, event)
{
if (window.event)
{
event = window.event;
}
var caller_;
if (event.target)
caller_ = event.target;
if (event.srcElement)
caller_ = event.srcElement;
var code;
if (event.keyCode) code = event.keyCode;
else if (event.which) code = event.which;

switch (code)
{
case 13:
checkEnteredOrder(caller_); // наша функция для обновления
break;
}
};

processKeyPress = function(event)
{
processKeyEvent("onkeypress", event);
};Syhi-подсветка кода


Затем меняем событие onchange на keypress:

input.onkeypress = processKeyPress;


Теперь все проходит через processKeyPress хэндлер, а в нем мы отлавливаем нажатую клавишу по keycode.

P.S.: Чувствую, скоро нужно будет создать отдельную категорию на блоге типа "Умри, IE поганый" или "Instant Evil"





вторник, 8 января 2008 г.

const + javascript in IE

Ну вот закончились праздники (ура!), и снова любимая работа...

Первое удивление в новом году:

Никогда не используйте ключевое слово const в javascript. Константы не поддерживаются в IE (в этом только что убедился, посвятив отладке 2 часа). Так что var вам в помощь ;-)


пятница, 21 декабря 2007 г.

Javascript Treeview

В нашем "вечном" проекте появилась новая задача - реализовать иерархическую структуру категорий. Сделать это нужно было в таблице + реализовать следующие действия:
  • открытие/закрытие ветвей дерева
  • перемещение категории на уровень вверх/вниз
  • дублирование (как категории отдельно, так и целой ветки)
  • удаление элементов

Немного поразмыслив я придумал такой подход:

Каждой строке таблицы присваивается 2 параметра:
level - уровень, на котором лежит узел (от 0 и выше)
state - состояние узла (open - узел открыт, closed - закрыт, end - узел является конечным )


Смотрите скриншот таблицы:




И так, первая функция для открытия и закрытия узлов. Встречайте:

  1. function changeRowState(box, RH_Panel)
  2. {
  3. elem = box.parentNode.parentNode.parentNode;

  4. var current_level = elem.getAttribute("level");
  5. var current_state = elem.getAttribute("state");
  6. var current_table = "table_body";

  7. if(RH_Panel)
  8. current_table = "RH_table_body";

  9. var row_display = "none"; // for style.display
  10. if(current_state == "closed") // if item is closed, than show all children
  11. row_display = "";


  12. var tbody = document.getElementById(current_table);
  13. var children = tbody.childNodes;

  14. var after_current = false;

  15. for(var i=0; i<children.length; i++)
  16. {
  17. if(children[i].tagName == 'TR')
  18. {
  19. if(children[i] == elem)
  20. {
  21. after_current = true;
  22. }

  23. if(after_current)
  24. {
  25. if((children[i] != elem) && (children[i].getAttribute('level') == current_level))
  26. {
  27. if(current_state == "open")
  28. {
  29. elem.setAttribute("state", "closed");
  30. box.src = "images/branch_closed.gif";
  31. }
  32. else
  33. {
  34. elem.setAttribute("state", "open");
  35. box.src = "images/branch_open.gif";
  36. }
  37. return;
  38. }

  39. if(children[i].getAttribute('level') > current_level)
  40. {

  41. children[i].style.display = row_display;
  42. }
  43. }
  44. }
  45. }

  46. if(current_state == "open")
  47. {
  48. elem.setAttribute("state", "closed");
  49. box.src = "images/branch_closed.gif";
  50. }
  51. else
  52. {
  53. elem.setAttribute("state", "open");
  54. box.src = "images/branch_open.gif";
  55. }

Эту функцию мы ставим на событие onclick для элемента <img> в строке таблицы:

<tr level="0" state="open" style="background:#99ddaa;">
<td><input type="checkbox" name="tree_items[]" /></td>
<td>
<a href="javascript:void(0)">
<img src="images/branch_open.gif" onclick="changeRowState(this);" />
</a>
<a href="action.php">&nbsp;&nbsp;<b>Web Channel (2)</b></a>
</td>
<td>56</td>
<td>2</td>
<td>3</td>
<td>10</td>
<td class="statusProduction">Published</td>
</tr>Syhi-подсветка кода


Логика очень проста: при нажатии на иконку, функция проходит по всем строчкам таблицы и изменяет атрибут display (если уровень больше). При таком подходе, в принципе, уровень вложенности может быть большим. Но для нашего проекта я сделал ограничение до 10 уровней.

Функция для изменения уровня узлов:

function changeLevel(direction)
{
var delta_level = -1;
if(direction == "down")
delta_level = 1;

var checkboxes = document.getElementsByName("tree_items[]");

for(var i=0; i<checkboxes.length; i++)
{
if(checkboxes[i].checked)
{
var row = checkboxes[i].parentNode.parentNode;
var current_level = row.getAttribute("level");

if(current_level != 0 || direction == "down") // dont move up row with level = 0
{
var td = checkboxes[i].parentNode.nextSibling;
if(td.nodeType == 3)
td = checkboxes[i].parentNode.nextSibling.nextSibling;

var prev_html = td.innerHTML;
prev_html = prev_html.slice(prev_html.indexOf("<"));
var new_level = parseInt(current_level) + parseInt(delta_level);
td.innerHTML = getSpacesForLevel(new_level) + prev_html;
row.setAttribute("level", new_level);
row.style.backgroundColor = arrColors[new_level];

var tbody = document.getElementById('table_body');
var children = tbody.childNodes;
var row_index = getRowIndex(row);

if(direction == "down")
row_index++;

for(var j=row_index; j<children.length; j++)
{
if(children[j].tagName == 'TR')
{
if(children[j].getAttribute("level") == current_level)
break;

if(children[j].getAttribute("level") > current_level)
{
var cur_level = children[j].getAttribute("level")
var td = children[j].childNodes[3];
if(td.innerHTML.indexOf("<img") == -1) // IE and Safari hack
td = children[j].childNodes[1];

var prev_html = td.innerHTML;
prev_html = prev_html.slice(prev_html.indexOf("<"));
var new_lev = parseInt(cur_level) + parseInt(delta_level);
td.innerHTML = getSpacesForLevel(new_lev) + prev_html;
children[j].setAttribute("level", new_lev);
children[j].style.backgroundColor = arrColors[new_lev];
}
}
}// for
checkAll(0); // uncheck all checkboxes
}// if
}// if checked


// AJAX request to set level
}
}Syhi-подсветка кода


А также функции дублирования:

function duplicateSingle()
{
var checkboxes = document.getElementsByName("tree_items[]");
var tbody = document.getElementById("table_body");

var len = checkboxes.length; // FireFox hack (against constant reference to collection of checkboxes)
for(var i=0; i<len; i++)
{
if(checkboxes[i].checked)
{
var row = checkboxes[i].parentNode.parentNode;
var inserted_row = tbody.appendChild(row.cloneNode(1));

var td = inserted_row.childNodes[3];
if(td.innerHTML.indexOf("<img") == -1) // IE and Safari hack
td = inserted_row.childNodes[1];

var cell_content = td.innerHTML;
var ins_pos = cell_content.indexOf("</b>");
td.innerHTML = cell_content.slice(0, ins_pos) + " Copy" + cell_content.slice(ins_pos);
}
}
checkAll(0);
}

function duplicateBranch()
{
var checkboxes = document.getElementsByName("tree_items[]");
var tbody = document.getElementById("table_body");

var len = checkboxes.length; // FireFox hack (against constant reference to collection of checkboxes)
for(var i=0; i<len; i++)
{
if(checkboxes[i].checked)
{
var row = checkboxes[i].parentNode.parentNode;
var inserted_row = tbody.appendChild(row.cloneNode(1));
var current_level = inserted_row.getAttribute("level");

var tbody = document.getElementById('table_body');
var children = tbody.childNodes;
var row_index = getRowIndex(row);


for(var j=(row_index+1); j<children.length; j++)
{
if(children[j].tagName == 'TR')
{
if(children[j].getAttribute("level") == current_level)
break;

if(children[j].getAttribute("level") > current_level)
{
tbody.appendChild(children[j].cloneNode(1));
}
}
}
}
}
checkAll(0);
}Syhi-подсветка кода


Кому нужны будут подробные объяснения, или кто сталкивался с подробной задачей - сообщите об этом в комментах.

Удачи!

среда, 5 декабря 2007 г.

Какая же ты прелесть ... C# !

С прошлой недели потихоньку начинаю переходить на C# - очень классная язык! Я просто балдею от него!

Параллельно с изучением в ШАГе решил написать свой проект для раскрутки сайтов.
Идея давно всем известна и проста - полуавтоматическая регистрация в поисковиках, каталогах и т.д.

Пока делаю основную часть программы. В будущем планирую добавить инструменты для упрощения работы с рекламными программами а также часть инструментов для блоггеров.

Все свои результаты выложу здесь, так что следите :-)

P.s.: использую Framework 2, у кого нету - можете скачать ТУТ (23,5 Мб)



пятница, 30 ноября 2007 г.

GUID Generator

Вот на днях понадобилось генерировать GUID. GUID (Globally Unique Identifier) — представляет собой статистически уникальный 128-битный идентификатор. Его главная особенность — уникальность, которая позволяет создавать расширяемые сервисы и приложения без опасения получения конфликтов, вызванных совпадением идентификатора. Хотя уникальность каждого отдельного GUID и не гарантируется, общее количество уникальных ключей настолько велико, что вероятность того, что один и тот же ключ будет получен дважды, крайне мала.

GUID — это частная реализация (фирмой Microsoft) стандарта, имеющего название Universally Unique Identifier (UUID).

В тексте GUID записывается в виде строки из 16-ричных цифр, разбитых на группы дефисами и окружённой фигурными скобками:

{6F9619FF-8B86-D011-B42D-00CF4FC964FF}

Есть куча online сервисов, которые позволяют это сделать, я же предлагаю скачать мой GUID Generator (написан на C# Framework v2.0 )


вторник, 27 ноября 2007 г.

PHP загрузчик с ProgressBar'ом

Одним из недостатков загрузки файлов через веб-интерфейс является отсутствие возможности увидеть статус процесса загрузки.

Raditha Dissanyake предлагает свой вариант решения этой проблемы -
"Mega Upload". CGI скрипты + javascript (страница загрузки: http://sourceforge.net/projects/megaupload/).

При аплоаде появляется вот такое окошко:



В есь процесс проходит такой путь:

1) Сабмит формы с файлами
2) Вызов javascript функции postIt
3) Передача управления upload - хендлэру
4) Хендлер выбирает нужный скрипт, который выполняет манипуляцию с файлами
5) Возврат в форму загрузки


Рассмотрим все этапы подробнее.

Форма загрузки должна иметь следующий вид:


<form enctype="multipart/form-data" action="/cgi-bin/upload.cgi?sid=1Kfg87r4sd5" method="post" name="uploadForm">
<input name="sessionid" value="1Kfg87r4sd5" type="hidden">
<input name="upload_single_font" value="1" type="hidden">
Файл 1: <input name="file[0]" type="file">
Файл 2: <input name="file[1]" type="file">
Файл 3: <input name="file[2]" type="file">
<input type="reset"> <input value="Загрузить" onclick="checkFields();" type="button">
</form>


Рассмотрим необходимые поля:

  • sessionid - используется для безопасности (в CGI сравнивается с параметром, переданным в адресной строке)

  • upload_single_font - название actiona, по которому в upload - хэндлере будет выбираться нужный скрипт для манипуляции с файлами


После нажатия на кнопку "Загрузить" вызывается javascript функция checkFields(). В ней можно проверить не пуста ли форма с файлами, а также здесь вызывается функция postIt() - она берет значения из формы и передает их CGI скрипту. После этого появляется окошко с ProgressBar'ом, управление передается upload - хэндлеру.
Структура хэндлера следующая:


if(isset($_REQUEST['upload_single_font']))
$upload_single_font = $_REQUEST['upload_single_font'];


// ...
// здесь могут быть проверки других actions
// ...

else if (@$upload_single_font)
{
include_once './upload_single_font.php';
exit;
}


Таким образом управление передается соответствующему скрипту (upload_single_font.php)

В скрипте для манипуляции с файлами массив файлов хранится в $file (не $_FILES !!!)

И финальный этап - редирект в изначальную форму с радостным сообщением ("Файлы успешно загрузились").

Если кто-нибудь еще знает способы реализации ProgressBar'ов - пишите в комментариях.


четверг, 22 ноября 2007 г.

Прикручиваем WebMoney на сайт

Вот так выводишь денежку из партнерок, и думаешь: а как же это сделано у них на сайте?
Для операций с WebMoney существует официальный "Merchant WebMoney Transfer".

Он содержит несколько интерфейсов:
  • Web Merchant Interface - интерфейс позволяющий быстро и с минимальными затратами дополнить свой веб-сайт или домашнюю страничку всем необходимым для того, чтобы начать принимать WM за предоставляемые вами товары или услуги
  • Click&Buy Merchant Interface - интерфейс позволяющий покупателю оплатить и получить товар на вашем веб-сайте одним кликом мышки; поддерживается начиная с версии WM Keeper Classic 2.2.0.9
  • WM Automation Interface - набор интерфейсов, позволяющих создавать программы, выполняющие операции в системе WebMoney Transfer с использованием протоколов HTTPS и XML.
Все примеры и подробности - на официальном сайте WebMoney

А как это сделать на PHP рассказано ЗДЕСЬ

Создание XML на php

Все знают о DOM функциях в javascript. При помощи них можно создать или изменить дерево документа динамически. В языке php тоже предусмотрен целый набор DOM

функций, причем они не требуют никаких дополнительных библиотек, так как являются частью ядра php.

Функции DOM очень удобно использовать при создании XML файлов.
Рассмотрим небольшой пример: нужно построить XML такого вида:


<?xml version="1.0" encoding="UTF-8"?>
<Товары>
<Клавиатура КоличествоКнопок="108">
<Бренд>Logitech</Бренд>
<Тип>проводная</Тип>
<Модель>KB-2025</Модель>
<Производитель>Тайвань</Производитель>
</Клавиатура>
</Товары>


Чтобы реализовать это при помощи DOM функций, создаем объект DOMDocument. Это следует сделать так:
$dom = new DOMDocument("1.0");

Основные методы, которые нам понадобятся:


  • $dom->createElement(имя_элемента) - создает XML элемент

  • $dom->createAttribute(имя_аттрибута) - создает аттрибут для элемента

  • $dom->createTextNode(текст) - создает текстовый элемент (узел)

  • $Node->appendChild(объект_Node) - применяет узел к указанному элементу


Далее приведен код с комментариями:

<?php
$dom = new DOMDocument("1.0");
// создаем корневой элемент 'Товары'
$root = $dom->createElement('Товары');
// создаем товар 'Клавиатура'
$keyb = $dom->createElement('Клавиатура');
// создаем аттрибут для клавиатуры
$q = $dom->createAttribute('КоличествоКнопок');
// применяем аттрибут для клавиатуры
$keyb->appendChild($q);
// добавляем элемент 'Клавиатура' к корневому элементу
$root->appendChild($keyb);

// создаем элемент 'Бренд'
$brand = $dom->createElement('Бренд');
// создаем текстовый узел
$txt = $dom->createTextNode('Logitec');
// записываем текст в содержимое тега 'Бренд'
$brand->appendChild($txt);

// располагаем 'Бренд' внутри тега 'Клавиатура'
$keyb = $dom->appendChild($brand);
// ...
?>


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


// сохраняем файл
$dom->save('file.xml');

Кроме этого можно не сохранять данные в файл, а получить их в виде строки:

// получаем строку
$str = $dom->saveXML();