Сохранение данных на сервере и файлы *.receive.js

Помимо задач рендеринга, шаблоны могут выполнять задачи на стороне сервера. Данный функционал реализован при помощи обработчика на стороне сервера, предоставляемым файлами *.receive.js. Вызов обработчика выполняется вызовом метода fcf.NClient.Wrapper.send. Его сигнатура имеет следующий вид:

fcf.Actions->mixed fcf.NClient.Wrapper.send(object a_data, array[FileList|DomElement{input type=file}] a_files = undefined).

Метод вызывает на стороне сервера обработчик и асинхронно возвращает результат его исполнения. Используя данный метод можно передавать, как данные, так и файлы в виде массива объектов FileList или input элементов имеющих тип file.

Обработчик шаблона на стороне сервера [TEMPLATE_NAME].receive.js имеет следующий вид.

fcf.module({ name: "templates/blocks/moving-containers.receive.js", dependencies: [], lazy: [], module: function() { return class Handler { receive(a_data, a_files){ } } } });

Как видно из выше приведенного кода, модуль поставляет класс обработчика с одним обязательным методом receive. Который принимает два аргумента, соответствующих аргументам метода fcf.NClient.Wrapper.send. Аргументы метода receive:

  • mixed a_data - Данные переданные методом fcf.NClient.Wrapper.send
  • array[object] a_files - Массив объектов, хранящих информацию о переданных файлах. Каждый объект имеет следующие поля:
    • integer size - Размер файла.
    • string path - Путь к файлу.
    • string name - Имя файла на стороне клиента.
    • string type - MIME тип.
    • object attributes - Объект со значениями атрибутов input элемента на стороне клиента.

Результат исполнения метода receive возвращает метод fcf.NClient.Wrapper.send.

Теперь допишем в наше приложение возможность сохранения конфигурации на стороне сервера.

Добавим кнопку для сохранения конфигурации.

Файл :templates/blocks/moving-containers.tmpl

... //~TEMPLATE <div class="moving-containers-view" style="background-image: url(@{{args._file}}@);"> <div class="moving-containers-view-info"> Rebound counter: <span name="rebound_counter">#{{args._reboundCounter}}#</span> </div> %{{ for(let i = 0; i < args._strings.length; ++i) { }}% @{{ render.template( "+view-item", { string: fcf.argRef(`_strings[${i}]`), fcfEventRebound: "parent.onReboundString(event)" })}}@ %{{ } }}% </div> <fieldset> <legend>Editor</legend> @{{ render.template("@controls:tabs", { items: fcf.argVal({ strings: { title: "Strings", data: fcf.argTmpl("+strings", {strings: fcf.argRef("_strings")}) }, settings: { title: "Settings", data: fcf.argTmpl("+settings") } }) }); }}@ @{{ render.template("@controls:button", {title: fcf.t("Save"), fcfEventClick: "parent.onSave()"}); }}@ </fieldset> ...

И добавим обработчик события onSave в код основного враппера.

Файл :templates/blocks/moving-containers.wrapper.js

fcf.module({ name: "templates/blocks/moving-containers.wrapper.js", dependencies: ["fcf:NClient/Wrapper.js"], module: function(Wrapper){ return class WrapperImpl extends Wrapper{ constructor(a_initializeOptions) { super(a_initializeOptions); } onRemoveString(a_index) { let strings = this.getArg("_strings"); strings.splice(a_index, 1); this.setArg("_strings", strings); this.update(); } onAddString() { let strings = this.getArg("_strings"); strings.push("") this.setArg("_strings", strings); this.update(); } onFile() { let self = this; let fileReader = new FileReader(); fileReader.onload = () => { self.setArg("_file", fileReader.result); self.update(); } fileReader.readAsDataURL(this.select("input[type=file]")[0].files[0]); } onSave() { this.send({strings: this.getArg("_strings")}, [this.select("input[type='file']")[0]]); } }; } });

Осталось только сохранить данные на стороне сервера

Файл templates/blocks/moving-containers.receive.js

const libFS = require('fs'); const libUtil = require('util'); fcf.module({ name: "templates/blocks/moving-containers.receive.js", dependencies: [], lazy: [], module: function() { return class Handler { async receive(a_data, a_files){ if (a_data.strings) { await fcf.application.setSystemVariable("application:strings", a_data.strings); } if (a_files[0]) { await libUtil.promisify(libFS.copyFile)(a_files[0].path, fcf.getPath(":files/background.jpg")); } } } } });

Теперь можно посмотреть, как все это работает