В консоли:
тот же параграф внутри функции:
Пояснения: этот параграф находится внутри iframe
, помещается он туда путем innerHTML
из textarea
. Тот же код но при обычной разметке отрабатывает нормально, т.е. instanceof
возвращает true, хотя этот же параграф вставленный из текстового поля на первом скрине.... мистика...
Исходя из второго скриншота видно, что в массиве лежит один элемент, его конструктор HTMLParagraphElement
, значит он наследовался от HTMLElement
, тот в свою очередь от Element
и Node
. Но проверка на instanceof
возвращает false
, почему так происходит?
Полностью воспроизвести код здесь не удается, поэтому привожу отдельно листинг js файла.
(function () {
/**
* Конструктор объекта консоли ифрэйма
*
* @param {any} doc
* @returns объект консоли
*/
function FrameConsole(doc) {
var console = Object.assign({}, window.console);
var consoleStyle = doc.createElement('style');
consoleStyle.textContent = ''; // вставить стили для консоли
doc.head.appendChild(consoleStyle);
/**
* @param {any} e new Date
* @returns возвращает дату в виде строки "часы:минуты:секунды.миллисекунды"
*/
function getDate(date) {
date = new Date(date.valueOf() - 6e4 * date.getTimezoneOffset());
var dateString = date.toISOString().replace("Z", "");
return dateString.substring(dateString.indexOf("T") + 1);
}
/**
* Преобразует входящие данные к строке
*
* @param {any} data - входящие данные
* @returns итоговый результат
*/
// добавить вывод тегов
function stringConvert(data) {
var b = data[0].constructor;
var c = data[0] instanceof HTMLElement; //!!!! здесь хром возвращает false, не пробовал оперу и ИЕ, в мозиле работает.
data.forEach(function(item, i, arr){
if(item instanceof HTMLElement) {
alert(true );
} else {
alert(false);
}
switch (Object.prototype.toString.call(item)) {
case "[object Array]":
case "[object Object]":
arr[i] = JSON.stringify(item);
break;
default:
break;
}
});
return data;
}
/**
* генерирует строки в консоле
*
* @param {any} data arguments метода console
*/
function genericRow(data) {
var eventContainer = doc.body.querySelector('.console');
var eventDate = doc.createElement('span');
var eventData = doc.createElement('p');
var eventCode = doc.createElement('code');
eventDate.className = 'console_date';
eventData.className = 'console_text';
eventCode.className = 'console_code';
eventCode.textContent = stringConvert(data);
eventDate.textContent = getDate(new Date());
eventData.appendChild(eventCode);
eventData.appendChild(eventDate);
eventContainer.appendChild(eventData);
}
console.log = function () {
var data = Array.prototype.slice.apply(arguments);
genericRow(data);
window.console.log.apply(null, arguments);
}
return console;
}
document.addEventListener('DOMContentLoaded', function () {
var engine = new CodeEngine();
engine.init();
engine.DOM.frame.contentWindow.console = new FrameConsole(engine.DOM.frame.contentWindow.document);
var button = document.getElementById('run');
button.addEventListener('click', function () {
engine.execute();
});
});
})();
Интересный вопрос, в общем суть в том, что HTMLElement в текущем scope действительно, не тот же самый инстасом которого, является параграф, просто можете проверить, начиная в вашем console.log враппере
data[0].__ptoto__ === HTMLParagraphElement //false
чтобы "исправить", нужно прокинуть ещё и window в ваш "конструктор" консоли, примерно так получилось (смотрите по коду коменты // ТУТ)
(function () {
/**
* текстовые поля
*
* @param {any} CSSClass
*/
function Field(CSSClass) {
this.elem = document.querySelector(CSSClass);
}
Field.prototype.write = function() {
}
/**
* кнопки
*
* @param {any} CSSClass
*/
function button(CSSClass) {
this.elem = document.querySelector(CSSClass);
}
/**
* Класс обработчика и загрузчика кода в iframe и ткстовые поля докуметта
* Содержит ключи (объекты) со ссылками на DOM узлы основного документа и iframe
*
*/
function CodeEngine() {
this.DOM = {
//cssText: document.querySelector('head style'),
htmlText: document.querySelector('.html-container'),
codeText: document.querySelector('body script'),
frame: document.querySelector('.code_result iframe'),
html: document.querySelector('.code_html textarea'),
css: document.querySelector('.code_css textarea'),
js: document.querySelector('.code_js textarea'),
}
}
/**
*
*
*/
CodeEngine.prototype.init = function () {
/**
* Adds the necessary DOM elements to the iframe
*
* @returns Item object in a iframe
*/
function renderFrame() {
var frame = this.DOM.frame.contentWindow.document;
var docStyle = frame.createElement('style');
var docHTML = frame.createElement('div');
docHTML.setAttribute('id', 'contentHTML');
var docScript = frame.createElement('script');
return {style: docStyle, html: docHTML, script: docScript}
}
/**
* Adds to the initial data in textarea
*
*/
function renderFields() {
this.DOM.js.value = this.DOM.codeText.innerHTML;
this.DOM.html.value = this.DOM.htmlText.innerHTML;
//this.DOM.css.value = this.DOM.cssText.textContent;
}
/**
* Running code in the iframe
*
*/
function execute() {
var frame = this.DOM.frame.contentWindow.document;
frame.body.innerHTML = '';
this.frameDOM.style.textContent = this.DOM.css.value;
this.frameDOM.html.innerHTML = this.DOM.html.value;
//this.frameDOM.script.textContent = this.DOM.js.value;
frame.head.appendChild(this.frameDOM.style);
frame.body.appendChild(this.frameDOM.html);
var eventContainer = frame.createElement('div');
eventContainer.className = 'console';
frame.body.appendChild(eventContainer);
frame.body.appendChild(this.frameDOM.script);
var newScript = frame.createElement('script');
newScript.textContent = this.DOM.js.value;
frame.body.replaceChild(newScript, this.frameDOM.script);
this.frameDOM.script = newScript;
}
renderFields.call(this);
this.frameDOM = this.frameDOM ? this.frameDOM : renderFrame.call(this);
this.execute = execute.bind(this);
this.execute();
}
/**
* Конструктор объекта консоли ифрэйма
*
* @param {any} doc
* @returns объект консоли
*/
function FrameConsole(doc, win) { //ТУТ
var win = win;
var console = Object.assign({}, window.console);
var consoleStyle = doc.createElement('style');
consoleStyle.textContent = ''; // вставить стили для консоли
doc.head.appendChild(consoleStyle);
/**
* @param {any} e new Date
* @returns возвращает дату в виде строки "часы:минуты:секунды.миллисекунды"
*/
function getDate(date) {
date = new Date(date.valueOf() - 6e4 * date.getTimezoneOffset());
var dateString = date.toISOString().replace("Z", "");
return dateString.substring(dateString.indexOf("T") + 1);
}
/**
* Преобразует входящие данные к строке
*
* @param {any} data - входящие данные
* @returns итоговый результат
*/
// добавить вывод тегов
function stringConvert(data) {
var b = data[0].constructor;
var c = data[0] instanceof HTMLElement; //!!!!!!!! FALSE
data.forEach(function(item, i, arr){
//ТУТ
if(item instanceof win.HTMLElement) { // true !!! :) //ТУТ
alert(true );
} else {
alert(false);
}
switch (Object.prototype.toString.call(item)) {
case "[object Array]":
case "[object Object]":
arr[i] = JSON.stringify(item);
break;
default:
break;
}
});
return data;
}
/**
* генерирует строки в консоле
*
* @param {any} data arguments метода console
*/
function genericRow(data) {
var eventContainer = doc.body.querySelector('.console');
var eventDate = doc.createElement('span');
var eventData = doc.createElement('p');
var eventCode = doc.createElement('code');
eventDate.className = 'console_date';
eventData.className = 'console_text';
eventCode.className = 'console_code';
eventCode.textContent = stringConvert(data);
eventDate.textContent = getDate(new Date());
eventData.appendChild(eventCode);
eventData.appendChild(eventDate);
eventContainer.appendChild(eventData);
}
console.log = function () {
var data = Array.prototype.slice.apply(arguments);
// ТУТ
console.debug(data[0], data[0] instanceof HTMLElement, data[0] instanceof win.HTMLElement); // эта строчка поясняет ситуацию
genericRow(data);
window.console.log.apply(null, arguments);
}
return console;
}
document.addEventListener('DOMContentLoaded', function () {
var engine = new CodeEngine();
engine.init();
engine.DOM.frame.contentWindow.console = new FrameConsole(engine.DOM.frame.contentWindow.document, engine.DOM.frame.contentWindow); //ТУТ
var button = document.getElementById('run');
button.addEventListener('click', function () {
engine.execute();
});
});
})();
https://plnkr.co/edit/W3zqz8oLJxscbTIwgvNn?p=preview
вкратце это выглядит так:
html<iframe id="test"></iframe>
js
var frameWindow = document.getElementById('test').contentWindow;
var frameDocument = frameWindow.document;
frameDocument.body.innerHTML='<p>test</p>';
var p = frameDocument.querySelector('p');
console.log(p instanceof HTMLElement, p instanceof frameWindow.HTMLElement); // false, true
https://plnkr.co/edit/b21nNfj3R92lqYW9Zxkb?p=preview
в firefox это баг, т.к.
var frameWindow = document.getElementById('test').contentWindow;
var frameDocument = frameWindow.document;
frameDocument.body.innerHTML='<p>test</p>';
var p = frameDocument.querySelector('p');
HTMLElement.prototype.myTest = () => 'hello world';
try {
console.log(p instanceof HTMLElement, p instanceof frameWindow.HTMLElement); // true, true
console.log('LOL', document.getElementById('test') instanceof frameWindow.HTMLElement); // true
console.log(document.getElementById('test').myTest()); // 'hello world'
console.log(p.myTest()); // exception
} catch(e) {
console.error(e); // myTest() is undefined...
}
ps: чтобы так не мучаться - передавайте эти данные сообщениями, библиотечку положите непосредственно во фрейм исполнения, тогда можно даже в sandboxed iframe делать (iframe src=dataURL)
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Перевод документов на английский язык: Важность и ключевые аспекты
Here is the code and i want for example to access the latitudw variable outside of this function and for example set to its value
вот пен codepenio/cache0/pen/JWMNge
Как динамически изменить min и max в jquery ui ползунке? Мне нужно будет перерисовать элемент