$_tpl -> テンプレートエンジン::超軽量「Micro-Templating」をカスタム
$_tpl -> html文字列(nodeではない)

Micro-Templatingはすごく優秀! raw html, include, wrapを可能 <- include, wrapは、外した

var me = arguments.callee; が非推奨!! -> なしバージョンにカスタム

lodashのテンプレートエンジンと同じ変数記法が使える

ただし、挿入する変数にタグが含まれる場合は、記述を、<%=raw 変数名 %>にする。

記法の変更が簡単! -> laraabelのBladeテンプレートと統一するかを検討中

wrapは、_$(hoge).wrap($tpl,$data)でwrapできるようにしている。

includeは、別の関数を作成しているが、将来カスタムして組み込む?(SEO対策やロードバーツのJavaScript実行は?)

重要:TODO)セキュリティについての配慮:javascriptセキュリティ

Micro-Templatingのアップデート: Rick Stahl's blog


let $test = '<div id="<%=id%>" class="<%=clss%>"><%=body%></div>';
let $data = {
 id: "reingo",
 clss: "d-inline-block red text-white p-2 rounded",
 body: "hogeee!"
}
document.querySelector('#micro').innerHTML = $_tpl($test, $data);

// ---- 重要 -------
// ---- 挿入する変数にタグが含まれる場合は、記述を、<%=raw 変数名 %>にする。
let thumimg = '<img src="' + $option.pdfpath + $thum + '" class="img-fluid" data-file="' + $thum + '">';

<%=raw thumimg %>


$_tpl -> エラー時の動作

(function(){
let $test = '<div id="hogfe" class="hogera">hoge--</div>';
let $data2 = {
 id: "reingo",
 clss: "d-inline-block red text-white p-2 rounded",
 body: "hogeee!"
}
document.querySelector('#micro2').innerHTML = $_tpl($test, $data2);
}());

_$('ターゲット').wrap + $_tpl -> テンプレートでwrap <%=raw self%> 必須!!
ヘルパー関数(html文字列をNodeに変換):htmlToNode($_tpl($tpl, $data));
テスト1:データあり
テスト2:データなし(selfのみ)

let $test3 = '<div id="<%=id%>" class="<%=clss%>"><%=raw self%></div>';
let $data3 = {
 id: "reingo",
 clss: "d-inline-block red text-white p-2 rounded",
}
_$('#micro3').wrap($test3, $data3);


let $test4 = '<div class="black text-white my-3 p-2 rounded"><%=raw self%></div>';
_$('#micro4').wrap($test4);


特定文字の前後を取り出す

var str = 'abcdefghij';
// dより前の文字が欲しい
var cut1 = str.substr(0, str.indexOf('d'));
console.log(cut1);
// 結果
abc

// dより後の文字が欲しい
var cut2 = str.substr(str.indexOf('d') + 1);
console.log(cut2);
// 結果
fghij

indexOf(特定文字) 文字の位置を返す(0スタート:ないときは -1)
substr(開始位置, 終了位置)で切り出し
substr(数字)で数字から終了位置まで切り出し

Micro-Templatingの備忘録

とにかく軽い:jQueryのジョン・グレグ氏作

ほんの少しコードが増えるけど:Micro-Templating改良版

解説:Micro-Templatingをコードリーディング

//こんだけーーーーー!!!
// Simple JavaScript Templating
// John Resig - https://johnresig.com/ - MIT Licensed
(function(){
  var cache = {};

  this.tmpl = function tmpl(str, data){
    var fn = !/\W/.test(str) ?
      cache[str] = cache[str] ||
        tmpl(document.getElementById(str).innerHTML) :
      new Function("obj",
        "var p=[],print=function(){p.push.apply(p,arguments);};" +
        "with(obj){p.push('" +
        str
          .replace(/[\r\t\n]/g, " ")
          .split("<%").join("\t")
          .replace(/((^|%>)[^\t]*)'/g, "$1\r")
          .replace(/\t=(.*?)%>/g, "',$1,'")
          .split("\t").join("');")
          .split("%>").join("p.push('")
          .split("\r").join("\\'")
      + "');}return p.join('');");
    return data ? fn( data ) : fn;
  };
})();


--------------------------------------------


var _tmplCache = {}
this.parseTemplate = function(str, data) {
    var err = "";
    try {
        var func = _tmplCache[str];
        if (!func) {
            var strFunc =
            "var p=[],print=function(){p.push.apply(p,arguments);};" +
                        "with(obj){p.push('" +
            str.replace(/[\r\t\n]/g, " ")
               .replace(/'(?=[^#]*#>)/g, "\t")
               .split("'").join("\\'")
               .split("\t").join("'")
               .replace(/<#=(.+?)#>/g, "',$1,'")
               .split("<#").join("');")
               .split("#>").join("p.push('")
               + "');}return p.join('');";
            func = new Function("obj", strFunc);
            _tmplCache[str] = func;
        }
        return func(data);
    } catch (e) { err = e.message; }
    return "< # ERROR: " + err.htmlEncode() + " # >";
}

------------------------------------------------------------------------

function $_tpl(id, data) {
// var me = arguments.callee;
//arguments.calleeの使用は非推奨:廃止になるので、関数名で置き換えた
var me = $_tpl;
	if (!me.cache[id]) me.cache[id] = (function () {
		var name = id, string = /^[\w\-]+$/.test(id) ? me.get(id): (name = '$_tpl(string)', id); // no warnings
		var line = 1, $body = (
			"try { " +
				(me.variable ?  "var " + me.variable + " = this.stash;" : "with (this.stash) { ") +
					"this.ret += '"  +
					string.
						replace(/<%/g, '\x11').replace(/%>/g, '\x13'). // if you want other tag, just edit this line
						replace(/'(?![^\x11\x13]+?\x13)/g, '\\x27').
						replace(/^\s*|\s*$/g, '').
						replace(/\n|\r\n/g, function () { return "';\nthis.line = " + (++line) + "; this.ret += '\\n" }).
						replace(/\x11=raw(.+?)\x13/g, "' + ($1) + '").
						replace(/\x11=(.+?)\x13/g, "' + this.escapeHTML($1) + '").
						replace(/\x11(.+?)\x13/g, "'; $1; this.ret += '") +
				"'; " + (me.variable ? "" : "}") + "return this.ret;" +
			"} catch (e) { throw 'templateError: ' + e + ' (on " + name + "' + ' line ' + this.line + ')'; } " +
			"//# sourceURL=" + name + "\n" // source map
		).replace(/this\.ret \+= '';/g, '');
		var func = new Function($body);
		var map  = { '&' : '&', '<' : '<', '>' : '>', '\x22' : '"', '\x27' : ''' };
		var escapeHTML = function (string) { return (''+string).replace(/[&<>\'\"]/g, function (_) { return map[_] }) };
		return function (stash) { return func.call(me.context = { escapeHTML: escapeHTML, line: 1, ret : '', stash: stash }) };
	})();
	return data ? me.cache[id](data) : me.cache[id];
}
$_tpl.cache = {};
$_tpl.get = function (id) { return document.getElementById(id).innerHTML };
window.$_tpl = $_tpl;


テンプレ(記述はlodashのテンプレエンジンと同じっぽい)

<script type="text/html" id="item_tmpl">
  <div id="<%=id%>" class="<%=(i % 2 == 1 ? " even" : "")%>">
    <div class="grid_1 alpha right">
      <img class="righted" src="<%=profile_image_url%>"/>
    </div>
    <div class="grid_6 omega contents">
      <p><b><a href="/<%=from_user%>"><%=from_user%></a>:</b> <%=text%></p>
    </div>
  </div>
</script>

実行!

var results = document.getElementById("results");
results.innerHTML = tmpl("item_tmpl", dataObject);

ループ用のテンプレ

<script type="text/html" id="user_tmpl">
  <% for ( var i = 0; i < users.length; i++ ) { %>
    <li><a href="<%=users[i].url%>"><%=users[i].name%></a></li>
  <% } %>
</script>

nja_.ui-manage.js
javascriptでパーツファイルを読み込み

問題点あり・・・。



// 読み込みたい箇所にDOM
<div id="○○" data-parts="パーツファイルのパス" data-call="△△△(読み込み後に実行するjavascript)"></div>

// 読み込み後に実行するjavascriptを「nJa_.func.△△△」で関数として登録。
nJa_.func.△△△ = function() {
  $('#navact').navACT();
  $('#main').codeESCAPE();
  $('#spo1').guideNinja({
guide_footer_btn: '<div style="" class="fa-sm footer-btn white line-text rounded p-1"><i class="fas nja-open-door line-text mr-1"></i>ログアウト</div>',
guide_footer_msg: 'ここにメッセージ',
  });
};

// 以上で、読み込みが行われ、javascriptも実行される。

// **** 課題 *****
// タブ化したファイル読み込みで、javascript実行がスムースに行われない。
// キャッシュクリアの再読み込みが必要になるケースが多い。

nja_.ui_nav.js / nja_.ui-parts.js 中身一緒
.navACT():ナビゲーションをURLでactive自動化

絶対パス・相対パス・ルート相対パス、全部で動作するように

リンク仕様/ハッシュタグ仕様

.load()で読み込まれた要素には適用されない。

/*
$('#navact').navACT({
  debug: false,
  type: 'link',
  active: 'active',
  txt_mute: 'text-muted',
  txt_act: 'text-dark',
  done: null,
  error: null,
  });
*/

.load()のコールバック関数で読み込ませる。関数を指定した配列に登録。属性に関数名を指定してload時に呼び出しする。


/*
javascriptでincludeする場合
<div id="header" data-parts="header.html" data-call="navact"></div>
nJa_.func.navact = function() {
  $('#navact').navACT(); // ←←←← これがナビactive自動化用関数の実行
};

//オプション・ハッシュタグ仕様
$('#navact').navACT({
  type: 'hash',
  active: 'active',
  txt_mute: 'text-muted',//非アクティブリンクテキストカラークラス
  txt_act: 'text-dark',//アクティブリンクテキストカラークラス
});
*/

.swipNAV().キュレーションアプリっぽいバー
/*
// For PC
$('#psc').swipNAV({
  parents: '.nav',
  class_back: '.navback',
  class_go: '.navgo',
  back_btn : '<div class="navback"><div class="w24"><div class="maru bg-kagero btn-back"><div class="navback"><div class="w24"><div class="maru bg-kagero btn-back">></div></div></div>'</div></div></div>',
  go_btn : '<div class="navgo"><div class="w24"><div class="maru bg-kagero btn-go"></div></div></div>',
  done: null,
  error: null,
});

.swip-nav  { position: relative; z-index: 2;
  max-height: 3.75rem; overflow-y: hidden;
}
.swip-nav .nav { display: -ms-flexbox; display: flex;
  -ms-flex-wrap: nowrap; flex-wrap: nowrap;
  overflow-x: auto; overflow-y: hidden;
  white-space: nowrap;
}

*/
ソートボックス

flex要素内の子要素の配置は、.flex-center .flex-middleでOK!

テスト1
テスト2
テスト3
テスト4
テスト5
テスト6
テスト7
テスト8
/*
Sortable.create($('#sortbox')[0], {
  animation: 150,
  ghostClass: 'rgba-blue-slight',
}
);

//オプション
draggable: ".item",
handle: ".my-handle",
ghostClass: "sortable-ghost", // Class name for the drop placeholder
direction: "horizontal", //vertical
onStart: function (/**Event*/ evt) {
  evt.oldIndex; // element index within parent
},
onEnd: function (/**Event*/ evt) {
    var itemEl = evt.item; // dragged HTMLElement
    evt.to; // target list
    evt.from; // previous list
    evt.oldIndex; // element's old index within old parent
    evt.newIndex; // element's new index within new parent
    evt.oldDraggableIndex; // element's old index within old parent, only counting draggable elements
    evt.newDraggableIndex; // element's new index within new parent, only counting draggable elements
    evt.clone; // the clone element
    evt.pullMode; // when item is in another sortable: `"clone"` if cloning, `true` if moving
},

*/
リサイズ

jquery ui resizable の代替

その1:CSSのresizeプロパティとobserverを使用

resizeプロパティ:ie,saffarでサポート外

/*
//css
#resizeable{ overflow: auto; resize: both;}

//javascript:ResizeObserve
const resizeObserver = new ResizeObserver(entries => {
  for (const entry of entries) { ... }
});
const target = document.querySelector('div');

// target の監視を開始する
resizeObserver.observe(target);

// target の監視を終了する
resizeObserver.unobserve(target);

//ResizeObserverEntry
const resizeObserver = new ResizeObserver(entries => {
  for (const entry of entries) {
    // 変更を検知した要素
    console.log(entry.target);

    // 検知した変更の矩形
    const rect = entry.contentRect;
    console.log(rect.top, rect.left);
    console.log(rect.width, rect.height);
  }
});

// 監視を追加する
resizeObserver.observe(document.querySelector('#foo'));
resizeObserver.observe(document.querySelector('#bar'));
resizeObserver.observe(document.querySelector('#baz'));

/ 監視を終了する
resizeObserver.disconnect();

*/

その2:javascriptで実現