Обертка для DDL . С миру по нитке...
Запись от in4core размещена 03.02.2012 в 15:03
Предыстория : когда то давно писал свой первый сайт, где то увидел, что можно прикрутить Deep Linking к флеш сайту, решил задаться этим вопросом, - попал соотв на библиотеку SwfAddress. В то время она мне показалась очень продвинутой, а главное работает! Поковырявшись в документации, прикрутили. В то время, я еще совсем плохо знал и ас2, а о JS вообще понятия не имел. И вот сейчас подумал, а не попробовать ли мне написать свою обертку, так сказать, свой велосипед. Ну что ж, поехали...
Постараюсь описать подробно все, что я узнал, и каким образом собрал DDL либу. Забегая вперед, сразу опишу, что нам пригодится для качественного линкования. ( не зря назвал с миру по нитке, создание либы было похоже на написания реферата сидя в библиотеке, - прочел часть из одной книги вырезал, редактировал, принялся за другую.. и так из кусочков собирается реферат ).
1. Базовые знания JS ( таковых у меня не было, пришлось разбираться )
2. Библиотека JQuery
3. Плагин для JQuery ( hash )
4. Ну и собственно ас3 )
DDL
Начал с того, что в поисковике вбивал фразы типа изменить заголовок страницы через JS и т.п. находил отдаленные куски кода. Очень мне помог САЙТ. Видимо приятно написанная документация по JS.
Потихоньку разбираясь , мы понимаем, что работать нам придется лишь с глобальными методиками JS - document , window , location.
На сколько я понял - document есть наша html страничка, тоесть весь ее код, или оболочка. Window - соотв окно в котором размещается наш document. Document должен где то хранится - поэтому у документа есть след уровень location , указывающий на URL , доменные имена и т.п.
Адрес в браузерной строке может выглядеть так http://my.com/mysite/ или например так http://my.com/mysite/#mySuper
-первое утверждение есть href для location , второе hash . Hash отличается тем, что не перегружает страничку , собственно на хеше и строится DDL.
Давайте попробуем создать свой первый метод, меняющий хеш в строке, напишем :
Код:
function setLocation(value) { document.location.hash = '#' + value; }
Ну что же, метод создали, осталось прикрутить к флешу и проверить , как оно работает. Для прикрутики воспользуемся ExternalInterface .
ExternalInterface имеет 2 основных метода call и addCallBack . Первый вызывает метод JS , второй ссылается на метод JS и может быть вызван из JS ( тоесть в первом случае флеш дергает JS , во втором JS - флешу ).
В данном случае нам потребуется 1й метод. Пишем :
stage.addEventListener(MouseEvent.CLICK , onClick); function onClick(e:MouseEvent) { ExternalInterface.call('setLocation' , 'superHash' + new Date().getTime() ); }
Код:
<script src="myDDL.js" type="text/javascript"></script>
Что нам еще нужно для качественного DDL ? Ну наверное изменение заголовка страницы, установка статуса , может какие то еще фишечки... Попробуем изменить заголовок страницы , лезем в JS справочник, ага
Код:
function setWindowTitle(value) { document.title = value; }
Код:
function doSetStatus(value) { window.status = value; }
Собственно с этого пункта я поплыл, когда статус строки не захотел меняться. Полез опять в гугл, читал читал, искал искал... все одно - пишите так ( как выше ) и все будет работать... Так бы и забил на этот пункт, если бы на каком то сайте не увидел надпись : Данная фича по умолчанию отключена у большинства браузеров и включается вручную. Ухх... значит не мой косяк... проехали. Тем временем я вспомнил про SWFAddress и решил посмотреть , а может у них работает ?! - Фигушки и у них строка статуса не работает, видимо, что то случилось Кроме того, пока искал полазил по их исходникам и ужаснулся.... такая муто-дребедень и чего они там писали все эти годы?! ... тонны никому не нужного кода основанные на регэкспах и переборах символов в строках . Каюсь, углубляться далеко не стал, возможно там много полезного того, что я просто не заметил или не понял - или вообще мой код будет не формат по сравнению с ними, но тесты показали, что моя система работает во всех браузерах без каких либо проблем ( всех* - современных версиях ).
Тем временем читатель попробовавший , то что я описал, мог заметить - кнопки вперед, назад - РАБОТАЮТ! Хм... подумал я, и чего там SWFA мучались? И тут я заметил, что история то работает, и урл меняется, но события о изменении не происходит... ага попался жучок...подумал я, и начал дальше курить мануалы.
Но прежде чем, говорить об этом, стоит сначала разобрать работу addCallBack у EI.
Первым делом откроем справочник адоба зайдем в EI - посмотрим пример и слямзим метод JS
Код:
function thisMovie(movieName) { if (navigator.appName.indexOf("Microsoft") != -1) { return window[movieName]; } else { return document[movieName]; } }
Модернизируем наш метод по установке урла так :
Код:
function setLocation(value) { document.location.hash = '#' + value; thisMovie(movie).getCall(value); }
А в AS напишем
ExternalInterface.addCallback("getCall" , callBackMethod); function callBackMethod(value:String):void { trace('getCallBackFromJS' + value); }
И так если все окей, после нажатия на сцену, в каком нить дебаг-профайлире мы увидим трейс , что заголовок изменен на value.
Теперь вернемся к нашим баранам. Коллбек при установке мы видим, а вот при изменении адреса вручную или кнопками вперед-назад - НЕТ! Оно и понятно... А что же делать ? Курим мануалы дальше...
* Наверное вы находили какие нибудь события? - Да мы копали копали и находили какие то события... но есть у меня один могильничек....* Собственно данная тема и выражает всю сущность событий JS - это порнография. Как таковых приятных нам addEventListener тут нет, зато есть всякие OnLoad, onChange да и то для форм html документа, или закрытия страницы. Наверняка нам помогло бы событие onUnload - запускающиеся при смене урл страницы, выгружая весь документ, но нет - у нас же хеш , а на него не влияет, ведь перезагрузки не происходит. Думаю дальше, ага таймеры то есть в JS - можно повесить 1 секундный таймер и получать изменение строки браузера. Однако, зачем нам лишняя обертка да еще и таймером? Читаем мануалы дальше, не забывая про гугл. Натыкаемся на JQuery - а что это? Вики ответит - это либа JS написанная умными дядьками, там и события есть и много всего, но вникать мы в нее не будем сильно, а просто скачаем, и установим в хтмл как обычный js файл. А так же скачаем плагин для jQuery для хеша отсуда И так же установим в хидер.
Обновим наш мега файл DDL следующей методой
Код:
function setLocation(value) { document.location.hash = '#' + value; } $(function(){ $(window).hashchange( function(){ thisMovie(movie).getCall(location.hash); }) $(window).hashchange(); });
Вот, что получилось у меня :
DDL.js
/** * ... * @author in4core lab * DYNAMIC DEEP LINKING - JS utils v1.0 */ var movie = ''; // calle from AS // events name var eLocation = 'jsSetLocation'; var eTitle = 'jsSetTitle'; var eCookie = 'jsSetCookie'; var eStatus = 'jsSetStatus'; function thisMovie(movieName) { if (navigator.appName.indexOf("Microsoft") != -1) { return window[movieName]; } else { return document[movieName]; } } function setMovieName($name) { movie = $name; } $(function(){ $(window).hashchange( function(){ thisMovie(movie).onChange(eLocation , location.hash); }) $(window).hashchange(); }); function getBrowserType() { return navigator.appName; } function getURL() { return document.URL; } function getBrowser() { return navigator.appCodeName; } function getDomain() { return document.domain; } function reloadPage() { document.location.reload(); } function doSetLocation(path) { document.location.href = path; } function doSetWindowTitle(title) { document.title = title; thisMovie(movie).onChange(eTitle , title); } function doSetStatus(title) { window.status = title; thisMovie(movie).onChange(eStatus , title); } function doSetCookie( $name , $value ) { if(navigator.cookieEnabled) { document.cookie = $name + "=" + escape($value); thisMovie(movie).onChange(eCookie , $name + ':' + $value); } } function doGetCookie( $name ) { var cookie = " " + _doc.cookie; var search = " " + $name + "="; var setStr = null; var offset = 0; var end = 0; if (cookie.length > 0) { offset = cookie.indexOf(search); if (offset != -1) { offset += search.length; end = cookie.indexOf(";", offset) if (end == -1) { end = cookie.length; } setStr = unescape(cookie.substring(offset, end)); } } return(setStr); }
DDLBroadcaster.as
package com.in4core.jsreader { import flash.display.LoaderInfo; import flash.errors.IllegalOperationError; import flash.events.EventDispatcher; import flash.external.ExternalInterface; /** * ... * @author in4core lab */ public final class DDLBroadcaster { private static const SPLIT :String = "#"; private static const STRICT:String = "/"; private static var _useStrict:Boolean = false; private static var _historyObject:Vector.<String> = new Vector.<String>; private static var _ddlDispatcher:EventDispatcher = new EventDispatcher(); private static var _availability:Boolean = false; public function DDLBroadcaster() { throw new IllegalOperationError("this class doesnt have a instance"); } public static function initialize(loaderInfo:LoaderInfo):void { if (ExternalInterface.available) { _availability = true; const a:Array = loaderInfo.loaderURL.split("/"); const s:String = a[a.length - 1].split(".swf").join(""); ExternalInterface.call("setMovieName" , s); ExternalInterface.addCallback("onChange" , onChange); } } ///////////////////////////////////////////////////////////////// //4 //4 PUBLIC METHODS //4 ///////////////////////////////////////////////////////////////// public static function addEventListener(ddlEventName:String , closureFunction:Function):void { _ddlDispatcher.addEventListener(ddlEventName , closureFunction); } public static function doSetLocation(location:String):void { const path:String = SPLIT + location + (useStrict ? STRICT : ""); call("doSetLocation", path); _historyObject.push ( fullURL ); } public static function doSetStatus(status:String):void { call("doSetStatus", status); } public static function doSetWindowTitle(title:String):void { call("doSetWindowTitle" , title); } public static function setCookie(cookName:String , value:String):void { call("setCookie", cookName , value); } public static function getCookieByName(name:String):String { return call("getCookie" , name ); } public static function getHistory():Vector.<String> { return _historyObject; } public static function reloadPage():void { call("reloadPage"); } ///////////////////////////////////////////////////////////////// //4 //4 PUBLIC SPECIAL //4 ///////////////////////////////////////////////////////////////// public static function getStrictLocationAsArray():Array { var URL:String = fullURL; if (URL.search(SPLIT) != -1 ) { URL = URL.slice( URL.indexOf(SPLIT) + 1 ); return URL.split ( STRICT ); } return null; } ///////////////////////////////////////////////////////////////// //4 //4 DDL GETTERS / SETTERS //4 ///////////////////////////////////////////////////////////////// public static function get available():Boolean { return _availability; } public static function get useStrict():Boolean { return _useStrict; } public static function set useStrict(bool:Boolean):void { _useStrict = bool; } public static function get browserName():String { return call("getBrowser"); } public static function get fullURL():String { return call("getURL"); } public static function get currentDomain():String { return call("getDomain"); } ///////////////////////////////////////////////////////////////// //4 //4 PRIVATE UTILS //4 ///////////////////////////////////////////////////////////////// private static function call(JSMethod:String , ...rest):String { if (_availability) return ExternalInterface.call(JSMethod , rest); return null; } private static function onChange(changeEvent:String , callBack:String):void { _ddlDispatcher.dispatchEvent(new DDLBroadcasterEvent(DDLBroadcasterEvent.DDL_ON_CHANGE , callBack , changeEvent)); } } }
Main.as
DDLBroadcaster.useStrict = true; DDLBroadcaster.initialize(loaderInfo); DDLBroadcaster.addEventListener(DDLBroadcasterEvent.DDL_ON_CHANGE , onChange); private function onChange(e:DDLBroadcasterEvent):void { tf.appendText ( e.callBack + ' : ' + e.changeName + '\n' ); tf.appendText ( 'Browser : ' + DDLBroadcaster.browserName + '\n' ); tf.appendText ( 'Domain : ' + DDLBroadcaster.currentDomain + '\n' ); tf.appendText ( 'FullURL : ' + DDLBroadcaster.fullURL + '\n' ); tf.appendText ( 'DDL Use Strict by end : ' + DDLBroadcaster.useStrict + '\n' ); }
И соотв для полной картины
index.html
Код:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html> <head> <title>IN4CORE WORK TABLE</title> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <meta name="language" content="en" /> <meta name="description" content="" /> <meta name="keywords" content="" /> <script src="jquery-1.7.1.min.js" type="text/javascript"></script> <script src="jquery.ba-hashchange.js" type="text/javascript"></script> <script src="DDL.js" type="text/javascript"></script> <script src="js/swfobject.js" type="text/javascript"></script> <script type="text/javascript"> var flashvars = { }; var params = { menu: "false", scale: "noScale", allowFullscreen: "true", allowScriptAccess: "always", bgcolor: "#FFFFFF" }; var attributes = { id:"IN4COREWORKTABLE" }; swfobject.embedSWF("IN4COREWORKTABLE.swf", "altContent", "100%", "100%", "10.0.0", "expressInstall.swf", flashvars, params, attributes); </script> <style type="text/css"> html, body { height:100%; overflow:hidden; } body { margin:0; } </style> </head> <body> <div id="altContent"> <h1>IN4CORE WORK TABLE</h1> <p>Alternative content</p> <p><a href="http://www.adobe.com/go/getflashplayer"><img src="http://www.adobe.com/images/shared/download_buttons/get_flash_player.gif" alt="Get Adobe Flash player" /></a></p> </div> </body> </html>
W3C School ( http://www.w3schools.com/js/ )
JQuery ( http://jquery.com/ )
Hash для JQuery ( http://benalman.com/projects/jquery-hashchange-plugin/ )
Если что то забыл, или где то не корректно написал про JS - поправьте, исправим.
Всего комментариев 30
Комментарии
03.02.2012 16:00 | |
Полезно. Не очень понятно каково практическое применение.
Я вот все жду реализацию слушателя JS функций из флэша без сокетов. |
03.02.2012 16:28 | |
а SWFAddress не устраивает?
|
03.02.2012 16:32 | |
fish_r, может у SWFAddress есть фатальный недостаток
|
03.02.2012 16:34 | |
> Я вот все жду реализацию слушателя JS функций из флэша без сокетов.
по-подробней плиз |
03.02.2012 17:09 | |
Цитата:
а SWFAddress не устраивает?
Цитата:
Не очень понятно каково практическое применение.
|
03.02.2012 17:34 | |
Цитата:
www.2advanced.com как пример
Только в адресной строке и всё? |
03.02.2012 18:30 | |
Цитата:
Я понимаю, что это невозможно, но вдруг что-то такое народится. Сейчас единственный выход таймер.
|
03.02.2012 18:55 | |
Astraport, а ExternalInterface.addCallback() разве не то, что нужно?
|
03.02.2012 19:47 | |
Зачем тянуть JQuery, если нужно просто посмотреть состояние location.href?
|
03.02.2012 20:02 | |
Цитата:
Astraport, а ExternalInterface.addCallback() разве не то, что нужно?
|
03.02.2012 20:10 | |
Нет, это и есть интерфейс открытый для вызовов из js-а.
|
03.02.2012 22:50 | |
Цитата:
Каким образом ты хочешь это сделать , кроме как по таймеру? Нам же нужно проверять кнопки вперед назад и ручной ввод хеша
Цитата:
Right now, in Internet Explorer 8, Firefox 3.6+, and Chrome 5+, you can bind callbacks to the window.onhashchange event and use it without any kind of plugin.
|
04.02.2012 02:32 | |
А как это в JQuery реализовано? Может как раз через таймер... А если нет, то может забрать оттуда только кусок отвечающий нашим нуждам?
|
04.02.2012 13:47 | |
in4core а где реализация DDLBroadcasterEvent ?
|
06.02.2012 10:37 | |
Цитата:
При желании можно с помощью EI вписывать необходимый js-функционал на страницу, тем самым не подключая скрипты в хтмл-коде.
Соответственно можно и другие функции вызывать. Так же можно избавиться от анонимности функций и действительно добавить их на страницу (тем самым дав возможность использовать эти функции вне флэша): import flash.external.ExternalInterface; this.onMouseMove = function() { var hash = ExternalInterface.call("function (){return window.___fl.getHash();}"); txt.text = hash } this.onMouseDown = function(){ ExternalInterface.call("function (){if(window.___fl){return};window.___fl = {getHash:function(){return document.location.hash;}};}"); } В примере по нажатию мышки создается объект window.___fl, к которому уже можно обращаться и из флэшки, и со страницы (я имею в виду, например, "alert(window.__fl.getHash())"). В общем, думаю, идея ясна. Цитата:
А вообще было бы неплохо использовать новые возможности с изменением адресной строки без перезагрузки страницы и без решетки ("#").
Про остальное напишу чуть позже |
06.02.2012 18:36 | |
Обновил(-а) Котяра 06.02.2012 в 19:23
|
07.02.2012 02:19 | |
jQuery - это жс. Он же как-то ловит событие.
|
07.02.2012 03:46 | |
Ну так вот, о том и вопрос. как он ловит, ты вкурсе? Мне например сложно понять весь движок, проще пихнуть его жертвуя 20 кб
|
Последние записи от in4core
- Система диалогов, создаем подобие old School типа Fallout. (07.05.2014)
- MVC в игорной индустрии (27.11.2012)
- Якорь мне .... ))) Или History API (06.11.2012)
- FSD - учим php/sql (28.06.2012)
- I4Logger - простой и компактный логгер (06.05.2012)