«Friendly Open Space» — очень молодой фреймворк, но бегать уже умеет :-)
В данной статье по освоению «Friendly Open Space», мы освоим рендеринг шаблона в браузере и запуск приложения на локальной файловой БД.
Ядро фреймворка поддерживает два типа сборки шаблона на клиенте:
- Рендеринг полностью выполняется на стороне клиента
- Выполняется запрос на рендеринг шаблона серверу, с последующим выводом его в окне браузера.
Первый режим имеет одну особенность, данные необходимые для отрисовки шаблона запрашиваются у сервера, т.е. клиент выполняет 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 и рассмотрите структуру нашего окошка.

Синей линией на рисунке помечен наш оберточный контейнер 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
Официальный сайт разработки
Ссылка на пример
