Javascript-форум (https://javascript.ru/forum/)
-   Events/DOM/Window (https://javascript.ru/forum/events/)
-   -   Является ли объект DOM объектом (https://javascript.ru/forum/events/46005-yavlyaetsya-li-obekt-dom-obektom.html)

Hapson 24.03.2014 20:29

Является ли объект DOM объектом
 
Пишу я функцию.
Функция принимает в параметре DOM элемент.
В процессе работы функция может имитировать клик по переданному элементу.
function foo(elem){
    elem.click();
    // or
    elem.submit()
}

Это будет модуль ajax проверки авторизации перед действием, но суть не в этом.
Нужно в функции сразу проверить, является переданный параметр DOM элементом. Ну и в разумных пределах отфильтровать, так как head и body тоже имеют метод click.
var doc = document;
var head = document.head;
var body = document.body;
var div = document.getElementById("dv");

console.log("document");
console.log("nodeType: "+ doc.nodeType);
console.log("typeObject: "+ new Object().toString.call(doc));
console.log("click: "+ doc.click);
console.log("---");

console.log("head");
console.log("nodeType: "+ head.nodeType);
console.log("typeObject: "+ new Object().toString.call(head));
console.log("click: "+ head.click);
console.log("---");

console.log("body");
console.log("nodeType: "+ doc.nodeType);
console.log("typeObject: "+ new Object().toString.call(body));
console.log("click: "+ body.click);
console.log("---");

console.log("div");
console.log("nodeType: "+ doc.nodeType);
console.log("typeObject: "+ new Object().toString.call(div));
console.log("click: "+ div.click);

Код:

document
nodeType: 9
typeObject: [object HTMLDocument]
click: undefined
---
head
nodeType: 1
typeObject: [object HTMLHeadElement]
click: function click() {
    [native code]
}
---
body
nodeType: 9
typeObject: [object HTMLBodyElement]
click: function click() {
    [native code]
}
---
div
nodeType: 9
typeObject: [object HTMLDivElement]
click: function click() {
    [native code]
}


Hapson 24.03.2014 21:35

if(typeof element.nodeType === "undefined" || element.nodeType !== 1 || /^(HTML|HEAD|BODY)$/i.test(element.nodeName)){}

Больше ниче в голову не приходит

nerv_ 24.03.2014 23:02

Я делал так, но тесты оставляют желать лучшего.

Кроме того, если ты проверяешь на DOM элемент, вероятно, тебе следует пересмотреть функцию/архитектуру.

Hapson 24.03.2014 23:24

Цитата:

Сообщение от nerv_
Кроме того, если ты проверяешь на DOM элемент, вероятно, тебе следует пересмотреть функцию/архитектуру

Почему?
Функция принимает DOM элемент, по которому кликнул пользователь. Сразу же отменяет действие возвращая false. Проверяет на сервере авторизацию пользователя и если все нормально, то эмулирует отмененное действие. Но перед тем как начать работать, функция должна удостовериться, что ей передали действительно DOM элемент, к которому применим click или submit. Ну и html, head и body отбрасываются

Hapson 24.03.2014 23:40

Цитата:

Сообщение от nerv_
Я делал так

Я таким макаром написал isArray и isObject
$G.isObject = function(test){
	if(test === null || test === undefined){return false;}
	return ({}.toString.call(test) == "[object Object]");
};

$G.isArray = function(test){
	if(test === null || test === undefined){return false;}
	return ({}.toString.call(test) == "[object Array]");
};

Sweet 25.03.2014 00:22

Проверять через Object.prototype.toString в IE не вариант. Например, в 9-м выдаёт "[object Object]", ибо никаких HTMLElement или HTMLDivElement там нет.

nerv_ 25.03.2014 01:59

Цитата:

Сообщение от Sweet
Например, в 9-м выдаёт "[object Object]"

в восьмом. Только что проверил. В девятом норм, кроме document

Тем не менее, соглашусь, что это не очень надежная проверка :)

Вероятно, можно проверить, например, так (IE9+):
function isElement(v) {
    if (typeof v !== 'object') return false;
    if (v === null) return false;
    var c = window.HTMLDocument || window.Document;
    return v instanceof c || v instanceof window.HTMLElement;
}

alert(isElement(document));
alert(isElement(document.documentElement));
alert(isElement(document.head));
alert(isElement(document.body));
alert(isElement(null));
alert(isElement({}));


upd: А вообще, как ты гуглил?

Sweet 25.03.2014 02:24

Цитата:

Сообщение от nerv_
В девятом норм, кроме document

Действительно, норм. Я без DOCTYPE проверял, в режиме совместимости.

Vlasenko Fedor 25.03.2014 02:50

Может проверять есть ли у элемента родитель (parentElement, parentNode) и от этого стартовать. Это так мысли вслух :)

Octane 25.03.2014 06:23

Цитата:

Сообщение от Hapson
функция должна удостовериться, что ей передали действительно DOM элемент, к которому применим click или submit

проверяй инстанс EventTarget
function isEventTarget(obj) {
	return Object(obj) === obj && obj instanceof EventTarget;
}
на этом бы и остановились, если бы не IE, даже в 11 нет EventTarget, поэтому перечислим конструкторы объектов, имеющих события
//IE8+
function isEventTarget(obj) {
	return Object(obj) === obj && [
		obj instanceof (window.EventTarget || function () {}),
		obj instanceof (window.HTMLElement || window.Element),
		obj instanceof HTMLDocument,
		obj instanceof Window,
		obj instanceof XMLHttpRequest
	].indexOf(true) != -1;
}
ну и по желанию можно дописать всякие Comment, Text и др., чтобы сравнять результаты во всех браузерах

Hapson 25.03.2014 18:36

Octane,
Чет я ниче не понял.
А если так
function isDomElement(el, type){
	return typeof el.nodeType !== "undefined" && el.nodeType === type;
}

Ведь click() есть у каждого DOM элемента. Ну а у формы есть submit

Hapson 25.03.2014 18:50

Или даже так
function isDomElement(el, type){
	return typeof type === "number" ? el.nodeType === type : typeof el.nodeType === "number";
}

Octane 25.03.2014 18:53

Я про то, что ты не свою задачу решаешь, тебе нужен объект с событиями, а ты проверяешь тип, проверяй возможность использовать события

Для твоей задачи вообще достаточно
function isEventTarget(obj) {
	return "addEventListener" in Object(obj);
}

Hapson 25.03.2014 18:58

Octane,
Нет мне не нужны события, мне нужно вот что:
function(elem){
    // проверяем, что elem - DOM элемент
    // ... что-то делаем
    // а теперь делаем
    elem.click();
    // или
    elem.submit();
}

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

Hapson 25.03.2014 19:15

Цитата:

Сообщение от Octane
function isEventTarget(obj) {
    return "addEventListener" in Object(obj);
}

Эта функция вернет true для любого объекта, на который можно вешать события.
Мне же нужен DOM элемент, по которому можно кликнуть мышкой. Сюда же входят и формы

Hapson 25.03.2014 19:27

Вот наглядный пример:
<a href="#" id="link">Link</a>

<script>
EventHandler.add(document.getElementById("link"), click, checkAction);

function checkAction(){
	// функция перехватывает действие пользователя
	// что-то делает...
	// может проверяет форму, если вместо <a> перехватила <form>
	// И теперь функция хочет проверить, не закончилась ли сессия пользователя
	// Она обращается к модулю из общей библиотеки
	// и передает ему элемент, с которого перехватила событие click или submit
	return issetSeance(this);
}

/******/

function issetSeance(elem){
	// упрощенно: если у переданного элемента нет метода click или submit
	// просто вернуть true и не отменять действие пользователя
	if(!elem.click || !elem.submit){return true;}
	// если указанные методы присутствуют, то запустить модуль проверки авторизации
	checkLogin(elem);
    return false;
}

function checkLogin(elem){
	// тут общаемся с сервером
	// в случае успеха делаем
	elem.click() // если не форма
	elem.submit() // если форма
}
</script>

Hapson 25.03.2014 19:34

И вот в функции issetSeance() мне нужно проверить, что передан DOM элемент, у которого есть метод click() или submit(), и что этот элемент не HTML, не BODY и не HEAD

Erolast 25.03.2014 19:51

Цитата:

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

Ну и, click ко всему применим.

Hapson 25.03.2014 20:17

Цитата:

Сообщение от Erolast
Один вопрос - зачем?

:( :help:
Ну я же привел пример. Я не знаю, как еще подробнее...
Функция, которая перехватывает действие пользователя должна вернуть true или false. Она вместо этого обращается к модулю проверки авторизации. И уже модуль должен вернуть true или false. Теперь:

1) модуль проверяет, что ему дали DOM объект и у этого объекта есть метод click() или submit(). Нахрена ему это - ниже
2) если модулю передали что-то не то, то он вернет true и просто не начнет работать.
3) если модулю передали DOM объект, у которого есть метод click() или submit(), то он возвращает false и начинает работать.
4) модуль делает запрос на сервер - авторизован ли пользователь
5) авторизован - имитируем действие пользователя, которое сами же и отменили. То есть кликаем программно по чем он там кликал

Hapson 25.03.2014 20:20

Нахрена я отменяю действие пользователя, а потом имитирую его программно?
Потому как я не знаю как поставить скрипт на паузу, пока выполняется асинхронный запрос(ы)

Hapson 25.03.2014 20:22

Цитата:

Сообщение от Erolast
Ну и, click ко всему применим.

Не ко всему, а к DOM элементам

Erolast 25.03.2014 20:26

Почему бы просто не выполнять никаких действий, пока от сервера не придет ответ?)

Цитата:

Не ко всему, а к DOM элементам
Ну разумеется я имел в виду "Ко всем DOM элементам".

Erolast 25.03.2014 20:33

Цитата:

Потому как я не знаю как поставить скрипт на паузу, пока выполняется асинхронный запрос(ы)
Никак. Зато можешь выполнять запрос синхронно.

http://learn.javascript.ru/ajax-xmlhttprequest#синхронный-вызов

Но лучше так не делать.

Hapson 25.03.2014 20:53

Цитата:

Сообщение от Erolast
Почему бы просто не выполнять никаких действий, пока от сервера не придет ответ?)

vs
Цитата:

Сообщение от Erolast
Но лучше так не делать.

PS потому что я не могу сказать скрипту: "СТОЯТЬ! Щас я с сервером перетру одно дело..."

Erolast 25.03.2014 21:25

Цитата:

PS потому что я не могу сказать скрипту: "СТОЯТЬ! Щас я с сервером перетру одно дело..."
Можешь.
Цитата:

Сообщение от Erolast (Сообщение 304239)
Никак. Зато можешь выполнять запрос синхронно.

http://learn.javascript.ru/ajax-xmlhttprequest#синхронный-вызов

Цитата:

Сообщение от Erolast (Сообщение 304239)
Но лучше так не делать.

Я не пойму, почему ты просто не повесишь на запрос колбэк, который для авторизованых делает то, что нужно, а неавторизованным говорит "Извините, вы не авторизованы."?

Sweet 25.03.2014 21:34

Hapson, а не пофиг ли, Dom-объект - не Dom? Тебе нужно вызвать метод, вот и проверяй его наличие:
if (isFunction(elem.click)) elem.click();

nerv_ 25.03.2014 21:53

Цитата:

Сообщение от Sweet
а не пофиг ли, Dom-объект - не Dom? Тебе нужно вызвать метод, вот и проверяй его наличие:

Цитата:

Сообщение от nerv_
Кроме того, если ты проверяешь на DOM элемент, вероятно, тебе следует пересмотреть функцию/архитектуру.

Я использовал эту функцию только в тестах и современных браузерах :) а он собрался кликать за пользователя и сабмитить :D

Если копнуть еще глубже, то ему не надо вызывать методы клик и сабмит у дум нод, т.к. это та же самая "ошибка в архитектуре" :)

Цитата:

Сообщение от Hapson
PS потому что я не могу сказать скрипту: "СТОЯТЬ! Щас я с сервером перетру одно дело..."

читай про ООП, изучай код опытных разработчиков... или продолжай топтаться на месте)

Erolast 25.03.2014 22:05

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

Hapson 25.03.2014 22:23

Цитата:

Сообщение от Erolast
Я не пойму, почему ты просто не повесишь на запрос колбэк, который для авторизованых делает то, что нужно, а неавторизованным говорит "Извините, вы не авторизованы."?

Есть приложение - движок сайта. Есть в нем модуль управления статьями. Есть в нем функционал добавления статьи.
Пользователь пишет статью, в процессе его сеанс заканчивается и он становится неавторизованным юзером. Но он узнает об этом лишь когда его выкинет на страницу авторизации при попытке сохранить статью. Я написал на php функционал хранения данных, которые пользователь вводил, так что катастрофы не будет, если юзер там поэму настрочил - все восстановится. Но вот захотел я сделать так, чтобы авторизация проверялась перед отправкой формы и чтобы подтвердить авторизацию юзер мог тутже - без перебросов на другие страницы.

Ну общие черты понятны думаю... едем дальше.
У движка сайта есть общая javascript библиотека со всякими функциями и даже модулями. В свою очередь, у каждого модуля сайта (в данном случае у модуля управления статьями) тоже есть свой набор скриптов javascript.
У модуля управления статьями есть скриптик, который перехватывает форму добавления статьи и поверхностно ее проверяет перед отправкой на сервер. И тут я решил, что хорошо бы было, если бы перед отправкой формы была бы еще и проверка авторизации.
Я начал писать эту проверку в составе скрипта модуля статей. Но тут я подумал... а ведь потом я буду писать модуль управления комментариями, и там тоже не помешала бы фишка проверки авторизации перед отправкой комментария.
Че делать? Потом писать аналогичную проверку в модуле комментариев? Нет наверно, нахрена одно и тоже переписывать.
Поэтому я решил написать модуль проверки авторизации, который смогут использовать все - любой модуль сайта. Естественно этот модуль вошел в состав общей javascript библиотеки. У модуля есть два открытых метода isLogin() и isLogin.setup(). Один конфигурирует модуль, второй используется a функции перехвата действия пользователя.
То есть скрипт перехватил форму, проверил ее и он делает
return isLogin();
И все. Теперь модуль проверки авторизации решает, что вернуть - true или false. Так как модуль будет делать асинхронные ajax запросы, то он должен сразу что-то вернуть. В данном случае он отменяет действие пользователя и проверяет авторизацию. Не отменить я не могу, так как никто ждать не будет, пока вернется ответ сервера. Поэтому, в модуль авторизации передается объект, по которому кликнул пользователь. Если с объектом все ОК, то модуль просто возвращает false и начинает делать свою работу.
nerv_
Что не так с архитектурой? Есть другие способы? Синхронные запросы не предлагать.

Hapson 25.03.2014 22:28

Цитата:

Сообщение от Erolast
Если в гугле нет описания проблемы, возникшей в процессе решения стандартной задачи - скорее всего, решение неверное.

Описание моей проблемы: Ajax проверка авторизации перед... ну скажем, отправкой формы.
Ну вот нет такого описания. А вся проблема сводится к другой проблеме: Как остановить скрипт на время выполнения ajax запроса. Ответа два: НИКАК или синхронный запрос. Ни то, ни другое не подходит.
Но вот многие пишут, что при таком раскладе просто отменяют действие юзера, а потом если все ОК эмулируют его программно (click, submit). И это единственное подходящее решение.

Hapson 25.03.2014 22:30

Цитата:

Сообщение от nerv_
Я использовал эту функцию только в тестах и современных браузерах а он собрался кликать за пользователя и сабмитить

Какую функцию? Что не так в программных кликах и сабмитах?

Erolast 25.03.2014 22:46

Цитата:

Есть приложение - движок сайта. Есть в нем модуль управления статьями. Есть в нем функционал добавления статьи.
Пользователь пишет статью, в процессе его сеанс заканчивается и он становится неавторизованным юзером. Но он узнает об этом лишь когда его выкинет на страницу авторизации при попытке сохранить статью. Я написал на php функционал хранения данных, которые пользователь вводил, так что катастрофы не будет, если юзер там поэму настрочил - все восстановится. Но вот захотел я сделать так, чтобы авторизация проверялась перед отправкой формы и чтобы подтвердить авторизацию юзер мог тутже - без перебросов на другие страницы.
Ну так и сделай функцию, которая запускает один колбек в случае, если пользователь авторизован, и другой - если пользователь не авторизован.

Но слишком обобщать - тоже не хорошо. При чрезмерном повышении уровня теряется гибкость.

Hapson 25.03.2014 22:56

Цитата:

Сообщение от Erolast
Ну так и напиши функцию, которая запускает один колбек в случае, если пользователь авторизован, и другой - если пользователь не авторизован.

Хорошо, упростим задачу. Я хоть убей не могу понять...
Вот функция которая перехватила форму
function checkForm(){
	// проверяет форму...
	// нет у нас никаких модулей проверки авторизации, тупо делаем все тут
	// нужно сделать ajax запрос...
	// запрос асинхронный - никто никого не ждет...
	// все нужно что-то вернуть - true или false... что вернуть!?
	// если вернуть true - форма уйдет и все проверки авторизации идет лесом
	// если false - то нужно потом при удачной проверке или удачном подтверждении (а это еще запросы) сделать submit этой чертовой формы
}

Hapson 25.03.2014 23:15

Смысл в том, что я перехватил клик юзера и нужно что-то решать. Но я не могу ничего решить пока не получу ответ сервера.

Erolast 25.03.2014 23:19

Ну так делай/не делай субмит программно по приходу ответа от сервера, когда уже будешь знать, авторизован ли пользователь.

Erolast 25.03.2014 23:26

<script>
function send_data()
{
  //Хорошей идеей было бы оповестить пользователя, что идет проверка авторизации.
  //Делаем запрос на сервер, вешаем колбек с соответствующими проверками - если пользователь авторизован, делаем document.getElementById("myform").submit(), не авторизован - выдаем ошибку, открываем окно авторизации.
}
</script>

<form id="myform" action="data_reciever.php">
<textarea></textarea>
<button onclick="send_data()">Отправить</button>
</form>

Hapson 25.03.2014 23:34

Цитата:

Сообщение от Erolast
Ну так делай/не делай субмит программно по приходу ответа от сервера, когда уже будешь знать, авторизован ли пользователь.

Ну так я так и делаю! :)
Но только товарищ nerv_ считает это корявой акхитектурой.
Единственным условием для успешного запуска модуля проверки авторизации, является передача ему ссылки на объект, по которому кликнул юзер, будь то кнопка, ссылка, форма... неважно. Главное чтоб это был объект, у которого есть click() или submit();
Так сделано, потому что модуль как бы общий, и использовать его может любой модуль сайта.

Ладно, проблема-то решена уже давно

Hapson 25.03.2014 23:35

Erolast,
Да... если задержка более 500мс, то юзер увидит анимацию и оповещение, что скрипт чего-то там делает... надо обождать. Это тоже все уже есть

Erolast 25.03.2014 23:43

Цитата:

Ну так я так и делаю!
Судя по твоим сообщениям, ты пытаешься отменять стандартный браузеровский субмит. А этого сделать в твоем случае невозможно, потому-что на момент, когда отменить можно, необходимых данных нету, а потом уже поздно. Поэтому надо вызывать функцию по обычной кнопке, а не по <input type="submit">, функцией отправлять запрос к серверу, вещать на запрос колбек, и только там, если пользователь авторизован, искусственно вызывать субмит формы.
И не надо никуда никаких элементов передавать.

Hapson 25.03.2014 23:54

Цитата:

Сообщение от Erolast
Судя по твоем сообщения, ты пытаешься отменять стандартный браузеровский субмит. А этого сделать в твоем случае невозможно, потому-что на момент, когда отменить можно, необходимых данных нету, а потом уже поздно. Поэтому надо вызывать функцию по обычной кнопке, а не по <input type="submit">, функцией отправлять запрос к серверу, вещать на запрос колбек, и только там, если пользователь авторизован, искусственно вызывать субмит формы.

Почему невозможно, и зачем какой-то левый инпут?
http://javascript.ru/forum/events/46...tml#post304218
Цитата:

Сообщение от Erolast
А этого сделать в твоем случае невозможно, потому-что на момент, когда отменить можно, необходимых данных нету, а потом уже поздно

Это и решает модуль проверки авторизации.
Если ему передали DOM объект на котором произошел click, то он отменить действие и приступит к работе.
В случае успешной проверки на сервере или при любых ошибках в работе, он программно совершит отмененное действие.
Если юзер потерял авторизацию, то будет выведена форма авторизации.
Если юзер верно введет все, то получить сообщение, типа все ОК пуляй форму.
Если N-ное кол-во раз он неверно укажет логин/пароль, то скрипт отключится и перестанет перехватывать данные с формы авторизации. Ну и юзер уже физически отправится по action, указанный в форме авторизации, а там уже сервер ему что-то скажет


Часовой пояс GMT +3, время: 06:18.