Как стать автором
Обновить

Friendly Open Space JS: Рендеринг на стороне клиента и создание враппера

Время на прочтение7 мин
Количество просмотров2.3K

«Friendly Open Space» — очень молодой фреймворк, но бегать уже умеет :-)


В данной статье по освоению «Friendly Open Space», мы освоим рендеринг шаблона в браузере и запуск приложения на локальной файловой БД.

Ядро фреймворка поддерживает два типа сборки шаблона на клиенте:

  1. Рендеринг полностью выполняется на стороне клиента
  2. Выполняется запрос на рендеринг шаблона серверу, с последующим выводом его в окне браузера.

Первый режим имеет одну особенность, данные необходимые для отрисовки шаблона запрашиваются у сервера, т.е. клиент выполняет FSQL запросы. Особой опасности в этом нет, если вы используете ограничение доступа и модуль fosAccess, но есть возможность выгрузки сырых данных копипастерами. Однако, такой подход существенно снимает нагрузку на сервер.

Второй тип рендеринга уже лишен данной особенности. Клиент отправляет параметры шаблона и принимает уже от сервера HTML. Да, нагрузка на сервер конечно возрастет, но зато такой метод больше подходит для открытых интернет решений.

Подготовка приложения и его настройка


И так, перед нами стоит задача создать одностраничное приложение, которое будет рендерить 2-а шаблона (окошки) на стороне клиента. В виду достаточно простой задачи мы обойдемся без базы данных MySQL и проекций, поэтому всю работу FSQL мы направим в файл, т.е. будем использовать БД на файле для работы внутренних механизмов фреймворка. Ну, приступим.

Создадим каталоги:

templates — директория шаблонов
css — директория css файлов
fos — скачиваем последнюю beta friendlyopenspace.site/ru/download
Разместим надоедающий favicon.ico в корневом каталоге приложения: favicon.ico

Так же сразу разместим файлы стилей в каталоге css: window.css и styles.css

Далее, создаем файл самого приложения application.js:

var fos = require("./fos/fos");

fos.module({
  name: "application.js",
  dependencies: [
    "fos:NServer/Application.js",
  ],
  module: function(application) {
    application.setSettings({
      port:                       3001,
      packages:                   [],
      dynamicLoading:             true,
      clientRenderingMode:        "client",
      dataClient: {
        defaultConnection: "default",
        connections: {
          default: {
            type: "file",
            file: "data.fosdb"
          }
        },
      },
      onInitialize: function(a_event) {
        if (!a_event.error) {
          application.run();
        } else {
          console.error(a_event.error);
        }
      }
    });

    application.getRouter().add([
      {
        route:      "",
        controller: "fos:NServer/NControllers/Tmpl.js",
        source:     "templates/page.tmpl",
      },
      {
        route:      "/css/*",
        controller: "fos:NServer/NControllers/File.js",
        source:     "css",
      },
      {
        route:      "/templates/*",
        controller: "fos:NServer/NControllers/File.js",
        source:     "templates",
      },
      {
        route:      "favicon.ico",
        controller: "fos:NServer/NControllers/File.js",
        source:     "favicon.ico",
      },
    ]);

    application.initialize();

  }
});

Теперь давайте разберемся с содержимым файла application.js

Мы отключили все пакеты, за их ненадобностью (параметр packages метода setSettings):

 ...
    application.setSettings({
      port:                       3001,
      packages:                   [],
      dynamicLoading:             true,
      clientRenderingMode:        "client",
...

Новый для нас параметр приложения clientRenderingMode, отвечает за тип рендеринга на клиенте и имеет два значения:

«client» — рендеринг выполняется полностью средствами браузера. Клиент самостоятельно подгружает зависимости и выполняет FSQL запросы к серверу, после чего собирает сам HTML

«server» — клиент выполняет запрос к серверу на рендеринг шаблона и получает в качестве ответа готовый HTML

      ...
      packages:                   [],
      dynamicLoading:             true,
      clientRenderingMode:        "client",
      dataClient: {
        defaultConnection: "default",
      ...

И последнее для нас новшество — это подключение базы данных на файле. Фреймворк не может полноценно работать без возможности обработки конфигурационных переменных, которые имеют табличную структуру. Поэтому, взамен MYSQL мы будем использовать обычный файл.

...
        defaultConnection: "default",
        connections: {
          default: {
            type: "file",
            file: "data.fosdb"
          }
        },
      },
...

Как видно из вышеприведенной выдержки, в этом случае тип базы данных (параметр type) равен «file», а единственный параметр соединения file должен содержать путь к файлу данных. Если файл отсутствует, приложение самостоятельно его создаст.

Создание шаблона страницы


Теперь пришло время создать файл шаблона страницы приложения templates/page.tmpl, который у нас прописан в корневом маршруте URL.

//~OPTIONS
{
  args:{
    fosInclude: ["css/styles.css"],
  }
}


//~BLOCK main default
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8"/>
    %{{ render.renderHTMLHeader(); }}%
    <script>
    function onClientSideRendering(a_event){
      a_event.preventDefault();
      fos.application.render({
        template: "templates/window.tmpl",
        owner: document.body,
        args: { title: "Client side rendering", context: "Simple example of client side rendering" },
        onResult: function(a_error, a_template){
        }
      });
    }
    function onServerSideRendering(a_event){
      a_event.preventDefault();
      fos.application.render({
        template:   "templates/window.tmpl",
        owner:      document.body,
        renderMode: "server",
        args: { title: "Server side rendering", context: "Simple example of server side rendering" },
        onResult: function(a_error, a_template){
        }
      });
    }
    </script>
  </head>
  <body>
    <div class="mainwrapper">
      <div class="header markup">
        Client Side Rendering
      </div>

      <div class="body-wrapper markup">
        <div class="body markup">
          <p class="example-link--container"><a onclick="onClientSideRendering(event);">Client side rendering</a></p>
          <p class="example-link--container"><a onclick="onServerSideRendering(event);">Server side rendering</a></p>
        </div>
        <div class="clear-body"></div>
      </div>
    </div>
  </body>
</html>

Шаблон страницы имеет две ссылки «Client side rendering» & «Server side rendering». При нажатии на которые будут отображаться окна, которых пока нет. Но есть код их вызова. И так давайте разберемся с кодом шаблона.

При нажатии на ссылку «Client side rendering» мы вызываем функцию onClientSideRendering(), которая выполняет рендеринг шаблона «templates/window.tmpl». Полностью на стороне клиента, т.к. в настройках приложения параметр clientRenderingMode был установлен в значение «client». Не смотря на то, что это значение по умолчанию :-).

function onClientSideRendering(a_event){
  a_event.preventDefault();
  fos.application.render({
    template: "templates/window.tmpl",
    owner: document.body,
    args: { title: "Client side rendering", context: "Simple example of client side rendering" },
    onResult: function(a_error, a_template){
    }
  });
}

Собственно метод render и выполняет рендеринг нашего окна и помещает его в тело страницы, как указано в свойстве аргумента owner. В шаблон окна мы передаем 2-а аргумента: title & context, собственно то, что будет отображаться в выводимом окошке. Более подробную информацию о методе см. fos::NClient::Application::render

Вторая ссылка вызывает функцию onServerSideRendering(), которая аналогично рендерит тот же шаблон, но на стороне сервера, а клиент получает уже готовый HTML. Данный режим задается в свойстве аргумента renderMode метода render значением «server».

function onServerSideRendering(a_event){
  a_event.preventDefault();
  fos.application.render({
    template:   "templates/window.tmpl",
    owner:      document.body,
    renderMode: "server",
    args: { title: "Server side rendering", context: "Simple example of server side rendering" },
    onResult: function(a_error, a_template){
    }
  });
}

Создание шаблона всплывающего окна и написание враппера шаблона


Сам шаблон всплывающего окошка очень прост. Создайте файл templates/window.tmpl. Ниже приведено его содержимое.

//~OPTIONS
{
  args:{
    fosWrapper: true,
    fosClass:   "window",
    fosInclude: ["css/window.css"],
    title:       "",
    context:     "",
  }
}

//~BLOCK main default
<div class="window-container">
  <div class="window-close" name="close">x</div>
  <div class="window-title">${{args.title}}$</div>
  <div class="window-context">${{args.context}}$</div>
</div>

Здесь для вас есть два новых параметра fosWrapper и fosClass.

Начнем с fosWrapper. Если данный флаг установлен в true, то HTML шаблон помещается в контейнер span и для него создается объект обертки fos::NRender::Wrapper.

Запустите приложение, перейдите по адресу localhost:3001 и выполните клик по ссылке «Client side rendering». Всплывающие окошко и есть наш шаблон. Всплытие окна реализовано полностью средствами css (файл css/window.css) — это я просто упомянул, что бы вы не искали скрытый JS :-).

Откройте DevTools браузера (Ctrl+Alt+i), перейдите на вкладку Elements и рассмотрите структуру нашего окошка.

image

Синей линией на рисунке помечен наш оберточный контейнер span c которым связан объект fos::NRender::Wrapper.

Следующий системный аргумент шаблона — fosClass. Он просто добавляет CSS класс к span контейнеру враппера.

И так, все сделано хорошо, но если мы попробуем закрыть наше всплывающие окошко, то ничего у нас из этого не выйдет. Да, операцию закрытия мы еще не писали!

Как мы говорили ранее, если системный аргумент fosWrapper равен true, то для шаблона создается объект враппера fos::NRender::Wrapper. Он предоставляет штатный интерфейс взаимодействия с шаблоном на клиенте. Что бы переопределить штатный враппер для шаблона достаточно создать модуль с именем соответствующему следующему формату [НАИМЕНОВАНИЕ_ШАБЛОНА].wrapper.js, при этом модуль должен быть унаследован от класса fos::NRender::Wrapper.

Теперь создадим файл врапера для шаблона templates/window.tmpl. Новый класс должен будет закрывать наше всплывающие окошко, при нажатии на символ «x».

Файл templates/window.wrapper.js:

fos.module({
  name: "templates/window.wrapper.js",
  dependencies: ["fos:NRender/Wrapper.js"],
  module: function(Wrapper){
    return function(a_initializeOptions) {
      var self = this;
      Wrapper.call(this, a_initializeOptions);

      var parentAttach = this._attach;
      this._attach = function(a_cb) {
        parentAttach.call(this, function(){
          fos.addDomListener(fos.select(self.getDomElement(), "[name=close]")[0], "click", function(){
            self.getDomElement().classList.add("window-hide");
            setTimeout(function() { self.destroy(); }, 2000);
          });
          a_cb();
        });
      }

    }
  }
});

Разберем содержимое нашего модуля. Сначала мы подключаем базовый класс fos::NRender::Wrapper и наследуемся от него через методом call.

fos.module({
  name: "templates/window.wrapper.js",
  dependencies: ["fos:NRender/Wrapper.js"],
  module: function(Wrapper){
    return function(a_initializeOptions) {
      var self = this;
      Wrapper.call(this, a_initializeOptions);
      ...

После переопределяем метод fos::NRender::Wrapper::_attach, который вызывается при связывании шаблона с объектом. В данном методе мы будем подключать событие нажатия на ссылку закрытия окна. Переопределение выполняется просто объявлением метода, но в начале мы должны сохранить ссылку на родительскую реализацию. Метод имеет «асинхронную природу», поэтому реализацию наших действий мы помещаем в функцию обратного вызова родительской реализации.

  ...
      var parentAttach = this._attach;
      this._attach = function(a_cb) {
        parentAttach.call(this, function(){
          fos.addDomListener(fos.select(self.getDomElement(), "[name=close]")[0], "click", function(){
            self.getDomElement().classList.add("window-hide");
            setTimeout(function() { self.destroy(); }, 2000);
          });
          a_cb();
        });
      }
      ...

Подключение к событию нажатия на символ «x» мы выполняем вызовом fos::addDomListener, который не сбрасывает подключенные события при смене родителя DOM элемента.

В обработчике события мы и выполняем закрытие окна. Вначале красиво убираем окошко с экрана, добавлением CSS класса «window-hide». После завершения анимации вызываем метод fos::NRender::Wrapper::destroy, который удаляет шаблон и объект враппера.

ВСЁ ПРИЛОЖЕНИЕ НАПИСАНО, ЗАПУСКАЕМ И РАДУЕМСЯ!!!

node application.js

Официальный сайт разработки

Ссылка на пример
Теги:
Хабы:
Всего голосов 12: ↑10 и ↓2+8
Комментарии9

Публикации

Истории

Работа

Ближайшие события