
Начало пути капитана $mol’a! Шта?..
Здравствуйте, меня не зовут Дмитрий Карловский и я… решил написать простенькие заметки на $mol в несколько итераций:
0. Настраиваем рабочее окружение MAM
парой команд — это делается один раз под все проекты:
git clone https://github.com/hyoo-ru/mam.git cd mam npm install
Запускаем дев сервер:
npm start
Он заиграет на 9080 порту http://127.0.0.1:9080, а нам можно начинать смолить..
Возводим скелет
Создаём наш проект: в склонированной папке mam создаем папки habr/notes
В нём создём точку входа habr/notes/index.html:
<!doctype html> <html mol_view_root> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, height=device-height, initial-scale=1"> </head> <body mol_view_root> <div mol_view_root="$habr_notes"></div> <script src="web.js" charset="utf-8"></script> </body> </html>
Заметили $habr_notes? Тут везде fqn обращения (имя = путь), а в mol_view_root мы указываем наше приложение. Точнее, компонент — здесь это одно и то же по смыслу, только мы можем вкладывать компоненты друг в друга и делегировать/рекомпозировать/хакать их свойства между собой.
Что же, создадим сам компонент habr/notes/view.tree:
- это комментарий, ах да, следим за табами $habr_notes $mol_page
Шпаргалка по синтаксису и страшная статья о view.tree
В браузере можем перейти по адресу http://127.0.0.1:9080/habr/notes и увидим зачаток нашего приложения:

Придадим форму, подправив файл view.tree:
- мы отнаследовали $habr_notes от $mol_page $habr_notes $mol_page - в свойство body мы положили массив / body / - в этот массив мы вложили компонент $mol_textarea и назвали его Input <= Input $mol_textarea
О, теперь у нас появилось текстовое поле ввода:

Но наш введенный текст теряется при обновлении страницы, давайте это изменим.
Сохраняемся…
в localStorage
Подправим наш view.tree файл до такого содержания:
$habr_notes $mol_page body / <= Input $mol_textarea - переопределяем наше свойство value value?val <=> text?val \
подробнее про свойства компонента $mol_textarea туть
Собственно на этом момент можно уже начать задаваться вопросом какого черта тут происходит и зачем нужны эти view.tree файлы.
view.tree — это DSL, транслирующийся в ts.
Пример выше преобразится в такой код:
namespace $ { export class $habr_notes extends $mol_page { /** * ```tree * body / <= input * ``` */ body() { return [ this.Input() ] as readonly any[] } /** * ```tree * text?val \ * ``` */ @ $mol_mem text(val?: any) { if ( val !== undefined ) return val as never return "" } /** * ```tree * Input $mol_textarea value?val <=> text?val * ``` */ @ $mol_mem Input() { const obj = new this.$.$mol_textarea() obj.value = (val?: any) => this.text(val) return obj } } }
Вы можете сами поиграться в песочнице.
Зачем он нужен? Для разделения мух и котлет.
С помощью view.tree мы декларативно описываем наш интерфейс.
С помощью view.tree.ts мы императивно описываем работу самой логики.
Из view.tree сборщик сгенерировал шаблонный код в файл habr/notes/-view.tree/view.tree.ts.
При обновлении view.tree файла, файл выше обновляется сам.
Зачем он нужен? Для переопределения!
Можем заметить, что код выше сгенерировался в неймспейсе $.
Свою логику мы будем описывать в неймспейсе $.$$ — то есть, «перекрывая» своей логикой.
Вернёмся же к нашему коду.
Создаём файл habr/notes/view.tree.ts:
namespace $.$$ { export class $habr_notes extends $.$habr_notes { @ $mol_mem text(val?: any) { if ( val !== undefined ) return val as never return "" } } }
Тут я перенёс text(val?: any) — функция-заглушка, сгенерированная из view.tree файла с навешенным декоратором @ $mol_mem (от memoization)
Это канал — он возвращает значение, при вызове его без параметра, а при вызове с параметром он указывается в качестве значения.
Почему оно работает?
Мы открыли наше приложение, поле ввода запросило значение из функции text, функция text вернуло пустую строку.
Мы ввели первый символ, в функцию text передалась нажатая клавиша, функция text сохранила её.
Мы вводим последующие символы, они запоминаются и результат функции text возвращается в поле ввода.
Ага, значит сюда и можно подвязать сохранение данных в localStorage.
В $mol есть модуль $mol_state_local — реактивная обертка над localStorage — ей и воспользуемся:
namespace $.$$ { export class $habr_notes extends $.$habr_notes { @ $mol_mem text(val?: any) { return $mol_state_local.value('note', val) || "" } } }
Проверяем… работает! После перезагрузки страницы наш введённый текст сохраняется.

Я создал репозиторий с веткой stage-1, действия выше воспроизведены в нём — можно сравниться.
Что же, осталось научиться шариться данными!
Собственно,
Шаримся
заметками, используя децентрализованную криптографическую систему, ну а почему нет
¯\(ツ)/¯
Поправим view.tree файл:
$habr_notes $mol_page - через синк клиент мы обмениваемся данными в сети yard $hyoo_sync_client tools / - через модуль онлайна мы подключаемся к пирам и синхронизируемся <= Online $hyoo_sync_online yard <= yard body / <= Input $mol_textarea value?val <=> text?val \ enabled <= i_have_can_mod false
Опишем логику view.tree.ts:
namespace $.$$ { export class $habr_notes extends $.$habr_notes { @$mol_mem text( val?: any ) { return this.store().str( val ) || "" } @$mol_mem store() { // через модуль клиента мы обращаемся к хранилищу (миру), // используем тип $hyoo_crowd_reg - он позволяет атомарно хранить значения (строки, числа, булы) // запрашиваем участок с указанным id return this.yard().world().Fund( $hyoo_crowd_reg ).Item( this.current_note_id() ) } @$mol_mem current_note_id() { // мы считываем id заметки из урла, или, если пустой, указываем новый свой const id = this.$.$mol_state_arg.value( '' ) || this.yard().land_grab().id() // задаём в урл текущий id - чтобы мы могли его сразу же скопировать this.$.$mol_state_arg.value( '', id ) return id as $mol_int62_string } @$mol_mem i_have_can_mod() { // проверка наличия прав на редактирование return this.yard().land( this.current_note_id() ).allowed_mod() } } }
Вот как это выглядит:

Для сверки, ветка stage-2.
А может вам рюшечки?
Добавим поддержку тем тройкой строк кода:
$habr_notes $mol_page plugins / - включаем поддержку смены тем <= Theme $mol_theme_auto yard $hyoo_sync_client tools / <= Online $hyoo_sync_online yard <= yard - добавляем кнопку-переключалку <= Lighter $mol_lights_toggle body / <= Input $mol_textarea value?val <=> text?val \ enabled <= i_have_can_mod false
Вот так это выглядит:

Или ехать?
А может сделаем наше pwa offline-first?
Пфф: создаем в той же директории файл view.meta.tree:
include \/mol/offline/install
Одной строчкой мы подключили Service Worker, который закеширует наше приложение и позволит работать ему при отсутствии интернетов.
Зачем? CROWD, который мы используем, автоматически синхронизируется с внешним миром при потери и появлении интернета.
Для сверки, ветка stage-3.
Пакуемся
мы командой:
npm start habr/notes
Наш статический бандл расположится в папке habr/notes/-/ — его и можно хостить.
В ходе всех вышеописанных шагов можно заметить появившиеся папки:
-/— наш бандл-view.tree/— наш переопределяемый код
Тут продуманно, что весь генерируемый код с которым мы не взаимодействуем лежит в минусах, это сделано для упрощения работы с тем же гитом.
Например, файл .gitignore будет таков:
-*
Отвлеклись, задеплоимся на какой-нибдь фапхаб с возможностью хостить статические странички — тот же Github Pages.
Выгрузим содержимое папки - в ветку gh-pages и можем лицезреть результаты наших работ по ссылке: https://koplenov.github.io/habr-notes/#!=sxktck_j3e02v
Схожее по теме:
- https://notes.hyoo.ru/ — Ведение личных заметок с напоминаниями.
** Сорцы: https://github.com/hyoo-ru/notes.hyoo.ru - https://page.hyoo.ru/ — Сервис написания и публикации статей с совместным редактированием даже в оффлайне.
** Сорцы: https://github.com/hyoo-ru/page.hyoo.ru/ - Запись стрима, где мы делали таск менеджер и обкатывали реалтаймовость
ссылка на оригинал статьи https://habr.com/ru/articles/732934/
Добавить комментарий