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