По умолчанию сохраненные данные доступны только тому Flash_ролику, кото_ рый их создал. Однако существует возможность ослабить это ограничение и по_ зволить различным роликам из одного каталога или с одного сервера совместно использовать сохраненные данные. Делается это способом, очень похожим на применение атрибута path в cookie. При создании объекта SharedObject методом SharedObject.getLocal() вторым аргументом можно передать путь, который дол_ жен представлять собой начальную часть фактического пути из URL_адреса ро_ лика. После этого любой другой ролик, расположенный по тому же пути, сможет получить доступ к данным, сохраненным текущим роликом. Например, в сле_ дующем фрагменте создается объект SharedObject, который может использоваться всеми Flash_роликами того же веб_сервера:
var so = SharedObject.getLocal("My/Shared/Persistent/Data", // Имя объекта
"/"); // Путь
При работе с классом SharedObject из JavaScript_сценариев вас вряд ли заинтере_ сует возможность совместного использования данных разными Flash_роликами, скорее разными веб_страницами, управляющими одним роликом (см. пример 19.3 в следующем разделе).
Пример: хранимые объекты
Данный раздел завершается расширенным примером, в котором определяется унифицированный прикладной интерфейс доступа к трем механизмам сохране_ ния данных, рассматриваемым в этой главе. В примере 19.3 определяется класс, позволяющий сохранять объекты. Класс PObject очень напоминает класс Cookie из примера 19.2. Сначала с помощью конструктора PObject() создается хранимый объект. Конструктору передаются имя объекта, набор значений по умолчанию и функция_обработчик события onload. Конструктор создает новый JavaScript_ объект и предпринимает попытку загрузить данные, сохраненные ранее с ука_ занным именем. Если данные обнаружены, выполняется их интерпретация в ви_ де пар имя–значение, после чего эти пары преобразуются в свойства вновь соз_ данного объекта. Если данные не обнаружены, используются значения, задан_ ные как свойства, предлагаемые по умолчанию. В любом случае указанная функ_ ция_обработчик вызывается асинхронно, когда данные готовы к использованию.
После вызова обработчика события onload хранимые данные становятся доступ_ ными в виде свойств объекта PObject, как если бы это были свойства обычного JavaScript_объекта. Чтобы сохранить новые данные, сначала нужно установить требуемые свойства объекта PObject (логического, числового или строкового ти_
486 Глава 19. Cookies и механизм сохранения данных на стороне клиента
па), а затем вызвать метод save() объекта PObject, указав при желании время жизни данных (в сутках). Чтобы удалить хранимые данные, следует вызвать ме_ тод forget() объекта PObject.
Определяемый ниже класс PObject при работе в IE использует механизм сохране_ ния данных этого броузера. В противном случае он проверяет доступность под_ ходящей версии Flash_модуля и при его наличии использует механизм сохране_ ния Flash_модуля. Если ни один из перечисленных вариантов недоступен, сохра_ нение выполняется с помощью cookies.1
Обратите внимание: класс PObject допускает сохранение значений только эле_ ментарных типов и преобразует значения числовых и логических типов в стро_ ки. Есть возможность реализовать сериализацию массивов и объектов в строки, а при загрузке данных преобразовывать эти строки обратно в массивы и объекты (подробнее об этом можно прочитать по адресу: http://www.json.org), но в данном примере это не предусмотрено.
Пример 19.3 достаточно большой, но он содержит подробные комментарии, по_ этому разобраться в нем не составит большого труда. Обязательно прочитайте вводный комментарий, где описывается класс PObject и его прикладной интер_ фейс (API).
Пример 19.3. PObject.js: хранимые объекты для JavaScript'объекта PObject
/**
* PObject.js: JavaScript_объекты, которые позволяют сохранять данные между
* сеансами работы с броузером и могут совместно использоваться веб_страницами
* одного каталога с одного и того же сервера.
*
* Данный модуль определяет конструктор PObject(), с помощью которого
* создается хранимый объект.
* Объекты PObject имеют два общедоступных метода. Метод save() сохраняет
* текущие значения свойств объекта, а метод forget() удаляет сохраненные
* значения свойств объекта. Чтобы определить хранимое свойство в объекте
* PObject, достаточно просто установить свойство, как если бы это был
* обычный JavaScript_объект, и затем вызвать метод save(), чтобы сохранить
* текущее состояние объекта. Вы не должны использовать имена "save"
* и "forget" для определения своих свойств, точно так же вы не должны
* использовать имена, начинающиеся с символа $. Объект PObject предполагает,
* что значения всех свойств будут иметь строковый тип. Хотя при этом
* допускается сохранять числовые и логические значения, но при получении
* данных они будут преобразованы в строки.
*
* В процессе создания PObject хранимые данные загружаются и сохраняются
* во вновь созданном объекте в виде обычных JavaScript_свойств, и вы можете
* использовать PObject точно так же, как обычный JavaScript_объект.
* Обратите внимание: к тому моменту, когда конструктор PObject() вернет
* управление, хранимые свойства могут быть еще не готовы к использованию
1 Кроме того, можно определить класс, который задействовал бы cookies как основ_ ной механизм сохранения данных, а возможности, предоставляемые IE и Flash_ модулем, применялись бы только в том случае, если пользователь заблокировал cookie_файлы.
19.5. Альтернативы cookies
* и вам нужно подождать, пока в виде асинхронного вызова функции_обработчика
* события onload не будет получено извещение о готовности,
* которое передается конструктору.
*
* Конструктор:
* PObject(name, defaults, onload):
*
* Аргументы:
*
* name Имя, идентифицирующее хранимый объект. Одна страница может хранить
* данные в нескольких объектах PObject, и каждый объект PObject
* доступен для всех страниц из одного каталога, поэтому данное имя
* должно быть уникальным в пределах каталога. Если этот аргумент
* содержит значение null или отсутствует, будет использовано
* имя файла (а не каталога), содержащего веб_страницу.
*
* defaults Необязательный JavaScript_объект. Если сохраненные ранее
* значения свойств хранимого объекта найдены не будут (что
* может произойти, когда объект PObject создается впервые)
* свойства данного объекта будут скопированы во вновь созданный
* объект PObject.
*
* onload Функция, которая вызывается (асинхронно), когда хранимые значения
* загрузятся в объект PObject и будут готовы к использованию.
* Данная функция вызывается с двумя аргументами: ссылкой на объект
* PObject и именем объекта PObject. Эта функция вызывается уже
* *после* того, как конструктор PObject() вернет управление.
* До этого момента свойства PObject не должны использоваться.
*
* Метод PObject.save(lifetimeInDays):
* Сохраняет свойства объекта PObject и гарантирует, их хранение по меньшей
* мере указанное число суток.
*
* Метод PObject.forget():
* Удаляет свойства объекта PObject. После этого сохраняет "пустой" объект
* PObject в хранилище, и если это возможно, определяет, что срок хранения
* этого объекта уже истек.
*
* Примечания к реализации:
*
* Этот модуль определяет единый прикладной интерфейс (API) объекта
* PObject, который предоставляет три различные реализации этого
* интерфейса. В Internet Explorer используется механизм сохранения
* "UserData". В любых других броузерах, в которых установлен Flash_модуль
* от Adobe, используется механизм сохранения SharedObject. В броузерах,
* отличных от IE и не имеющих Flash_модуля расширения, используется
* реализация на базе cookie. Обратите внимание: Flash_реализация не
* поддерживает возможность определения даты окончания срока действия
* хранимых данных, поэтому в данной реализации хранимые данные существуют
* до тех пор, пока не будут явно удалены.
*
* Совместное использование объектов PObject:
*
* Данные, сохраняемые в объекте PObject из одной страницы, будут доступны
488Глава 19. Cookies и механизм сохранения данных на стороне клиента
* из других страниц, расположенных в том же каталоге на том же веб_сервере.
* При использовании реализации на базе cookie страницы, расположенные
* во вложенных каталогах, смогут читать (но не писать) свойства объектов
* PObject, созданных страницами из родительского каталога. В случае
* реализации на базе Flash_модуля любые страницы с того же веб_сервера смогут
* совместно использовать данные, если задействуют модифицированную
* версию этого модуля.
*
* Различные броузеры сохраняют свои cookie_файлы в разных хранилищах,
* потому данные, сохраненные как cookie_файлы в одном броузере, будут
* недоступны в других броузерах. Однако если два броузера применяют
* одну и ту же установленную копию Flash_модуля, они смогут совместно
* использовать данные, сохраненные с помощью реализации на базе Flash_модуля.
*
* Сведения о безопасности:
*
* Данные, сохраняемые в виде объекта PObject, хранятся в незашифрованном
* виде на жестком диске локальной системы. Приложения, работающие на этом
* компьютере, могут прочитать эти данные, поэтому PObject не подходит
* для хранения частной информации, такой как номера кредитных карт,
* паролей или номеров банковских счетов.
*/ // Это конструктор
function PObject(name, defaults, onload) {
if (!name) { // Если имя не задано, использовать последний компонент URL name = window.location.pathname;
var pos = name.lastIndexOf("/");
if (pos != _1) name = name.substring(pos+1);
}
this.$name = name; // Запомнить имя
// Вызов делегированного частного метода init(),
// определяемого реализацией.
this.$init(name, defaults, onload);
}
// Сохраняет текущее состояние объекта PObject на заданное число суток. PObject.prototype.save = function(lifetimeInDays) {
// Для
начала преобразовать свойства объекта в одну строку
var s = "";
//
Изначально строка пустая
for(var name in
this) {
//
Цикл по свойствам объекта
if
(name.charAt(0) == "$") continue; //
Пропустить частные свойства,
//
имена которых начинаются с $
var value =
this[name];
//
Получить значение свойства
var type = typeof value;
//
Получить тип свойства
//
Пропустить свойства_объекты и функции
if
(type ==
"object" || type == "function") continue;
if
(s.length > 0) s += "&";
//
Отделить свойства знаком &
//
Добавить
имя свойства и кодированное
значение
s += name +
':' + encodeURIComponent(value);
}
// Затем вызвать делегированный метод, определяемый реализацией,
// для фактического сохранения строки.
this.$save(s, lifetimeInDays);
19.5. Альтернативы cookies
};
PObject.prototype.forget = function() {
// Сначала удалить сериализуемые свойства данного объекта с помощью
// тех же критериев отбора свойств, что использовались в методе save(). for(var name in this) {
if (name.charAt(0) == '$') continue; var value = this[name];
var type = typeof value;
if (type == "function" || type == "object") continue; delete this[name]; // Удалить свойство
}
// Затем стереть сохраненные ранее данные, записав пустую строку
// и установив время жизни равным 0.
this.$save("", 0);
};
// Преобразовать строку в пары имя/значение и превратить их в свойства объекта this.
// Если строка не определена или пустая, скопировать свойства из объекта по умолчанию.
// Данный частный метод используется реализациями $init().
// Теперь известно, что данные загружены Flash_модулем,
// следовательно, можно прочитать их
var data = pobj.$flash.GetVariable("data")
pobj.$parse(data, defaults);// Преобразовать данные в свойства
// или скопировать данные по умолчанию if (onload) onload(pobj, name); // Вызвать обработчик onload,
// если он определен
};
// Создать тег <embed> для хранения Flash_ролика. Использование тега
// <object> точнее соответствует стандартам, но он вызывает проблемы
// при приеме FSCommand. Обратите внимание: мы никогда не используем
// Flash в IE, что существенно упрощает реализацию.
var movie = document.createElement("embed"); // Элемент с роликом
movie.setAttribute("id", moviename);
//
Идентификатор элемента
movie.setAttribute("name", moviename);
//
И имя
movie.setAttribute("type", "application/x_shockwave_flash"); movie.setAttribute("src", url); // Это URL_адрес ролика
// Сделать ролик малозаметным и переместить его в правый верхний угол movie.setAttribute("width", 1); // Если установить равным 0,
// это работать не будет
movie.setAttribute("height", 1);
movie.setAttribute("style", "position:absolute; left:0px; top:0px;"); document.body.appendChild(movie); // Добавить ролик в документ this.$flash = movie; // И запомнить для дальнейшего использования