« Поставить закладку » « Сделать стартовой »

« Форумы » « Блоги » « Статьи » « Новости » « Файлы » « Realcoding IRC » « Site map » « Поиск »


Главная Главная
Анонсы Анонсы
Форумы Форумы
Каталог Каталог
Поиск Поиск
Опросы Опросы
Книжный магазин Книжный магазин
Реклама на сайте
Публикации Публикации
Партнеры Партнеры
Карта Карта сайта
Рассылки Рассылки
RSS экспорт
Настройки Настройки
О нас пишут О нас пишут
Контакты Контакты
Гостевая книга Гостевая книга

Тестирование 64-битных приложений

ПнВтСрЧтПтСбВс
        1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
    Популярное
jQuery Autocomplete: автозаполнение

Функция AccessResource

Функция CreateRectRgnIndirect

Win32 API именованных каналов (named pipes) и почтовых ящиков (mailslots)

ExtJS: компонент выбора местонахождения

Определение класса атрибута

Осваиваем командную строку Windows 2003

Обработка исключений в C++

Компоненты: ListView

Как Создать Библиотеку




    Архив файлов



    Сообщества



    Документация

Статьи:: Интернет технологии :: Java Script :: 16 действительно полезных решений для JavaScript


отправить ссылку другу версия для печати  Обсудить на форуме

16 действительно полезных решений для JavaScript



Представляю вам набор функций, которые у меня лежат в отдельном файле utils.js - это функции, которые я использую чаще всего. Они стараются быть кроссбраузерными и проверены на IE6/7, FF2 и Safari 2 и на боевой, сложной системе, в XHTML документах. Должны, по идее, работать, и на других, но не очень старых версиях браузеров - проверку браузера я использовал только в исключительных случаях. Некоторая часть из них, конечно же, просто нарыта на просторах интернета (где - обычно указано) и заимствована ввиду открытости, а большая часть - сконструирована из многих ресурсов и своих идей (и советов коллег), дабы работать на ура - поскольку часто в разных скриптах не учитываются разные тонкости, которые, тем не менее - при ближайшем рассмотрении - оказываются общностями :) , ну и быть довольно читабельными.



Фукнции разделены тематически:

  • ООП -обеспечение (или, вернее сказать - эмуляция) возможности использовать принципы ООП в JavaScript
  • Объектная модель JS - использование и расширение встроенных объектов JS
  • Определение браузера - чтобы использовать в тех редких случаях, когда это все-таки неизбежно необходимо :)
  • Координаты / Позициионирование - вычисление координат и позиционирование объектов - ввиду того, что это часто довольно хитрая штука
  • DOM - работа с объектной моделью документа
  • AJAX - вспомогательные функции для AJAX - так как это средство часто применимо :)
  • Логгинг - иногда он нужен чтобы везде :)

NB! (советы по оптимизации и исправлениям приветствуются)

NB! (если вам не хватает подстветки кода в данной статье и вы используете браузер Firefox - прошу проследовать по этой ссылке за соответствующим плагином, поскольку в бесплатной версии WordPress обеспечить её внутренними средствами нет возможности)

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

ООП

1. Первый блок - набор из трех функций (две из которых пустые :) ), позволяющих применять (эмулировать?) все три принципа ООП в JavaScript. Из нескольких предложенных на AJAXPath и на AJAXPatterns вариантов я выбрал именно этот ввиду его одновременной понятности и быстрой скорости выполнения и немного его видоизменил, так - чтобы отдельно объявленные свойства воспринимались как статические константы.

function Class() { };

Class.prototype.construct = function() { };

Class.extend = function(def) {

    var classDef = function() {
        if (arguments[0] !== Class) {
            this.construct.apply(this, arguments);
        }
    };

    var proto = new this(Class);
    var superClass = this.prototype;

    for (var n in def) {
        var item = def[n];
        if (item instanceof Function) item.$ = superClass;
                else classDef[n] = item;
        proto[n] = item;
    }

    classDef.prototype = proto;
    classDef.extend = this.extend;

    return classDef;
};

Полные примеры использования относительно велики, поэтому я их вынесу в следующую статью и проследую далее. Пару простых примеров вы можете наблюдать в пунктах 2, 5 и 15.

2. Следующая функция - простая но изящная - полезна в сочетании с предыдущим набором - она создает функцию-ссылку на метод:

function createMethodReference(object, methodName) {
    return function () {
        return object[methodName].apply(object, arguments);
    };
}

Теперь можно, например, сделать так:

var ScrollingHandler = Class.extend({

    construct:
        function(elementId) {
            this._elementId = elementId;
            this.assignListener();
        },

    assignListener:
        function() {
            var scrollControlElem =
                        document.getElementById(this._elementId);
            if (scrollControlElem) {
                scrollControlElem.onscroll =
                    createMethodReference(this, "_onElementScroll");
            }
        },

    _onElementScroll:
        function(ev) {
            ev = ev || window.event;
            alert("please stop scrolling,
                        I've already got an event: " + ev);
        }
});

var elmScrollHandler = new ScrollHandler('SomeElmId');

Объект этого класса можно будет ассоциировать с событием скроллинга элемента с указанным ID и совершать что-либо по этому случаю.

Объектная модель JS

3. Нижеприведенная функция клонирует любой объект вместе со всеми его свойствами:

function cloneObj(objToClone) {
    var clone = [];
    for (i in objToClone) {
        clone[i] = objToClone[i];
    }
    return clone;
}

Использование - простейшее до невозможности:

var clonedObj = cloneObj(objToClone);

4. Конвертер объектов, следующая функция, позволяет удобно использовать всяческие условные (и претендующие ими быть :) ) конструкции вида if (tablet.toLowerCase() in oc(['cialis','mevacor','zocor'])) { alert('I will not!') };. Код заимствован отсюда.

function oc(a) {
    var o = {};
    for(var i=0;i<a.length;i++) {
        o[a[i]]='';
    }
    return o;
}

Для примера возьмем ситуацию, когда сначала требуется определить, входит ли объект в какое-либо множество одиночных объектов, а затем - не входит ли он в сочетании с другим объектом в другое множество пар объектов. Допустим, на вечеринку пускают одиночек только с определенными именами, либо пары из списка с позволенными сочетаниями имен:

function isPersonAllowed(maleName, femaleName) {
    var pairsAllowed = new Array([ "John", "Yoko" ],
            [ "Bill",  "Monica" ], [ "Phil",  "Sue" ],
            [ "Jason",  "Harrison" ], [ "Adam",  "Eve" ]);
    var singlesAllowed = new Array("Michael", "Pete", "John",
            "Dave", "Matthew");
    return (femaleName
            ? ([maleName, femaleName] in oc(pairsAllowed))
            : (maleName in oc(singlesAllowed)));
}

alert(isPersonAllowed("Jack")); // false
alert(isPersonAllowed("Adam")); // false
alert(isPersonAllowed("John")); // true
alert(isPersonAllowed("Phil","Marlo")); // false
alert(isPersonAllowed("Jason","Harrison")); // true
alert(isPersonAllowed("Martin","Luther")); // false

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

function Hash()
{
    this.length = 0;
    this.items = new Array();
    for (var i = 0; i < arguments.length; i++) {
        this.items[arguments[i][0]] = arguments[i][1];
    }
}

Доступ к элементам производится засчет свойства items (кстати, следует, может, в более тяжелой версии добавить keys :) ?):

var Game = Class.extend({ 

    STG_STOP: 0,
    STG_START: 1,
    STG_LOADING: 2,
    STG_MENU: 3,
    STG_PROCESS: 4,

    construct:
        function() { this._stage = Game.STG_LOADING; },

    getStage:
        function() { return this._stage; }

});

var stateMap = new Hash(
            [ Game.STG_START,   "start"    ],
            [ Game.STG_LOADING, "loading"  ],
            [ Game.STG_MENU,    "menu"     ],
            [ Game.STG_PROCESS, "process"  ],
            [ Game.STG_STOP,    "stopping" ]);

var someGame = new Game();
alert("You are in "+stateMap.items[someGame.getStage()]+" stage!");

6. Три других функции просто упрощают и/или делают очевиднее некоторые операции: getTime на 11 символов сокращает доступ к получению текущего времени, getTimeDelta позволяет найти промежуток в милисекундах между отрезками времени (или указанным моментом и текущим временем, в формате с одним параметром), а последняя функция расширяет свойства объекта Number для того чтобы при его значении NaN можно было чуть быстрее получить 0.

function getTime() {
    return new Date().getTime();
}

function getTimeDelta(timeBegin, timeEnd) {
    timeEnd = timeEnd || getTime();
    return timeEnd - timeBegin;
}

Number.prototype.NaN0=function() { return isNaN(this) ? 0 : this; }

Определение браузера

7. Небольшой объект, поименованные по названиям браузеров свойства которого - суть условия. Этим достигается более читабельное (но не настолько скурпулезное насколько могло бы быть) определение большинства типов браузеров. Этот объект был заимствован мной из проекта, в котором я учавствовал - и как-то прижился, но, думаю, истинные авторы всё-таки где-то в сети, да и код не так уж сложен и громоздок чтобы на него сильно претендовать :). Кроме того, он конечно не идеально надежен (а некоторые говорят что не надежен вообще), но пока на перечисленных браузерах он меня не подвел ни разу :). Если вас не устраивает такое положение дел - вы можете использовать нечто похожее с HowToCreate. И повторюсь: данное определение я стараюсь использовать (как и сказано, например, по ссылке) “только в случае если известен конкретный баг в конкретном браузере и его нужно обойти”. Также - несложно пересобрать этот объект в одно длинное условие, для меньшей скорости исполнения (см., опять же, ссылку)

var USER_DATA = {

    Browser: {
        KHTML: /Konqueror|KHTML/.test(navigator.userAgent) &&
                !/Apple/.test(navigator.userAgent),
        Safari: /KHTML/.test(navigator.userAgent) &&
                /Apple/.test(navigator.userAgent),
        Opera: !!window.opera,
        MSIE: !!(window.attachEvent && !window.opera),
        Gecko: /Gecko/.test(navigator.userAgent) &&
                !/Konqueror|KHTML/.test(navigator.userAgent)
    },

    OS: {
        Windows: navigator.platform.indexOf("Win") > -1,
        Mac: navigator.platform.indexOf("Mac") > -1,
        Linux: navigator.platform.indexOf("Linux") > -1
    }
}

Координаты / Позициионирование

8. Набор функций, позволяющих получить координаты элемента на экране пользователя. Если ваш документ статичен относительно окна и не имеет скроллбаров - лучше использовать функцию getPosition - так будет быстрее. В обратном случае используйте getAlignedPosition - она учитывает положения скроллбаров. Только обратите внимание: значение top у элемента может быть орицательным, если элемент верхней частью за пределами окна - для синхронизации с курсором мыши иногда нужно обнулить в этом случае высоту. Основной скрипт позаимствован из одного блога, Aligned-версия - результат поисков по сусекам и совмещения с информацией из двух статей (при обнаружении DOCTYPE IE входит в свой собственный, несколько непредсказуемый, режим).

var IS_IE = USER_DATA['Browser'].MSIE;

function getPosition(e){
    var left = 0;
    var top  = 0;

    while (e.offsetParent) {
        left += e.offsetLeft + (e.currentStyle ?
            (parseInt(e.currentStyle.borderLeftWidth)).NaN0() : 0);
        top  += e.offsetTop  + (e.currentStyle ?
            (parseInt(e.currentStyle.borderTopWidth)).NaN0() : 0);
        e = e.offsetParent;
    }

    left += e.offsetLeft + (e.currentStyle ?
            (parseInt(e.currentStyle.borderLeftWidth)).NaN0() : 0);
    top  += e.offsetTop  + (e.currentStyle ?
            (parseInt(e.currentStyle.borderTopWidth)).NaN0(): 0); 	

    return {x:left, y:top};
}

function getAlignedPosition(e) {
    var left = 0;
    var top  = 0;

    while (e.offsetParent) {
        left += e.offsetLeft + (e.currentStyle ?
            (parseInt(e.currentStyle.borderLeftWidth)).NaN0() : 0);
        top  += e.offsetTop  + (e.currentStyle ?
            (parseInt(e.currentStyle.borderTopWidth)).NaN0() : 0);
        e  = e.offsetParent;
        if (e.scrollLeft) {left -= e.scrollLeft; }
        if (e.scrollTop)  {top  -= e.scrollTop; }
    }

    var docBody = document.documentElement ?
        document.documentElement : document.body;

    left += e.offsetLeft +
        (e.currentStyle ?
                (parseInt(e.currentStyle.borderLeftWidth)).NaN0()
                : 0) +
        (IS_IE ? (parseInt(docBody.scrollLeft)).NaN0() : 0) -
        (parseInt(docBody.clientLeft)).NaN0();
    top  += e.offsetTop  +
        (e.currentStyle ?
                (parseInt(e.currentStyle.borderTopWidth)).NaN0()
                :  0) +
        (IS_IE ? (parseInt(docBody.scrollTop)).NaN0() : 0) -
        (parseInt(docBody.clientTop)).NaN0();

    return {x:left, y:top};
}

9. Определить текущие координаты курсора мыши и смещение элемента относительно курсора легко, если использовать соответствующие функции:

function mouseCoords(ev) {

    if (ev.pageX || ev.pageY) {
        return {x:ev.pageX, y:ev.pageY};
    }

    var docBody = document.documentElement
                        ? document.documentElement
                        : document.body;

    return {
        x: ev.clientX + docBody.scrollLeft - docBody.clientLeft,
        y: ev.clientY + docBody.scrollTop  - docBody.clientTop
    };
}

function getMouseOffset(target, ev, aligned) {
    ev = ev || window.event;
    if (aligned == null) aligned = false;

    var docPos    = aligned
        ? getAlignedPosition(target)
        : getPosition(target);
    var mousePos  = mouseCoords(ev);

    return {
        x: mousePos.x - docPos.x,
        y: mousePos.y - docPos.y
    };
}

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

function onMouseMove(elm, ev) {
    var mouseOffset = getMouseOffset(elm, ev);
    console.log("x: %d; y: %d", mouseOffset.x, mouseOffset.y);
}
. . .
<div id="someId" onmousemove="onMouseMove(this, event);
        return false;"></div>

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

function findOffsetHeight(e) {
    var res = 0;
    while ((res == 0) && e.parentNode) {
        e = e.parentNode;
        res = e.offsetHeight;
    }
    return res;
}

function getOffsetHeight(e) {
    return this.element.offsetHeight ||
            this.element.style.pixelHeight ||
            findOffsetHeight(e);
}

DOM

11. Иногда нужно пройти рекурсивно по дереву DOM, начиная с некоторого элемента и выполняя некоторую функцию над каждым из потомков, забираясь в самую глубь. В DOM есть объект TreeWalker, но он не работает в IE и не всегда удобен/прост в использовании. Функция walkTree позволяет выполнить некоторую другую функцию над каждым из элементов и позволяет также передать в нее некоторый пакет данных. Функция searchTree отличается от нее тем, что останавливает проход по дереву при первом удачном результате и возвращает результат в точку вызова:

function walkTree(node, mapFunction, dataPackage) {
    if (node == null) return;
    mapFunction(node, dataPackage);
    for (var i = 0; i < node.childNodes.length; i++) {
        walkTree(node.childNodes[i], mapFunction, dataPackage);
    }
}

function searchTree(node, searchFunction, dataPackage) {
    if (node == null) return;
    var funcResult = searchFunction(node, dataPackage);
    if (funcResult) return funcResult;
    for (var i = 0; i < node.childNodes.length; i++) {
        var searchResult = searchTree(node.childNodes[i],
                            searchFunction, dataPackage);
        if (searchResult) return searchResult;
    }
}

В примере используются функции setElmAttr и getElmAttr, которые будут рассмотрены позже - в пункте 13. По сути они делают то же что и getAttribute и setAttribute. Пояснения к используемой функции oc вы можете посмотреть в пукте 4. В первой части примера корневому элементу атрибут “nodeType” устанавливается в “root”, а всем его потомкам - в “child”. Во второй части демонстрируется также передача пакета данных - при нахождении первого элемента с атрибутом “class”, равным одному из перечисленных в пакете имен, атрибут “isTarget” ему устанавливается в “true”.

var rootElement = document.getElementById('rootElm');

setElmAttr(rootElement, "nodeType", "root");
var childNodeFunc = function(node) {
    if (node.nodeName && (node.nodeName !== '#text')
                        && (node.nodeName !== '#comment')) {
        setElmAttr(node, "nodeType", "child");
    }
}
walkTree(rootElement, childNodeFunc);

var findTargetNode = function(node, classList) {
    if ((node.nodeName && (node.nodeName !== '#text')
                    && (node.nodeName !== '#comment')) &&
                    (getElmAttr(node, "class") in oc(classList))) {
        return node;
    }
}
var targetNode = searchTree(rootElement, findTargetNode,
                    ['headingClass', 'footerClass', 'tableClass']);
setElmAttr(targetNode, "isTarget", true);

12. Удаление узлов - иногда необходимая задача. Иногда нужно удалить сам узел, а иногда - только его потомков. Функция removeChildrenRecursively рекурсивно удаляет всех потомков указанного узла, не затрагивая, конечно, его самого. Функция removeElementById, как и сказано в названии, удалает узел по его id - при всей простоте задачи способ относительно хитрый:

function removeChildrenRecursively(node)
{
    if (!node) return;
    while (node.hasChildNodes()) {
        removeChildrenRecursively(node.firstChild);
        node.removeChild(node.firstChild);
    }
}

function removeElementById(nodeId) {
    document.getElementById(nodeId).parentNode.removeChild(
                            document.getElementById(nodeId));
}

13. Казалось бы - элементарная задача работы с атрибутами элемента - иногда наталкивает на абсолютно неожиданные проблемы: например, IE бросает исключение при попытке доступа к атрибутам высоты/ширины элемента table, а у Safari отличается способ доступа к атрибутам с пространствами имен. Приведенные ниже функции обходят все встреченные мной проблемы без сильного ущерба к скорости выполнения (конечно же, в стандартных случаях лучше использовать встроенные функции):

var IS_SAFARI = USER_DATA['Browser'].Safari;

function getElmAttr(elm, attrName, ns) {
    // IE6 fails getAttribute when used on table element
    var elmValue = null;
    try {
        elmValue = (elm.getAttribute
                    ? elm.getAttribute((ns ? (ns + NS_SYMB) : '')
                    + attrName) : null);
    } catch (e) { return null; }
    if (!elmValue && IS_SAFARI) {
        elmValue = (elm.getAttributeNS
                    ? elm.getAttributeNS(ns, attrName)
                    : null);
    }
    return elmValue;
}

function setElmAttr(elm, attrName, value, ns) {
    if (!IS_SAFARI || !ns) {
        return (elm.setAttribute
                    ? elm.setAttribute((ns ? (ns + NS_SYMB) : '')
                    + attrName, value) : null);
    } else {
        return (elm.setAttributeNS
                    ? elm.setAttributeNS(ns, attrName, value)
                    : null);
    }
}

function remElmAttr(elm, attrName, ns) {
    if (!IS_SAFARI || !ns) {
        return (elm.removeAttribute
                    ? elm.removeAttribute((ns ? (ns + NS_SYMB) : '')
                    + attrName) : null);
    } else {
        return (elm.removeAttributeNS
                    ? elm.removeAttributeNS(ns, attrName)
                    : null);
    }
}

Засчет универсальности появляется некоторая неудобочитаемость ввиду того, что необязательный атрибут пространства имен - последний. Решения приветствуются.

AJAX

14. Если вам не нужно ничего большего, чем просто выполнить асинхронный запрос и на основе полученных данных сделать нечто - для вас эта функция. Способ получения объекта XMLHttpRequest безусловно может быть заменен. Комментарии намеренно оставлены, дабы показать некоторые идеи по расширению:

function makeRequest(url, parameters, onComplete, package) {

    var http_request = false;
    try {
        http_request = new ActiveXObject("Msxml2.XMLHTTP");
    } catch (e1) {
        try {
            http_request= new ActiveXObject("Microsoft.XMLHTTP");
        } catch (e2) {
            http_request = new XMLHttpRequest();
        }
    }

    //if (http_request.overrideMimeType) { // optional
    //  http_request.overrideMimeType('text/xml');
    //}

    if (!http_request) {
      alert('Cannot create XMLHTTP instance');
      return false;
    }

    completeListener = function() {
        if (http_request.readyState == 4) {
            if (http_request.status == 200) {
                onComplete(http_request, package)
            }
        }
    };

    //var salt = hex_md5(new Date().toString());
    http_request.onreadystatechange = completeListener;
    http_request.open('GET', url + "?" + parameters, true);
    //http_request.open('GET', './proxy.php?' + parameters +
                    // "&salt=" + salt, true);
    http_request.send(null);
}

Пример использования - из одного моего рабочего тестового задания, которое занималось поиском в базе музыки и/или фильмов по введенной в элемент (с id “searchStr”) строке, используя SQL’ный LIKE:

function gotSearchResults(http_request, dataPackage) {
    request_result = http_request.responseText;
    var divElement = document.getElementById(dataPackage["divId"]);
    divElement.innerHTML = request_result;
}

function insertMusicSearchResults(divId) {
    var searchStrElement = document.getElementById("searchStr");
    var dataPackage = new Array();
    dataPackage["divId"] = divId;
    makeRequest("getAlbums.php", "searchStr="
            + searchStrElement.value, gotSearchResults, dataPackage);
}

function insertVideoSearchResults(divId) {
    var searchStrElement = document.getElementById("searchStr");
    var dataPackage = new Array();
    dataPackage["divId"] = divId;
    makeRequest("getMovies.php", "searchStr="
            + searchStrElement.value, gotSearchResults, dataPackage);
}

Логгинг

15. Представленная ниже функция для помощи в ведении логов очень проста, добавьте в нужное место в документе элемент <div id="LOG_DIV"></div>, задайте ему необходимую высоту, и в него будет сбрасываться информация + обеспечиваться ее скроллинг:

function LOG(informerName, text) {
    var logElement = document.getElementById('LOG_DIV');
    if (logElement) {
        logElement.appendChild(document.createTextNode(
                        informerName + ': ' + text));
        logElement.appendChild(document.createElement('br'));
        logElement.scrollTop += 50;
    }
}

16. В замечательном плагине Firebug для браузера Firefox есть замечательная консоль, в которую с широкими возможностями можно производить логгинг. Однако, если вы отлаживаете параллельно код в других браузерах - обращения к ней могут вызывать ошибки. Для того чтобы не очищать каждый раз код от логов, можно использовать такую заглушку:

var Console = Class.extend({
    // the stub class to allow using console when browser have it,
    // if not - just pass all calls
    construct: function() {},
    log: function() { },
    info: function() { },
    warn: function() { },
    error: function() { }
});

if (!window.console) {
    console = new Console();
}

Сочетание этого и предыдущего пункта + CSS может вдохновить вас на написание собственной консоли с функциональностью консоли Firebug, но для других браузеров ;). Если вы ее напишете - поделитесь, пожалуйста, со мной :).

Бонус

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

var dblClicked = false;
var dblClickedNode = null; 

function dblClick(clickedNode) {
    dblClicked = true;
    dblClickedNode = clickedNode || dblClickedNode;
}

function releaseDblClick() {
    setTimeout('dblClicked=false;', 300);
}

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

<div id="someId" onclick="if (!dblClicked) alert('click');"
ondblick="dblClick(this); alert('dblclick'); releaseDblClick();";></div>

Заключение

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

Источник: шаманские бредни




Рубрика: Java Script




Trac + Subversion @ Ubuntu: Revisited.

Ubuntu

Задача: Установить на только что инсталлированный Ubuntu последнюю версию Trac, создать репозитории для нескольких проектов и настроить окружение соответственно. Структура проектов должна быть полностью корректной, установка максимально быстрой при минимальном количестве пакетов. Авторизация в репозитории и окружения Trac может быть общей, но позволяющей индивидуальную настройку для каждого проекта. Также, установка должна быть максимально независима от версий.


Подробнее... | Рубрика: Ubuntu | Добавлено: 30.08.2008

[g]Vim в режиме Python: Рекомпиляция в Windows.

Статьи

Редактор Vim наиболее известен среди разработчиков в системах Unix — конкурент emacs, что-то вроде консольного IDE — этот редактор при должной сноровке и настройке (мне кажется, сноровке несколько меньшей и настройке более очевидной чем в emacs, но у последнего также есть мощная мультифункциональность — выбор за программистом) способен убыстрить и упростить многие процессы на этапах разработки не в ущерб таким удобствам как, например, авто-дополнение и навигация по проекту.


Подробнее... | Рубрика: Статьи | Добавлено: 30.08.2008

Java + JSON. Пути к дружбе.

Технология JAVA

Спешу поделиться результатами небольшого исследования, оказавшегося необходимым для текущего проекта. Рассматривается возможность связки Java и JSON, её преимущества и недостатки. Я расскажу о практической части, о теории больше поведают нижеприведённые ссылки (англ.).


Подробнее... | Рубрика: Технология JAVA | Добавлено: 30.08.2008

Остальные статьи:

Драйвер SQL Server 2005 для PHP
Типы данных в MySQL (сжатый справочник для PHP программиста)
PHP класс для работы с Яндекс.XML
Ошибки начинающих PHP разработчиков
Наследование шаблонов в Smarty
Особенности хранения сессий PHP в memcached
Internet Explorer 8 beta 2
9 правил для начинающего Ajax-разработчика
ExtJS 2.2 - полная поддержка Firefox 3, новые виджеты и другие нововведения
Windows 7: под покровом тайны
Apache mod_ndb - MySQL кластер с доступом через HTTP и Ajax
Поиск уязвимостей в программах с помощью анализаторов кода
Как появилась библиотека VivaCore
Это сложно
ASP.NET и немного поисковой оптимизации
Protocol buffers: библиотека обмена данными для C++, Java, Python от Google


Цитата дня (все,добавить):



    Рубрикатор

Программирование

C/С++
Обучение
Windows API
XAML
Моделирование
Паттерны
Visual Basic 7 .NET
WxWidgets
Функции WinApi
Функции С++
Разработка под Mac OS
Eiffel
Visual Studio 2008
UI дизайн
Алгоритмы
Конкурсные статьи
Turbo Pascal
Visual Studio
CASE-средства
Visual Studio 2005
Без VCL
Delphi
Тех. документация
Тестирование
Software Testing
ООП
TCP/IP
Google Android
Windows Installer
.NET Framework
Драйвера
C# C Sharp
Справка
Проектирование
Информ. системы
Visual Basic
Assembler
Оптимизация кода
Gtk+
Компоненты
Реинжиниринг
Управление проектами
Extreeme programming
Lotus Notes
Алгебраическое проектирование

Интернет технологии

PHP
Perl
ASP
WAP
Cookies
SSI
CGI
Web Servers
VB Script
DNS
CSS
XML
Html
Java Script
Java2ME
Firewall
Flash
.htaccess
Apache
VRML
Протоколы
Поисковые системы
Технология JAVA
Учебник по PHP
Учебник по JavaScript
Учебник по XML
Java Q&A
AJAX
DHTML
XHTML
Dreamweaver
Web 2.0
Python
Вебмастеру
Cisco
Ruby on Rails
Silverlight

Базы данных

Access
InterBase
MySQL
Oracle
ADO .NET
Основы SQL
Учебник по Access 2002
MS
Microsoft FoxPro
Доступ к данным
XML в MS SQL Server 2000
ODBC и MyODBC
Обучение
Caché
DB2
PostgresSQL
Sybase
Теория
Хранилища данных
Безопасность
Реляционные данные
MySQL и mSQL

Остальное:

Разное
Обзоры книг
Безопасность
Графика и дизайн
Юмор
Linux
Фракталы
Microsoft Axapta
Многоядерность
Сети
Microsoft Office
Работа
MS-DOS
Криптография
Графика и игроделание
Новости SDK
Системы защиты
Учебник по AutoCad
CVS
Windows XP
Windows Server 2003
Windows Vista
Windows 7
Мероприятия

    Кто на сайте
Вы не зарегистрированы.
Имя:

Пароль:

Запомнить

Регистрация позволит Вам пользоваться дополнительными сервисами.
Сейчас на сайте:
Гостей: 78
Пользователей: 0