Javascript-форум (https://javascript.ru/forum/)
-   Ваши сайты и скрипты (https://javascript.ru/forum/project/)
-   -   Snakeskin (https://javascript.ru/forum/project/35057-snakeskin.html)

Gozar 17.06.2015 14:22

Не нашёл в wiki, у snakeskin есть callback из скрипта, а ля Snakeskin(tpl, callback) или что-то типа Snakeskin.compile.then? Чтобы вызывался после активации DOM в шаблоне. callback в шаблоне не понял что делает.

Сейчас использую Snakeskin.hash[tplName] для рендеринга шаблона в DOM, так подключать нормально? в wiki тоже не нашёл описания про это.

Использую es6, про это тоже в вики немногословно.

Скомпиленные шаблоны подключены в header> menu.ss.js ... и т.д.

Если я что-то не нашёл, то просьба ткнуть носом или пояснить.

kobezzza 17.06.2015 18:19

Не совсем понял, что ты хочешь сделать. Ты имеешь ввиду, можно ли, чтобы результат шаблона отдавался по колбеку, а не сразу?

Цитата:

Сейчас использую Snakeskin.hash[tplName] для рендеринга шаблона в DOM, так подключать нормально? в wiki тоже не нашёл описания про это.
?

foo.ss

{template foo()}
    Hello World!
{/}


index.js

console.log(foo()); // Hello World!


Если не хочется писать в глобалспейс, то просто добавляем шаблону неймспейс, например tpls.foo

Цитата:

Использую es6, про это тоже в вики немногословно.
А что именно нужно? В SS7 появится поддержка некоторых ES6 фич, но врятли ты про это.

{void foo(...args)}

Gozar 17.06.2015 19:02

Цитата:

Сообщение от kobezzza
Ты имеешь ввиду, можно ли, чтобы результат шаблона отдавался по колбеку, а не сразу?

Я написал обертку, с помощью которой я монтирую шаблон в DOM, а когда он вставлен и отображается в браузере делаю с ним разные действия, скрытие, показ и т.д. Типа onload на img.

Типа как тут:
insertTplIntoDOM('menu').then(function(){
//плавно скрываем первый элемент и уже точно известно, что элемент примонтирован и к нему есть доступ.
});

//где 'menu' это Snakeskin.hash['menu']


В принципе у меня обертка есть, я просто подумал, может есть из коробки. Или меня уже глючит и все вставляемые элементы уже доступны мгновенно после innerHTML=tpl?

Цитата:

Сообщение от kobezzza
А что именно нужно?

Мне пришлось гадать как подключить шаблоны в проект es6, оказалось я так понял никак, вернее также как и в es5, в <head><script snakeskin.js></head>

а в скрипте Snakeskin.hash[tplName] - тут получаем доступ к шаблону

Цитата:

Сообщение от kobezzza
не хочется писать в глобалспейс, то просто добавляем шаблону неймспейс, например tpls.foo

На этом месте я просто не понимаю, мозг не понимает без примера. Как подключать Snakeskin, что такое tpls в tpls.foo. tpls.foo это название шаблона?

{template tpls.foo()}
    Hello World!
{/}


Как вообще не писать в глобал? Snakeskin.hash[tplName] - это разве не локал?

kobezzza 17.06.2015 20:45

Цитата:

Или меня уже глючит и все вставляемые элементы уже доступны мгновенно после innerHTML=tpl?
Конечно.

Цитата:

Мне пришлось гадать как подключить шаблоны в проект es6, оказалось я так понял никак, вернее также как и в es5, в <head><script snakeskin.js></head>
Для подключения скомпиленого шаблона можно использовать CommonJS, AMD и экспорт в глобал спейс.

https://github.com/SnakeskinTpl/Snak...world.ss.js#L6

Вот тут можно глянуть код после компиляции и увидеть логику.

Цитата:

Snakeskin.hash[tplName] - тут получаем доступ к шаблону
Да, так можно, только поправочка: Snakeskin.cache.

Цитата:

На этом месте я просто не понимаю, мозг не понимает без примера. Как подключать Snakeskin, что такое tpls в tpls.foo. tpls.foo это название шаблона?
Всё очень просто :)

{template foo()}
{/}


Тоже самое, что и

function foo() {
}


А

{template bar.foo()}
{/}


Тоже самое, что и

if (typeof bar === 'undefined') {
    var bar = {};
}

bar.foo = function foo() {
};


Неймспейс может называться как угодно и иметь любую вложенность, можно использовать точечную и скобочную нотацию: логика идентичная с JS.

{var fffuuu = 121}
{template car.bar['someStr' + fffuuu]foo()}
{/}


Можно ставить шаблоны, как методы JS класса

{template MyWidget.prototype.tpl()}
{/}


Цитата:

Как вообще не писать в глобал? Snakeskin.hash[tplName] - это разве не локал?
Использовать CommonJS или AMD. Логика такая: если есть exports, то шаблоны экспортируются туда, если есть функция define со свойством amd, то используется AMD, т.е. шаблон сам подстраивается под окружение.

Ещё можно просто обернуть полученный JS код функций и задать нужный this. Для таких задач удобно использовать конвеер сборки gulp/grunt с плагином wrap.

PS: отмечу, что в SS7 весь этот механизм значительно улучшен, например появилась поддержка runtime модулей и можно явно задать тип экспорта шаблонов.

{@= export 'es6'}
{import { getUserData } from './myLib.js'}

{template foo() @async}
   {forEach await getUserData() => @el}
       {@name} - {@age}
   {/}
{/}

Safort 17.06.2015 21:54

Цитата:

Сообщение от kobezzza (Сообщение 375519)
PS: отмечу, что в SS7 весь этот механизм значительно улучшен, например появилась поддержка runtime модулей и можно явно задать тип экспорта шаблонов.

{@= export 'es6'}
{import { getUserData } from './myLib.js'}

{template foo() @async}
   {forEach await getUserData() => @el}
       {@name} - {@age}
   {/}
{/}

О, офигенно!

kobezzza 20.06.2015 11:50

Одна из важнейших фич SS7 будет открытость API парсера, т.е. сам пользователь сможет расширять язык своими директивами и поэтому я потратил кучу времени на рефакторинг существующего API и в итоге получился на мой взгляд очень простой, но в тоже время мощный интерфейс, вот например директивы switch-case-default на новом API:

import { Snakeskin } from '../core';

Snakeskin.addDirective(
	'switch',

	{
		block: true,
		notEmpty: true,
		inside: Snakeskin.group('case')
	},

	function (command) {
		this.append($=> `switch (${this.out(command, {sys: true})}) {`);
	},

	function () {
		this.append('}');
	}

);

Snakeskin.addDirective(
	'case',

	{
		block: true,
		notEmpty: true,
		group: 'case',
		replacers: {
			'>': 'case ',
			'/>': 'end case'
		}
	},

	function (command) {
		this.append($=> `case ${this.out(command, {sys: true})}: {`);
	},

	function () {
		this.append('} break;');
	}

);

Snakeskin.addDirective(
	'default',

	{
		block: true,
		group: 'case'
	},

	function () {
		this.append('default: {');
	},

	function () {
		this.append('}');
	}

);


Как вам?

Gozar 20.06.2015 22:41

Цитата:

Сообщение от kobezzza
Как вам?

Побольше примеров и хорошая документация, в остальном я хз, что оно делает :D.

Я пока из ss6 использую 40% и ума не приложу зачем мне больше, поэтому вряд ли буду полезен.

Для меня главное дока и предсказуемое поведение, в остальном пиши хоть "справа налево".

Gozar 22.06.2015 10:18

Как вставить код скрипта, вместе с тегами script в шаблон, чтобы парсер не ругался?

cdata, data, ругается, мол ошибка. Почему?

Gozar 22.06.2015 10:30

Оо, нашёл. Честно говоря решётку не заметил, думал это коммент, автоматом воспринимаю в конфигах...

#{cdata}

А тогда такой вопрос, а зачем тут решётка? Был хитрый план по на будущее? :)

kobezzza 22.06.2015 23:30

Цитата:

Как вставить код скрипта, вместе с тегами script в шаблон, чтобы парсер не ругался?
Для этой задачи в SS существует расширенный синтаксис: https://github.com/kobezzza/Snakeski...%D0%B8%D 1%81

Логика простая: когда ты начинаешь юзать #{...} для декларации директивы, то все вложенные директивы также будут требовать такую декларацию, например:

{template foo()}
  #{script}
    var a = {
      bar: #{1 + 2}
    };
  #{/}
{/}


Цитата:

data
Эта директива для inline вставок, например,

{template foo()}
  <input type="button" onclick="{data console.log({foo: 1})}">
{/}


Цитата:

А тогда такой вопрос, а зачем тут решётка? Был хитрый план по на будущее?
CDATA работает до построения AST, чисто вырезается по регулярке и поэтому я сделал обязательным расширенный синтаксис директивы для использования, чтобы случайно не выстрелить себе в ногу.

Цитата:

Оо, нашёл. Честно говоря решётку не заметил, думал это коммент, автоматом воспринимаю в конфигах...
В SS комменты обозначаются через

/// Однострочный коммент
/* Многострочный коммент */
/** JSDoc (не вырезается парсером из конечного кода) */


Для создания XML комментариев есть удобная директива comment, которая также поддерживает условия для старых ИЕ.

{template foo()}
  {comment IE 7}
    {link}http://bar.com/ie.css{/link}
  {/}
{/}


Но также можно просто писать по старинке :)

PS: По поводу однострочных комментов: есть сильное желание заменить в SS7 на //# (или ещё как), т.к. сейчас можно напороться на ошибку при подключение некоторых урлов:

<a href="file:///C://foo.png">121</a>


Т.е. нужно явно экранировать:

<a href="file://\/C://foo.png">121</a>


Забавно, что я сделал коммент как /// чтобы не напарываться на такие ошибки с //, но не учёл, что урлы с тремя слешами тоже бывают :(

Gozar 06.07.2015 14:56

У меня такой вопрос, я подключаю в node шаблон так:

var tpl = require('../tpl/menu.ss.js').init(require('snakeskin'));
tpl.menu([{item: '', item: ''}]);


Но если один и тот же шаблон подключается в двух разных файлах, то кидается ошибка. Это потому что подключение глобальное или почему?

Как правильней организовать подключение шаблонов в проекте на сервере если шаблон используется в разных файлах?

kobezzza 06.07.2015 15:40

Не понял где ошибка, напиши подробнее.

Gozar 06.07.2015 19:54

Цитата:

Сообщение от kobezzza
ошибка

Ошибки нет если это один файл:
menu.js

но если так подключить в двух
menu.js
menu2.js

То появляется ошибка.

kobezzza 06.07.2015 21:30

Проверил дома, действительно есть баг, сейчас сделаю патч.

UPD: патч 6.6.5 выложен в NPM, спасибо за репорт.

kobezzza 07.07.2015 12:12

Забыл сказать, что для исправления баги нужно перекомпилить шаблоны пропатченой версий SS.

cyber 05.08.2015 11:51

kobezzza, я не совсем пойму как сделать, мне нужно сгенерить js файл через gulp
что в таком формате:
require.config({
    waitSeconds: 60,
    paths: <%= map.paths %>,
    shim: <%= map.shim %>
});

я искал что то подобное в доке но не нашел, можно так?

kobezzza 05.08.2015 12:33

cyber, не совсем понял, что ты хочешь. Раз ты задаешь вопросы в треде SS, то ты хочешь понять, как сгенерить JS файл через SS и gulp?

config.ss
# template config(@map)
  require.config({
    waitSeconds: 60,
    paths: #{@paths|json},
    shim: #{@shim|json}
  });


gulpfile.js
var gulp = require('gulp'),
      ss = require('gulp-snakeskin')

gulp.task('config', function () {
  gulp.src('./config.ss')
    .pipe(ss({exec: true, data: {paths: [ ... ], shim: [ ... ]}}))
    .pipe(gulp.dest('./config.js'));
});


Как то так.

cyber 05.08.2015 12:36

Цитата:

Сообщение от kobezzza
то ты хочешь понять, как сгенерить JS файл через SS и gulp?

да, спасибо за пример
Не получилось за юзать вебпак, так как ты писал, сильно много менять, приходится подстраивается под то что есть)

kobezzza 05.08.2015 12:53

Цитата:

Сообщение от cyber (Сообщение 382811)
да, спасибо за пример
Не получилось за юзать вебпак, так как ты писал, сильно много менять, приходится подстраивается под то что есть)

Бывает :)

Если нужна гибкая сборка файлов без привязки к языку или фреймворку, то рекомендую мой другой проект: https://github.com/MonicBuilder/Monic

cyber 05.08.2015 12:55

kobezzza, уже использую давно
https://github.com/cyberua/multiPopu...rc/popup.js#L8

MakeMeFeel 09.09.2015 14:37

а как экранировать вывод html кроме <br>? например: есть текст и в нем \n переносы строк, если написать так:
{content|br}, то вместо <br> мы получим &lt;br&gt;

отэкранируются все символы, а нужно все, кроме <br>

MakeMeFeel 09.09.2015 14:42

если написать так:
{content|br|!html}
то получится натуральная XSS

Что нужно написать в фильтр, чтобы не получить дыру в сайте и переводить строку?

trikadin 09.09.2015 15:22

MakeMeFeel,
- block tpl->outputWithBr(text)
  : paragraphs = text.split('\n')
  - forEach paragraphs -> p
    {p}
    < br

trikadin 09.09.2015 15:25

Ну и, соответственно, создаёшь темплейт tpl, где и юзаешь активно этот блок)

trikadin 09.09.2015 15:28

А правильно, конечно, вот так:

- block tpl->p(text)
  : paragraphs = text.split('\n')
  - forEach paragraphs -> p
    < p
      {p}

MakeMeFeel 09.09.2015 16:16

trikadin,
это весь текст нужно отпарсить, что это за жесть?

Сначала применяем фильтр на html, а затем грабли на перевод строки? Проще тогда дрюкать в браузере пользователя, чтобы сервер не упарывать.

Механизма встроенного, порядка фильтров например, нету? типа как в php nl2br?

, а и спасибо за пример.

trikadin 09.09.2015 16:21

MakeMeFeel, эээм, в чём проблема? Где нужно отпарсить какой текст? Не понял тебя)

MakeMeFeel 09.09.2015 16:26

Цитата:

Сообщение от trikadin
эээм, в чём проблема?

Наверное в том, что это какой-то дикий костыль.

вместо записи: {content|nl2br} ты предложил писать весь твой код в блоке.

Как минимум нужно запихать твой код в фильтр. Но мне интересно, есть ли встроенных nl2br? чтобы его не писать. Для меня странно, что его нет или я что-то упустил?

Я уж не говорю о том, что ты навязываешь мне использование тега p

MakeMeFeel 09.09.2015 16:29

Страннее всего, что нет html2br, экранировать всё, а переносы гнать в <br>

trikadin 09.09.2015 16:31

MakeMeFeel, если тебе принципиально сделать это фильтрами, то легко:

{text |html |replace '\n', '<br>' |!html}


Но это плохой вариант.

MakeMeFeel 09.09.2015 16:36

Цитата:

Сообщение от trikadin
Но это плохой вариант.

почему? выглядит короче и читабельней

trikadin 09.09.2015 16:40

MakeMeFeel, при выводе текста разбить его на параграфы (<p>) гораздо разумнее -- потом можно задать параграфам стили, вроде отступа первой строки и какой-нибудь заглавной буквы, расстояние между параграфами и т. д. Плюс директива tag в snakeskin работает в DOM-режиме (когда шаблон компилируется непосредственно в DOM в браузере) лучше, т. к. сразу создаёт тег через createElement() , а вариант с replace, хоть и сработает в таком режиме, но будет хуже по производительности из-за юзания innerHTML и дополнительного разбора браузером.

kobezzza 09.09.2015 16:40

Фич реквесты лучше оставлять на гитхабе, но ок, я добавлю такой фильтр в ближайшем минорном релизе SS6 на выходных.

Будет так:
data|nl2br

trikadin 09.09.2015 16:42

К тому же, может понадобиться сделать такую операцию не с одним текстом на странице, а с двумя разными -- и тут тоже гораздо логичнее сделать что-то типа callBlock p(text1), callBlock p(text2).

MakeMeFeel 09.09.2015 16:54

Цитата:

Сообщение от kobezzza
Будет так:
data|nl2br

Спасибо добрый "Санта" :)

Цитата:

Сообщение от trikadin
и тут тоже гораздо логичнее сделать

data|nl2br ;) а не плодить блоки. Чем проще, тем проще вспомнить что оно делает.

MakeMeFeel 09.09.2015 16:56

trikadin,
У меня блоки короткие и плодить в них p, ничего не даст. Один, два переноса.

MakeMeFeel 09.09.2015 16:58

Гораздо важнее поменьше кода, т.к. шаблоны и так уже довольно сложные и дополнительная логика в блоках уже начинает напрягать. А также хочется такую фичу из коробки, т.к. она и работать будет побыстрее.

kobezzza,
только если можно не забыть, что остальной части данных html фильтр должен работать :)

kobezzza 09.09.2015 17:04

Цитата:

kobezzza,
только если можно не забыть, что остальной части данных html фильтр должен работать
Ну это понятно :)

kobezzza 19.09.2015 21:29

Забыл тут написать, что вышел очередной релиз SS ветки 6. В основном багфиксы. Добавлен фильтр nl2br.

Mаxmaxmаximus 19.12.2015 08:46

Я тут новый язык шаблонов для юишки пилю, как вам пасоны? как джейд тока круче, больше придется добавлять префиксы к кастомным атрибутам так как при компиляции движок поймет что раз есть директива с таким именем то значит надо при превращении в html добавить префикс)) ну грубо говоря.

и вот в фотошопе подсветочку примерную нарисовал чтобы вы понимали структуру, все атрибуты желтые а точ то до конца строки это просто значение атрибута, строковое, а то как его парсить будет уже решать сам атрибут, ну все как в ангуляре




А вот как бы это было написано на jade например




Правда еще префиксы надо добавлять чтобы не было конфликта с обычными атрибутами (вдруг потом в html10 атрибут repeat добавят), вот так щас приходится писать в jade:



СРАВНИТЕ ВОТ С ЭТИМ:




Плюс, раз уж я буду писать плагин для подсветки синтаксиса то потом вполне научу идешку подсвечивать атрибуты которые кастомные каким-то особым цветом.

кстати messages in Message или message in @messages это обычные строки синтаксис которых не определен, там могло быть написано хоть "апывавпаав 434 334 34 34", и директива repeat или range например должна была бы быраспарсить эту строгу и выдернуть нужное) как щас она делает со строкой message in @messages

создатель директивы сам решает че туда передавать и в каком формате, но я заготовил пару парсеров для выражений через запятую типа name, 1+2, 33 он распарсит эту строку в массив, ну парсинг частого выражения name as val in arr которое во всяких итераторах используется тоже добавил, можно будет свои пресеты выражений создавать и вообще я думаю это дело как-то стандартизировать чтобы потом можно было подсветку выражений организовывать. все таки это же не просто строки а какой то код и он чето делает.

потому шо я могу организовать подсветку в подстановках {{1+2}} потому что там банальный кофескрипт. А вот строку которую мы в атрибут передаем, которая тоже мини логику несет, я как то не стандартизировал.


А еще я хочу добавить че-то типа дубликатов атрибутов, ну знаете часто хочется это сделать в коде



И будет например если дублируется обычный атрибут то при рендере все значения просто сложатся и разделятся пробелом ну в случае с class например пригодится.

А если же это кастомный какой-то атрибут то я хочу чтобы туда какая-то функция вызывалась чтоле, то есть чтобы он конструировался один раз, но какая то функция типа init вызывалась несколько раз с разными значениями)) удобно? Удобно.

Например кастомный атрибут add-class будет парсить строку регуляркой типа вначале слово название класса, потом двоеточие, а потом до конца строки выражение которое будет отслеживаться в скоупе на изменения и.т.п.

и вот эта логика опишется в функции init и эта функция вызовится несколько раз с разными значениями атрибута)

Ребят по моему это вообще прорыв и это самый лучший шаблонизатор который я видел.

Кто знает как на атрибутах красиво сделать свитч? я вот уже 3 года не знаю как придумать))). Или раз уж у нас свой синтаксис теперь то может какую нить хитрую конструкцию придумаем?

А еще думаю может чето типа таких логическх псевдоблоков запилить? а то логику в атрибутах элементов не всегда удобно писать. когда что то вроде "примени для этого элемента эту штуку" да, самое то, типа как настройки элемента. но когда это логика связанная именно С РАЗМЕТКОЙ карл. Тут нужно что-то ВНЕ блоков.



Че думаете? А при рендеринге я буду рендерить это в какие-то хитрые html комментарии которые че-то делают.

Ну или вот лучше так, вначале реализую стандартные компоненты которые логику реализуют, а потом шаблон просто буду вн их компилить, шаблон вообще это сахар по сути над декларативным html и все что мы пишем в шаблоне должно быть можно написать без шаблона используя чистый html (ну в данном случае я для простоты на джейде написал пример)



То есть текущий API уже позволяет реализовать такую логику, просто ужасно смотрится по этому я и не делал такое, но по сколкьу пилим шаблонизатор... ;)


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


А вообще, по скольку я создам компоненты на все свойства которые есть в style тогда можно будет писать вот так


и это вообще сказка)
прям как в css прикиньте)) тока динамически подвязка к яваскрипту.

при компиляии заменится на уже работающие сейчас
<ul class='ui-chat ui-button ui-text' style-position='absolute' style-width='100px' style-height='{{@height}}px'>


Часовой пояс GMT +3, время: 21:21.