- Общение между окнами
- Политика «Одинакового источника»
- Доступ к содержимому ифрейма
- Окна на поддоменах: document.domain
- Ифрейм: подождите документ
- Коллекция window.frames
- Атрибут ифрейма sandbox
- Обмен сообщениями между окнами
- postMessage
- Событие message
- JavaScript — Объект window: фреймы
- Что такое фреймы
- Свойства объекта window для работы с фреймами
- Свойство frameElement
- Свойство length
- Свойство frames
- Свойство parent
- Свойство top
- Свойство self
- Пример работы с фреймами
- JavaScript. Глава 3. Фреймы
- Создание и использование фреймов
- Фреймы и JavaScript
- Меню навигации
Общение между окнами
Политика «Одинакового источника» (Same Origin) ограничивает доступ окон и фреймов друг к другу.
Идея заключается в том, что если у пользователя открыто две страницы: john-smith.com и gmail.com , то у скрипта со страницы john-smith.com не будет возможности прочитать письма из gmail.com . Таким образом, задача политики «Одинакового источника» – защитить данные пользователя от возможной кражи.
Политика «Одинакового источника»
Два URL имеют «одинаковый источник» в том случае, если они имеют совпадающие протокол, домен и порт.
Эти URL имеют одинаковый источник:
А эти – разные источники:
- http://www.site.com (другой домен: www. важен)
- http://site.org (другой домен: .org важен)
- https://site.com (другой протокол: https )
- http://site.com:8080 (другой порт: 8080 )
Политика «Одинакового источника» говорит, что:
- если у нас есть ссылка на другой объект window , например, на всплывающее окно, созданное с помощью window.open или на window из и у этого окна тот же источник, то к нему будет полный доступ.
- в противном случае, если у него другой источник, мы не сможем обращаться к его переменным, объекту document и так далее. Единственное исключение – объект location : его можно изменять (таким образом перенаправляя пользователя). Но нельзя читать location (нельзя узнать, где находится пользователь, чтобы не было никаких утечек информации).
Доступ к содержимому ифрейма
Внутри находится по сути отдельное окно с собственными объектами document и window .
Мы можем обращаться к ним, используя свойства:
- iframe.contentWindow ссылка на объект window внутри .
- iframe.contentDocument – ссылка на объект document внутри , короткая запись для iframe.contentWindow.document .
Когда мы обращаемся к встроенному в ифрейм окну, браузер проверяет, имеет ли ифрейм тот же источник. Если это не так, тогда доступ будет запрещён (разрешена лишь запись в location , это исключение).
Для примера давайте попробуем чтение и запись в ифрейм с другим источником:
Код выше выведет ошибку для любых операций, кроме:
- Получения ссылки на внутренний объект window из iframe.contentWindow
- Изменения location .
С другой стороны, если у ифрейма тот же источник, то с ним можно делать всё, что угодно:
Событие iframe.onload – по сути то же, что и iframe.contentWindow.onload . Оно сработает, когда встроенное окно полностью загрузится со всеми ресурсами.
…Но iframe.onload всегда доступно извне ифрейма, в то время как доступ к iframe.contentWindow.onload разрешён только из окна с тем же источником.
Окна на поддоменах: document.domain
По определению, если у двух URL разный домен, то у них разный источник.
Но если в окнах открыты страницы с поддоменов одного домена 2-го уровня, например john.site.com , peter.site.com и site.com (так что их общий домен site.com ), то можно заставить браузер игнорировать это отличие. Так что браузер сможет считать их пришедшими с одного источника при проверке возможности доступа друг к другу.
Для этого в каждом таком окне нужно запустить:
После этого они смогут взаимодействовать без ограничений. Ещё раз заметим, что это доступно только для страниц с одинаковым доменом второго уровня.
Ифрейм: подождите документ
Когда ифрейм – с того же источника, мы имеем доступ к документу в нём. Но есть подвох. Не связанный с кросс-доменными особенностями, но достаточно важный, чтобы о нём знать.
Когда ифрейм создан, в нём сразу есть документ. Но этот документ – другой, не тот, который в него будет загружен!
Так что если мы тут же сделаем что-то с этим документом, то наши изменения, скорее всего, пропадут.
Нам не следует работать с документом ещё не загруженного ифрейма, так как это не тот документ. Если мы поставим на него обработчики событий – они будут проигнорированы.
Как поймать момент, когда появится правильный документ?
Можно проверять через setInterval :
Коллекция window.frames
Другой способ получить объект window из – забрать его из именованной коллекции window.frames :
- По номеру: window.frames[0] – объект window для первого фрейма в документе.
- По имени: window.frames.iframeName – объект window для фрейма со свойством name=»iframeName» .
Ифрейм может иметь другие ифреймы внутри. Таким образом, объекты window создают иерархию.
Навигация по ним выглядит так:
- window.frames – коллекция «дочерних» window (для вложенных фреймов).
- window.parent – ссылка на «родительский» (внешний) window .
- window.top – ссылка на самого верхнего родителя.
Можно использовать свойство top , чтобы проверять, открыт ли текущий документ внутри ифрейма или нет:
Атрибут ифрейма sandbox
Атрибут sandbox позволяет наложить ограничения на действия внутри , чтобы предотвратить выполнение ненадёжного кода. Атрибут помещает ифрейм в «песочницу», отмечая его как имеющий другой источник и/или накладывая на него дополнительные ограничения.
Существует список «по умолчанию» ограничений, которые накладываются на . Их можно уменьшить, если указать в атрибуте список исключений (специальными ключевыми словами), которые не нужно применять, например: .
Другими словами, если у атрибута «sandbox» нет значения, то браузер применяет максимум ограничений, но через пробел можно указать те из них, которые мы не хотим применять.
Вот список ограничений:
allow-same-origin «sandbox» принудительно устанавливает «другой источник» для ифрейма. Другими словами, он заставляет браузер воспринимать iframe , как пришедший из другого источника, даже если src содержит тот же сайт. Со всеми сопутствующими ограничениями для скриптов. Эта опция отключает это ограничение. allow-top-navigation Позволяет ифрейму менять parent.location . allow-forms Позволяет отправлять формы из ифрейма. allow-scripts Позволяет запускать скрипты из ифрейма. allow-popups Позволяет открывать всплывающие окна из ифрейма с помощью window.open .
Больше опций можно найти в справочнике.
Пример ниже демонстрирует ифрейм, помещённый в песочницу со стандартным набором ограничений: . На странице содержится JavaScript и форма.
Обратите внимание, что ничего не работает. Таким образом, набор ограничений по умолчанию очень строгий:
Атрибут «sandbox» создан только для того, чтобы добавлять ограничения. Он не может удалять их. В частности, он не может ослабить ограничения, накладываемые браузером на ифрейм, приходящий с другого источника.
Обмен сообщениями между окнами
Интерфейс postMessage позволяет окнам общаться между собой независимо от их происхождения.
Это способ обойти политику «Одинакового источника». Он позволяет обмениваться информацией, скажем john-smith.com и gmail.com , но только в том случае, если оба сайта согласны и вызывают соответствующие JavaScript-функции. Это делает общение безопасным для пользователя.
Интерфейс имеет две части.
postMessage
Окно, которое хочет отправить сообщение, должно вызвать метод postMessage окна получателя. Другими словами, если мы хотим отправить сообщение в окно win , тогда нам следует вызвать win.postMessage(data, targetOrigin) .
data Данные для отправки. Может быть любым объектом, данные клонируются с использованием «алгоритма структурированного клонирования». IE поддерживает только строки, поэтому мы должны использовать метод JSON.stringify на сложных объектах, чтобы поддержать этот браузер. targetOrigin Определяет источник для окна-получателя, только окно с данного источника имеет право получить сообщение.
Указание targetOrigin является мерой безопасности. Как мы помним, если окно (получатель) происходит из другого источника, мы из окна-отправителя не можем прочитать его location . Таким образом, мы не можем быть уверены, какой сайт открыт в заданном окне прямо сейчас: пользователь мог перейти куда-то, окно-отправитель не может это знать.
Если указать targetOrigin , то мы можем быть уверены, что окно получит данные только в том случае, если в нём правильный сайт. Особенно это важно, если данные конфиденциальные.
Например, здесь win получит сообщения только в том случае, если в нём открыт документ из источника http://example.com :
Если мы не хотим проверять, то в targetOrigin можно указать * .
Событие message
Чтобы получать сообщения, окно-получатель должно иметь обработчик события message (сообщение). Оно срабатывает, когда был вызван метод postMessage (и проверка targetOrigin пройдена успешно).
JavaScript — Объект window: фреймы
На этом уроке мы познакомимся со свойствами объекта window , которые предназначены для работы с фреймами ( iframe ).
Что такое фреймы
Фреймы — это элементы HTML, которые используются для внедрения в текущую страницу других веб-страниц. Фреймы в HTML5 представлены с помощью элемента iframe ( ). Для указания URL, который будет отображаться внутри фрейма ( iframe ) используется атрибут src .
Например, внутри фрейма отобразим страницу «http://getbootstrap.com/».
Фреймы немного похожи с картинками, только вместо картинки отображается внешний ресурс (HTML страница). Размещать фреймы ( iframe ) можно в любом месте страницы. Они относятся к строчным элементам. Кроме атрибута src у тега iframe есть множество других атрибутов: width (ширина), height (высота), name (имя) и др.
Например, создадим веб-страницу, содержащую ссылку и фрейм с именем. При нажатии на ссылку будем открывать в этом фрейме указанную веб-страницу.
С точки зрения объектной модели браузера фреймы ( iframe ) — это тоже окна (объекты window ), которые можно расположить в основном окне (вкладке) браузера или в другом фрейме.
Свойства объекта window для работы с фреймами
Для работы с фреймами объект window содержит следующие свойства: frameElement , frames , length , self , parent и top . Разберём назначение этих свойств на примере.
Рассмотрим окно, состоящее из 5 фреймов ( . ). Первые три фрейма (1,2 и 3) расположены непосредственно в этом окне, а остальные 2 фрейма (4 и 5) расположены во фрейме 2.
- свойство parent , возвращает родительское окно (объект window ), т.е. фрейм 2.
- свойство top , возвращает прародителя (предка), т.е. основное окно (вкладку), куда загружены все фреймы.
- свойство self , возвращает текущий объект window , т.е. фрейм 4.
- свойство parent , возвращает родительское окно (объект window ), т.е. основное окно (вкладку).
- свойство top , возвращает прародителя (предка), т.е. основное окно (вкладку), куда загружены все фреймы.
- свойство self , возвращает текущий объект window , т.е. фрейм 2.
Свойство frameElement возвращает сам элемент iframe , или null если он таковым не является (например, если он является обычным окном, а не фреймом).
Свойство length обычно используется совместно со свойством frames и возвращает количество фреймов, содержащихся в текущем окне или фрейме. Например, в нашем примере свойство length для окна 2, вернёт значение 2. А для основного окна, свойство length вернёт значение 3. Свойство frames возвращает массив объектов window , каждый из которых отвечает за вложенный в это окно фрейм ( iframe ). Фреймы с логической точки зрения тоже являются окошечками, т.е. для каждого фрейма создаётся свой собственный объект window .
Вернёмся к нашему примеру, в котором основное окно (вкладка) браузера содержит 3 фрейма. В этом месте возникает вопрос: «А сколько всего объектов window будет создано?». В нашем случае будет создано 4 объекта window . Первый объект window будет отвечать за основное окно (вкладку) браузера. Три остальных объекта window будут отвечать за каждый из фреймов, непосредственно расположенных в этом окне. Эти объекты window, т.е. те которые отвечают за каждый фрейм, образуют массив frames , который можно получить как свойство объекта window .
Свойство frameElement
Свойство frameElement возвращает элемент iframe , если текущее окно является фреймом. В противном случае данное свойство, возвращает значение null (т.е. данное окно не является фреймом).
Например, узнать является ли текущее окно фреймом ( iframe ) и если является, то изменить его URL на «http://getbootstrap.com/»:
Свойство length
Свойство length возвращает количество фреймов ( iframe ) в текущем окне. Это свойство очень часто используется совместно со свойством frames . Свойство length доступно только дли чтения.
Например, получить количество фреймов ( iframe ) в текущем окне:
Свойство frames
Свойство frames возвращает массив фреймов (объектов window ), расположенных а текущем окне. Доступ к фрейму (объекту window ) осуществляется по индексу (отсчёт индексов начинаются с 0). Для определения количества фреймов в текущем окне или фрейме используйте свойство length .
Например, изменить URL первого фрейма (т.е. фрейма с индексом 0), который расположен а текущем окне:
Например, изменить URL всех фреймов расположенных в текущем окне на «http://getbootstrap.com/»:
Свойство parent
Свойство parent возвращает родительский объект window no отношению к текущему объекту window . Данное свойство доступно только для чтения.
Например, установить задний фон родительскому объекту window :
Свойство top
Свойство top возвращает основное окно (вкладку).
Например, определим, является ли данное окно основным окном:
Свойство self
Свойство self возвращает текущее окно. Данное свойство обычно используется в операциях сравнения и доступно только для чтения.
Пример работы с фреймами
Рассмотрим наиболее сложный пример, в мотором продемонстрируем использование всех свойств объекта window для работы с фреймами:
JavaScript. Глава 3. Фреймы
Фреймы — это английское слово, в переводе означающее рамки. HTML-cтраница, в которой используются фреймы, выглядит разделенной на несколько частей, которые окаймлены границами как рамками. Мы не будем переводить слово «фрейм», более того, даже будем использовать его русифицированную форму множественного числа. Все это оправдывается тем фактом, что все-таки фреймы — это не совсем то, что обозначает русское слово рамки, к тому же в программировании фреймов мы будем вынуждены пользоваться английскими словами, а в ?родном| написании слово фреймы выглядит как frames.
Создание и использование фреймов
Часто возникает вопрос о том, как могут быть связаны друг с другом, казалось бы, совершенно разные вещи, такие, как фреймы и язык JavaScript. Не будем спешить, и остановимся вначале на рассказе о том, что представляют собой фреймы и для чего они используются. После этого рассмотрим вопрос о том, как могут быть взаимосвязаны фреймы и язык JavaScript.
Окно броузера может быть разделено на несколько фреймов. Фрейм представляет собой прямоугольную область экрана, расположенную в окне броузера. Каждый фрейм показывает свой документ, как правило это обычный HTML-документ. Например, можно создать два окна и в одно из них загрузить домашнюю страничку компании Netscape, а в другое v домашнюю страничку компании Microsoft.
Несмотря на то что создание фреймов осуществляется в рамках языка HTML, напомним основные принципы и способы создания фреймов. Для того чтобы создать фреймы, мы пользуемся двумя ярлыками, а именно ярлыком и ярлыком . Страница, разбитая на два фрейма, может быть описана при помощи HTML следующим образом:
Этот код порождает два фрейма. В ярлыке указано свойство rows, rows v это в ряды. Это свойство указывает на то, что два фрейма расположены рядами, друг над другом. Верхний фрейм загружается страницей page1.htm, а нижний фрейм загружается страницей page2.htm. Нажмите кнопку строкой ниже, и вы увидите, как будут выглядеть эти фреймы.
Если вы захотите расположить фреймы сто-лбцами, то вместо свойства rows в ярлыке укажите cols. If you want to have columns instead of rows you write cols instead of rows in the tag. Процентные величины ?50%, 50%| указывают относительные размеры окон фреймов. Если вы не хотите утруждать себя вычислениями того, каким должен быть размер второго окна, чтобы в целом получилось 100%, то можно указать размер окна в пикселях, при этом знак % опускается.
Каждый фрейм имеет свое уникальное имя, которое задается при помощи свойства name в ярлыке . При помощи этого имени фрейм легко доступен при описаниях на JavaScript.
Можно использовать несколько последовательных описаний фреймов при помощи ярлыков , при этом фреймы могут быть расположены друг в друге. Вот пример такого расположения фреймов:
Посмотрите, как выглядят такие фреймы:
Существует возможность установить толщину рамки фрейма при помощи свойств border в ярлыке . Если border = 0, то это обозначает, что вы не хотите, чтобы фреймы имели видимые рамки.
Фреймы и JavaScript
Сейчас мы переходим к обсуждению того, как с точки зрения JavaScript выглядят фреймы, расположенные в окне броузера. Для этого создадим два фрейма, точно так, как это было сделано в первом примере.
Ранее мы видели, что все элементы web-страницы иерархически организованы. Фреймы v не исключение. Иерархия страницы первого примера выглядит таким образом:
Основным элементом иерархии является окно броузера. Это окно разбивается на два фрейма. Окно броузера является родительским элементом по отношению к двум фреймам, которые являются дочерними по отношению к окну броузера. Мы дали этим двум фреймам уникальные имена frame1 и frame2. Используя эти имена, мы можем передавать информацию из одного фрейма другому. При помощи скриптов мы можем решить следующую задачу. Нужно создать такую страницу, в которой при нажатии ссылки, расположенной в документе первого фрейма, происходит загрузка запрашиваемого документа во второй фрейм, а не в первый. Эта задача может быть актуальной в случаях, когда используются различные меню, причем фрейм, в котором содержится меню или содержание, остается неподвижным и неизменным, и в котором имеется набор ссылок на другие страницы.
Рассмотрим три следующих варианта:
- родительское окно или фрейм обращаются к дочернему фрейму;
- дочерний фрейм обращается к родительскому окну или фрейму;
- дочерний фрейм обращается к другому дочернему фрейму.
С точки зрения окна броузера (простите за жаргон) дочерние фреймы имеют имена frame1 and frame2. На рисунке показано, что окно броузера имеет прямые (родительские) связи с этими фреймами. Поэтому если вы используете скрипт, расположенный в родительском фрейме (в окне броузера), т.е. во фрейме, который содержит два дочерних фрейма, и хотите обратиться из родительского фрейма к дочерним, то у вас есть простой метод v укажите имя дочернего фрейма, к которому необходимо обратиться. К примеру, можно написать так:
frame2.document.write (?Обращение из родительского окна»).
Иногда появляется необходимость обратиться к родительскому окну из дочернего фрейма. Эта необходимость может возникнуть, например, тогда, когда нужно избавиться от фреймов. Освобождение от фреймов означает, что в окно броузера загружается другая страница, которая отличается от той, что породила фреймы. В нашем примере это страница, которая содержится в дочернем фрейме. Мы можем обратиться к родительскому окну или родительскому фрейму при помощи parent (родитель). Для того чтобы загрузить в окно броузера новый документ, необходимо задать новый адрес URL, присвоив его объекту местоположения location.href. Поскольку мы хотим удалить фреймы, то нам необходимо обратиться к объекту местоположения, который расположен в родитель-ском окне. Поскольку каждый фрейм может быть загружен своим собственным документом, то у каждого фрейма есть свой собственный объект местоположения. Мы можем загрузить новую страницу в родительское окно при помощи следующей команды, расположенной в документе дочернего фрейма: parent.location.href= ?http://. |
Довольно часто приходится сталкиваться с задачей, когда из одного дочернего документа необходимо обратиться к другому дочернему документу. Как записать что-либо во второй фрейм, находясь в первом фрейме? Иными словами, какая команда должна быть записана в документе page1.htm, загруженном в первый фрейм, чтобы привести, появлению во втором фрейме необходимых записей? На нашей картинке нет прямых связей между первым и вторым дочерними фреймами. Это означает, что мы не имеем возможности обратиться из первого фрейма frame1 ко второму, указав имя второго фрейма frame2 в документе page1.htm, поскольку первый фрейм ничего ?не знает| о существовании второго фрейма. С точки зрения родительского окна второй фрейм носит имя frame2, а с точки зрения первого фрейма к родительскому окну обращаются при помощи parent. Поэтому, объединяя все вместе, для того, чтобы обратиться ко второму фрейму из первого, мы пишем
parent.frame2.document.write (?Это обращение из frame1.|);
Меню навигации
Рассмотрим пример того, как можно создавать меню навигации. Меню навигации v это набор нескольких ссылок, расположенных в одном фрейме. Если пользователь выбирает какую-либо ссылку из этого фрейма, то выбранная страница загружается не в этот фрейм, а во второй.
В начале мы пишем документ, который создает фреймы. Этот документ выглядит подобно тому, что был приведен в первом примере.
Документ start.htm v это стартовая страница, которая будет вначале загружена во фрейм, носящий имя main. К этой странице нет никаких особых требований.
Во фрейм, который назван menu, будет загружена следующая страница: