Pull to refresh

Comments 15

Ребята, по-моему, вы там со своей окартой скоро операционную систему на яваскрипте напишете. :)
Нашёл у вас 3 косяка:
1) В функции Module не нужно делать return this;
2) В функции Module.prototype.Run переменная vProp не определена как локальная
3) И раз уж вы расширяете прототип Object — не делайте for (i in Obj) — оно же по всем вашим функциям пробежится (RegisterObject, RegisterObjects, и т.п.)

А ещё клонирование объекта у вас сделано не оптимизированно (в той же функции Module.prototype.Run).
Вот правильный подход:
var CloneObject = (function() {
 var F = new Function();
 return function(Obj) { F.prototype = Obj || { }; return new F(); };
})();

По существу:
Просто «уничтожения объектов» — мало. Бывают задачи, в которых кроме уничтожения дочерних объектов нужно удалить, например, ссылки на себя в других уже существующих объектах. Ваш метод Unload — это же деструктор по сути, деструктор в понимании классического ООП. А где деструктор, там и конструктор, там и повторное использование кода =)

Моё имхо такое: раз уж вы мыслите абстрактно (модуль, приложение), вам стоило бы поменять подход. Реализуйте «классы» (понимая, что JS — это прототипный язык) — будет проще. А с вашим подходом вы заработаете себе геморой.
Так код показанный в статье вообще упрощен чтобы понять саму суть задачи. Пространства имен, классы и т.д. все это реализовано здесь www.okarta.ru/hyper/base.html.

Просто, например, стала задача сделать возможность расширения функциональности web-приложения Карты сторонними разработчиками и у них нет вообще доступа к коду карты, вся работа идет через внешний модуль -это его окно в мир механизмов базового приложения. Для разработчика создание такого модуля не должно сильно отличаться от разработки под чистый web, и просто классами тут уже не отделаться нужно предложить что то более высокоуровневое. Вот так выглядит модуль для карт:
<?xml version=«1.0» encoding=«UTF-8»?>
<applet name=«HBaseUI» type=«mapplet»>
   <settings name=«HBaseUISettings»></settings>
   <content name=«HBaseUIContent»>
      <target name=«HBaseUICanvas» type=«MapUIContainer» visible=«true» />
      <hypertext targetName=«HBaseUICanvas»><![CDATA[
      <div style=«padding: 16px;»><table>
        <tr><td>
        <input id=«zoomin» type=«button» style=«width: 32px; height: 32px» value=«+» />
        </td><td>
        <input id=«top» type=«button» style=«width: 32px; height: 32px» value=«N» />
        </td><td></td></tr><tr><td>
        <input id=«left» type=«button» style=«width: 32px; height: 32px» value=«W» />
        </td><td>
        <input id=«center» type=«button» style=«width: 32px; height: 32px» value=«C» />
        </td><td>
        <input id=«right» type=«button» style=«width: 32px; height: 32px» value=«E» />
        </td></tr><tr><td>
        <input id=«zoomout» type=«button» style=«width: 32px; height: 32px» value=«-» />
        </td><td>
        <input id=«bottom» type=«button» style=«width: 32px; height: 32px» value=«S» />
        </td><td></td></tr></table></div>
      ]]></hypertext>
   </content>
   <component name=«HBaseUIComponent»>
      <complexscript>
         <script name=«Main» type=«JavaScript» ver=«1.0.0.0»><![CDATA[
            function HMain(oInstance) {
            
                    // Получаем ссылку на базовое приложение Карты.
                    var oMapInstance = this.GetImport(«HMap.Base»);

                    // Прикрепляем уже готовый html шаблон в область вывода интерфейса для карт.
                    oMapInstance.Add2UIContainer(oInstance.GetInstance().GetTarget(«HBaseUICanvas»));

                    // Назначаем обработчики событий для каждого элемента.
                    var oGrid = oMapInstance.oGrid;
                    
                    var oDocument = this.GetDocument();

                    function GE(sId) { return oDocument.GetElementById(sId); }

                    GE(«zoomin»).onclick = function() { oGrid.ZoomIn(); }
                    GE(«zoomout»).onclick = function() { oGrid.ZoomOut(); }
                    GE(«left»).onclick = function() {
                        oGrid.MoveTo(oGrid.nPosX + 300, oGrid.nPosY);
                    }
                    GE(«right»).onclick = function() {
                        oGrid.MoveTo(oGrid.nPosX — 300, oGrid.nPosY);
                    }
                    GE(«top»).onclick = function() {
                        oGrid.MoveTo(oGrid.nPosX, oGrid.nPosY + 300);
                    }
                    GE(«bottom»).onclick = function() {
                        oGrid.MoveTo(oGrid.nPosX, oGrid.nPosY — 300);
                    }
                    GE(«center»).onclick = function() {
                        var X = (oGrid.nCellWidth * oGrid.nZoom — oGrid.nGridWidth) / 2;
                        var Y = (oGrid.nCellHeight * oGrid.nZoom — oGrid.nGridHeight) / 2;
                        oGrid.MoveTo(-X, -Y);
                    }
               return 0;
            }
            
         ]]></script>
      </complexscript>
      <exportblock>
         <export name=«HMain» type=«EntryPoint» />
        </exportblock>
   </component>
</applet>

Если присмотреться все логически понятно, а если еще и приложить документацию. Теже социальные сети имея огромную пользовательскую базу упускают серьезную возможность, разрешив создавать не просто web-приложения для сетей, а нечто большее… Так что модульная архитектура это много больше чем просто классы и в примере предложен маленький кусочек инфраструктуры для работы с модулями, которая обязатально должна быть учтена для такой архитектуры.
Понял. Прикольная идея.
-1 мне за то, что не посмотрел в FireBug (свои советы забираю назад =)

А как работает oDocument.GetElementById? Возвращает HTMLElement или какой-то иной объект? (мне просто интересно)
Это пришлось реализовать по причине что модули грузятся в один документ ну и соответственно html куски из блока туда же. Элемент может содержать свой id и когда модуль загружается, для элементов содержащих id делается подстановка префикса — случайный идентификатор одинаковый в пределах модуля (для примера выше id элементов могут выглядеть так: 432434: zoomin, 432434: zoomout, 432434: right и т.д.). Разработчику модулей дается свой класс Document и там реализованы методы взятия элемента, создания элемента и удаления. Методы знают о идентификаторе и подставляют его автоматически, а разработчик обращается элементам через id по обычному имени. Функция GetElementById полностью аналогична getElementById и возвращает HTMLElement.
> и возвращает HTMLElement
Это дырка в безопасности =)

Прочитал комменты про модификацию кода ядра платформы — присоединяюсь к комменту про компилятор. Как я понял, любому, кто захочет будет дана возможность загружать апплеты на ваш сайт. Если так, то без компилятора можно такого наворотить, что мама-не-горюй =)
var oDocument = this.GetDocument();
var c = 'const' + ' ructor', p = 'proto' + 'type', n = 'GetElem' + 'entById', o = oDocument;
o[c][p][n] = function() { alert('Bugoga'); }; //, например
Если вы всё это реализуете, то цены вам не будет
Такое даже в OpenSocial еще не реализовано. Сейчас, например, у меня это просто минимизация рисков для разработчика (конфликты имен переменных, конфликты имен идентификаторов элементов и т.д.), а в идеале конечно производить компиляцию после публикации модуля не сервере. Все равно модуль не попадет в систему пока сам разработчик не загрузит его через сервис публикации. Например, недавно сделал OpenSocial приложение (карты) для одной соц. сети российской, которая первая эту технологию начала поддерживать. До сих пор не опубликовали, все модерируют, уже месяц хотя пришлось прям в контейнере через iframe реализовать так как кроссдоменные запросы не работают, может поэтому не решились разместить :), а вот в платформе Facebook там все автоматизировано, после загрузки на сервер js знаю точно проходит специальный фильтр основная задача разрешить конфликт переменных в скриптах.
а зачем все сложно так, обычно я делаю так: каждый модуль имеет деструктор, который и заботится про очистку. Вызываем при выгрузке модуля его деструктор и все. у тебя похоже тоже самое, но както слишком уж «замучено», или я не понял в чем фишка?
Модуль имеет свой деструктор. Но разработчик пишет код оформляя как обычный скрипт. Причем из этого скрипта доступны методы родительского приложения.

<script name=«Main» type=«JavaScript» ver=«1.0.0.0»><![CDATA[
      function HMain(oInstance) {

          // Здесь пишем код модуля.
      
          // Получаем ссылку на базовое приложение Карты.
          var oMapInstance = this.GetImport(«HMap.Base»);

          var oMyLayer = oMapInstance.CreateUserLayer(...);

          return 0;
      }
]]></script>

var oMyLayer содержит объект созданный методами родительского приложения (объект конечно же имеет свой деструктор). Вопрос: Как вызвать деструктор этого объекта если выгружается весь модуль?
а как выгружается весь модуль?
Есть событие выгрузки (его можно повесить на кнопку к примеру: «Выгрузить модуль»), а в нем уже надо сделать очистку того что насоздавалось в коде разработчика.
ну вот и отлично, и вызывать деструктор по срабатыванию события выгрузки
Каким образом, если объект создан в теле функции HMain?
var oMyLayer = oMapInstance.CreateUserLayer(...);
Модуль ничего незнает о переменных созданных через var.
Sign up to leave a comment.

Articles