スキップしてメイン コンテンツに移動

Nice Page Builderをブログ書きながらテストしていったよ

目次を追加してマークアップを修正、併せて追記と修正を行っています。(2021.5.11)

諸々公開しています。(2017.2.2)

  1. 最小のパターン
  2. 任意のプロパティを追加してみる
  3. 各ページで共通する値を別ファイルに分離したい MIXINS
  4. ルート相対リンクから相対リンクへ変換
  5. beforeBuild スクリプトと Page クラスの拡張

現在 Nice Page Builder は自分のホームページ開発に使っています。生憎とコードが散らかっているので公開はもうちょい先になります。

1. 最小のパターン

npmTestProject
 - source
    templete.html
    index.html
 - output
    index.html

まずは最低限の機能、テンプレートだけな HTML とコンテンツだけの HTML から完成版の HTML を生成します。

source/templete.html

<!DOCTYPE html>
<html>
<head></head>
<body>
<header></header>
<main>{$$ this.CONTENT $$}</main>
<footer></footer>
</body>
</html>

テンプレート側からコンテンツは this.CONTENT または page.CONTENT で取得します。

source/index.html

<script type="nice-page-builder/object" for="page-option">
{
 TEMPLETE : '/templete.html'
}
</script>
<p>Hello, World!

テンプレートへの参照は上の通り <script> 要素内のオブジェクトリテラルで行います。独自の typefor 属性が付いています。

この独自 <script> 要素の内容は生成過程で評価・破棄されて生成物に含まれることはありません。

output/index.html

18日(日)夕までに先の2つのファイルから次の index.html を得ることが出来ました。

<!DOCTYPE html>
<html>
<head></head>
<body>
<header></header>
<main>
<p>Hello, World!</main>
<footer></footer>
</body>
</html>

2. 任意のプロパティを追加してみる

次に任意のプロパティの使い方を見ていきます。これはサイト開発者がプロジェクト毎に独自に定義していきます。

source/index.html

<script type="nice-page-builder/object" for="page-option">
{
 TEMPLETE : '/templete.html',
 title : 'Hello'
}
</script>
<p>Hello, World!

ページ毎にタイトルを変えたいので(当たり前ですね)、title というプロパティを追加します。

source/templete.html

<!DOCTYPE html>
<script type="nice-page-builder/object" for="page-option">
{
 title : 'No Title!'
}
</script>
<html>
<head><title>{$$ this.title $$}</title></head>
<body>
<header><h1>{$$ this.title $$}</h1></header>
<main>{$$ this.CONTENT $$}</main>
<footer></footer>
</body>
</html>

テンプレートで title 文字列を挿入したい位置に追記していきます。またデフォルトのタイトルがある場合、テンプレートに書いておきます。

output/index.html

Hello が挿入されていること、source/index.html で title を指定しなかった場合、No Title! が代わりに挿入されていることを確認できました。

<!DOCTYPE html>
<html>
<head><title>Hello</title></head>
<body>
<header><h1>Hello</h1></header>
<main>
<p>Hello, World!</main>
<footer></footer>
</body>
</html>

3. 各ページで共通する値を別ファイルに分離したい MIXINS

DreamWeaver でいうところのライブラリ機能のように各ページで共通して使う値を分離することができます。

トップページ(index.html)の他に商品の紹介ページ(今回はペン、パイナップル、アップルの計3ページ)を持つ企業サイトを例にします。

npmTestProject
 - source
    templete.html
    index.html
    products
      apple.html
      pen.html
      pineapple.html
    mixins
      products.json
 - output
    index.html
    products
      apple.html
      pen.html
      pineapple.html

source/templete.html

<!DOCTYPE html>
<script type="nice-page-builder/object" for="page-option">
{
 title : 'No title!'
}
</script>
<html>
<head><title>{$$ (this.category ? this.category + ' &gt; ' : '' ) + this.title $$}</title></head>
<body>
<main>{$$ this.CONTENT $$}</main>
</body>
</html>

新しいプロパティ category を追加します。三項式を使って <title> に出力されるようにしました。

source/products/apple.html

<script type="nice-page-builder/object" for="page-option">
{
    MIXINS : ['/mixins/products.json'],
    title  : 'Apple'
}
</script>
<p>This is a Apple.

MIXINS というビルトインプロパティで商品紹介ページに共通する値を持つ "/mixins/products.json" のパスを書きます。

source/mixins/products.json

{
    "TEMPLETE" : "/templete.html",
    "category" : "商品紹介",
    "title"    : "商品の title がありません"
}

ミックスインの内容はページのプロパティにコピーされます。ページ側ですでにプロパティが定義されている場合、上書きされることはありません。優先順位は ページ > ミックスイン[0] > ミックスイン[z] > テンプレートです。

json の書き方がめんどくさい場合、js のオブジェクトリテラルで書いてしまっても構いません。その際はエディタの構文チェックが警告してくるのでファイル名を products.js にします。

output/products/apple.html

<!DOCTYPE html>
<html>
<head><title>商品紹介 &gt; pineapple</title></head>
<body>
<main>
<p>This is a pineapple.</main>
</body>
</html>

できた!

4. ルート相対リンクから相対リンクへ変換

ここまでのテストでフォルダ階層ができたのでリンクの変換を CSS の追加をダシに確認します。

npmTestProject
 - source
    templete.html
    index.html
    products
      apple.html
      pen.html
      pineapple.html
    mixins
      products.json
 - output
    index.html
    products
      apple.html
      pen.html
      pineapple.html
    css
      all.css

output/css/all.css

output/css 下に次のファイルを追加しました。

body { background: yellow; color : darkgoldenrod; }

source/templete.html

続いて <link> をテンプレートに追加します。この際にリンクをソースのルートフォルダからのルート相対リンクで指定して ($$ ~ $$) で挟みます。

<link rel="stylesheet" type="text/css" href="($$ /css/all.css $$)">

テンプレートは様々な階層から参照されます。その際にパスがズレない為のルート相対リンクです。

/index.html では <link rel="stylesheet" type="text/css" href="css/all.css"> が products/*.html では <link rel="stylesheet" type="text/css" href="../css/all.css"> が追加されました。

5. beforeBuild コールバックと Page クラスの拡張

インラインスクリプト({$$ /* inline script */ $$})では長々とスクリプトを書くには適しません。また同じ内容のインラインスクリプトが複数ある場合メソッドにまとめたいところです。

次のように <script type="nice-page-builder/js" for="beforeBuild"> 内にスクリプトを書きます。ここに書かれたスクリプトは pagesPage のグローバル変数にアクセスできます。

pagesfor in ループで回して集計をしたり、Page.prototype に値やメソッドを追加できます。

<!DOCTYPE html>
<script type="nice-page-builder/object" for="page-option">
{
 title : 'No title!'
}
</script>
<script type="nice-page-builder/js" for="beforeBuild">
// 全ページのリンクを取得
var links = [], path, label;
for( path in pages ){
    links.push({title:pages[path].title,path:pages[path].FILE_PATH});
};
// リンクリストを書きだすメソッドの追加
Page.prototype.ALL_LINK = links;
Page.prototype.createLinkList = function(){
    var html = [], i = -1, link;
    for( ; link = this.ALL_LINK[++i]; ){
        if( link.path !== this.FILE_PATH )
            html.push('<a href="'+ this.toRelativePath(link.path) + '">' + link.title + '</a>');
    };
    return html.join(',');
};
</script>
<html>
<head>
<title>{$$ (this.category ? this.category + ' > ' : '' ) + this.title $$}</title>
<link rel="stylesheet" type="text/css" href="($$ /css/all.css $$)">
</head>
<body>
<main>{$$ this.CONTENT $$}</main>
<footer>{$$ this.createLinkList() $$}</footer>
</body>
</html>

<footer> に他のページへのリンクを貼ることが出来ました!