てくてく

タグ「JavaScript5件]

小説をサイトに載せるとき気付いたんです。
「中身ほとんど一緒なんだからぱっと置き換えたら楽なんじゃない?」
最近PHPでパーツの共通化してとても便利ではあったのですが、小説本文をペッと貼ったらパッとhtml形式で書き出してくれたら楽できるなって気付いたんです。
ということでそんな小説をhtmlに書き出してくれる置き換えスクリプトを作りました!
今回は配布ありです。

配布
ダウンロードはこちら⇨novel 2 template
免責事項をご確認の上、ご利用くださいませ。

デモはこちらより確認できます。

内容物
  • index.html
  • readme.txt
  • script.js
  • style.css


確認環境はGoogle Chromeのみです。またローカルでの使用を想定しております。

使い方
あらかじめ、以下のものを用意してください。
  • 小説本文
  • 小説を載せたいテンプレート(html、phpどちらでも可)以降テンプレート表記


novel 2 template
index.htmlを開く(ダブルクリック)と規定ブラウザでページが開きます。
各項目を設定します。

◯タイトルタグ
<title>に書きたい内容。
置き換えの必要がない場合は空欄で大丈夫です。

◯cssのURL
ファイルを配置する場所からcssまでのパス。
文字を置き換えるだけなので、相対パス・絶対パスどちらでもOKです。
置き換えの必要がない場合は空欄で大丈夫です。

◯作品タイトル
小説のタイトル。
置き換えの必要がない場合は空欄で大丈夫です。

◯本文
小説本文。通常だとタグに囲まれずそのまま置き換えられます。
置き換えの必要がない場合は空欄で大丈夫です。
下記の機能があります。
・改行タグを入れる
 - 改行済みテキストの場合、改行タグを挿入します。デフォルトでチェックが入っています。
・空行が◯行以上ならpタグで囲む
 - 空行の行数を指定すると、その間のテキストをpタグで囲みます。
・ルビ表記をルビタグに差し替える
 - 特定のルビ表記をルビタグに変更します。対応しているルビ表記は後述です。
・pタグとpタグの間に水平タグを挟む
 - pタグとpタグの間に水平タグを入れます。これは管理人が欲しくて追加したオマケ機能です。

対応しているルビ表記は以下のとおりです。
| 漢字 《かんじ》
#漢字__かんじ__#
[RB:漢字,かんじ]
[[rb: 漢字 > かんじ ]]
[漢字"かんじ"]

◯JavaScriptのURL
JavaScriptのファイルまでのパス。
cssのURL同様、ファイルを配置する場所からJavaScriptファイルまでのパスをいれてください。
置き換えの必要がない場合は空欄で大丈夫です。

◯項目追加
項目名を入れ追加ボタンを押すと、項目を追加できます。
項目名はわかりやすくするためのものなので、未定義のままでも動きます。
追加した項目は削除可能です。追加・削除した項目はナンバリングが再設定されます。

◯ファイルから読み込み
テンプレートファイルがあればこちらから読み込むのが早いです。
読み込むとテンプレート欄に内容が表示されます。

◯テンプレート
ファイルから読み込まない場合、テンプレート欄にテンプレートを記入してください。

◯置き換え
設定した項目をテンプレートに反映させます。
テンプレート欄になにもないとアラートが表示されます。

◯置き換え結果
置き換えた内容をこのエリアに表示します。
内容をコピーしてご利用ください。
整形されていないので、整形したい場合は外部ツールやソフトをご利用くださいませ。

◯ダウンロード
ファイル名(デフォルトはoutput)を記入しhtmlかphpかを選びダウンロードボタンを押すと、置き換え結果の内容を選択した拡張子でダウンロードできます。
なお、サーバーに送信はされませんのでご安心ください。
置き換え結果欄になにもないと、アラートが表示されます。

テンプレートファイルの書き方
novel 2 templateの各項目には[item数字]が書かれています。
この[item数字]を書いた場所が、設定した内容と置き換わる仕組みです。
例1:
タイトルタグフォーム:小説をhtmlに置き換えるスクリプト作ってみたっ
テンプレート:<title>[item0]</title>
書き出されるもの:<title>小説をhtmlに置き換えるスクリプト作ってみたっ</title>

例2:
cssのURLフォーム:../css/style.css
テンプレート:<link rel="stylesheet" href="[item1]" type="text/css" id="style">
書き出されるもの:<link rel="stylesheet" href="../css/style.css" type="text/css" id="style">

例3:
追加した項目[item5]:明日は明日の風が吹く
テンプレート:<p>[item5]</p>
書き出されるもの:<p>明日は明日の風が吹く</p>

カスタマイズ
MITライセンスで配布しておりますので、ご自身のテンプレートに合うように好きに改変していただいて構いません!
カスタマイズ向けの説明は同梱のreadme.txtに記載されています。

最後に
自分用に試しに作ってみたものですが、割といい感じにできたと思います。
カスタマイズ次第では項目追加も不要になると思いますので、自分だけの変換ツールを作ってみてください!

関連記事
簡易ログイン作ってみた!
【JavaScript】名前変換機能を作ってみた!
今は便利な名前変換機能(単語変換機能)スクリプトを配布してくださっている方がいらっしゃいます。
私が自分のサイトに実装した当時、求めている機能が微妙になかったため「作るっきゃねえ!」の精神で自作しました。

デモ
こちらのデモページから動作確認ができます。

仕様
①名字・名前・名字ひらがな・名前ひらがなを変換
②名字と名前はユニークなものを前提としている
③ひらがなは[RB:吃 > ども]りなどで利用
④小説ページごとにデフォルト名が異なっていても対応可能
⑤Cookieを利用
⑥変換フォームのプレースホルダーには変換した名前を入れておく。

ユニークなものとは、重複しない独特なものを意味しています。本文で使われない単語のことです。
例えば、名前が「空」だと「青空の下に広がる海。」など本文に「空」の文字が入っていると仕様上その文字も変換されてしまいます。

基本私が小説を書くときは名前変換を前提としておらず、名前を決めて執筆しています。
htmlに持っていくときに名前の部分にタグ付けがいちいち面倒だな……と思い、JavaScriptの文字列変換を利用して書き換える方向にしました。
ただひらがなはなかなか難しかったため、ひらがなだけタグをつけています。
(私の小説ではそこまで多用しなかったので妥協しました)

ファイル構成
index.html
contents.html
css/style.css
js.name-change.js
今回はjQueryを使いません。
Cookie処理はかわりにjs-cookieを利用しました。

JavaScriptの読み込み
名前変換のフォームがあるページと、名前変換処理をするページで読み込みます。
<!-- js-cookie -->
<script src="https://cdn.jsdelivr.net/npm/js-cookie@3.0.5/dist/js.cookie.min.js"></script>
<!-- script -->
<script src="js/name-change.js"></script>

js-cookieのCDNはこちらからコピペしています。
Cookie操作をしやすいように利用しています。

名前変換フォーム
今回index.htmlに書いてる名前変換のフォームです。
なお、デザインに関するクラスは省いています。
<form name="d_name">
    <input type="text" placeholder="名字" name="lastname">
    <input type="text" placeholder="名前" name="firstname"><br>
    <input type="text" placeholder="みょうじ" name="lastname_hira">
    <input type="text" placeholder="なまえ" name="firstname_hira"><br>
    <button type="button" onclick="setName()">変換</button>
    <button type="button" onclick="resetName()">リセット</button>
</form>
<div id="setName"></div>

onclickの処理はjs/name-change.jsファイルに記述します。
<div id="setName"></div>は変換ボタンやリセットボタンを押した後の結果を表示するためのものです。

style.css
上記<div id="setName"></div>の設定です。
#setName {
    display: none;
    /* 下記はデザイン用 */
    margin: 15px 0;
    padding: 15px;
    border: 1px solid transparent;
    border-radius: 3px;
    margin: 0 0 10px;
    padding: 8px;
}

#setName.change,#setName.reset {
    display: block;
}

#setName.change::after {
    content: "名前を変換しました。";
}

#setName.reset::after {
    content: "名前をリセットしました。";
}

/* 下記はデザイン用 */
#setName.change,#setName.reset {
    border-color: #9ad4de;
    background-color: rgba(154, 212, 222, 0.25);
}


名前変換ありの本文
記述はこのようにします。
<div id="d-name-default"  data-last="デフォルト名字" data-first="デフォルト名前" data-last-hira="でふぉるとみょうじ" data-first-hira="でふぉるとなまえ"></div>
<div id="d-name-nvl">
    <!-- 本文 -- >
</div>

一つずつ解説していきます。

<div id="d-name-default" data-last="デフォルト名字" data-first="デフォルト名前" data-last-hira="でふぉるとみょうじ" data-first-hira="でふぉるとなまえ"></div>
タグはdivにしていますがなんでもいいです。こちらは
<script src="js/name-change.js"></script>
より上に記述してあればどこに記述しても構いません。今回は本文の前に記述しています。
id="d-name-default"でJavaScriptから取得できるようにします。
data-last=""はデフォルトの名字を入れます。省略可能です。
data-first=""はデフォルトの名前を入れます。省略可能です。
data-last-hira=""はデフォルトの名字のひらがな(読み方)を入れます。省略可能です。
data-first-hira=""はデフォルトの名前のひらがな(読み方)を入れます。省略可能です。
この省略可能は、本文で使用しない場合に記述しなくていいようにするものです。

id="d-name-nvl"の中に小説本文を流し込みます。これは上記で設定したデフォルト名と変換フォームで設定した名前を置き換えるためのものです。このidがないと変換されないので注意です。

ひらがなのタグ
名字や名前のひらがな部分にはタグを追加します。
デモ版の場合はこのようにしてます。
「俺は<em>愛上陵</em>!”<em><span class="last-hira">あいうえ</span></em><em><span class="first-hira">おか</span></em>”って読むんだぜ!珍しいだろ?」<br>
 ──<em><span class="last-hira">あ……いう……</span></em>──<br>
「ん?いまなにか聞こえたか?」<br>
 ──<em><span class="last-hira">あい……うえ……</span></em><em><span class="first-hira">お……か</span></em>──<br>
「やっぱ誰かに呼ばれてる!」

名字のひらがなを
<span class="last-hira"></span>
名前のひらがなを
<span class="first-hira"></span>
で囲みます。
このとき間に三点リーダ(…)や句読点が入っても大丈夫です。
もしひらがなの部分に別のタグ(強調タグやルビタグなど)を使いたい場合は、spanタグの外側に設置します。

name-change.js
処理はこちらです。
/* 名前設定 */
function setName() {
    const formEl = document.forms.d_name;
    let change = false;
    change = setItem(formEl.lastname,'lastname');
    change = setItem(formEl.firstname,'firstname');
    change = setItem(formEl.lastname_hira,'lastname_hira');
    change = setItem(formEl.firstname_hira,'firstname_hira');
    if (!change) { return; }
    document.getElementById("setName").classList.remove("reset");
    document.getElementById("setName").classList.add("change");
    /* 同じページ内に変換箇所がある場合 */
    changeName();
}

/* 項目別 */
function setItem(elName,cookieId){
    const name = elName ? elName.value : '';
    if(name === null || name === '') return false;
    Cookies.set(cookieId, name);
    return true;
}

/* 名前変換時にテキストエリアを変換した名前に保持 */
function keepName() {
    const formEl = document.forms.d_name;
    if (!formEl) { return; }
    keepItem(formEl.lastname,'lastname');
    keepItem(formEl.firstname,'firstname');
    keepItem(formEl.lastname_hira,'lastname_hira');
    keepItem(formEl.firstname_hira,'firstname_hira');
    document.getElementById("setName").classList.remove("reset");
    document.getElementById("setName").classList.remove("change");
}

/* 項目別 */
function keepItem(elName,cookieId){
    let input = elName ?? null;
    if(input === null) return;
    const name = Cookies.get(cookieId) ?? input.placeholder;
    if(input.placeholder !== name){
        input.value = name;
    }
}

/* 名前リセット */
function resetName() {
    const formEl = document.forms.d_name;
    let reset = resetItem(formEl.lastname,'lastname');
    reset = resetItem(formEl.firstname,'firstname');
    reset = resetItem(formEl.lastname_hira,'lastname_hira');
    reset = resetItem(formEl.firstname_hira,'firstname_hira');
    if(reset){
        ajaxReload(); // 同一ページに変換箇所がある場合
        document.getElementById("setName").classList.remove("change");
        document.getElementById("setName").classList.add("reset");
    }
}

/* 項目別 */
function resetItem(elName,coolieId){
    Cookies.remove(coolieId);
    if (!elName) return false;
    else elName.value = '';
    return true;
}

/* 名前変換 */
function changeName() {
    let d_name_nvl = document.getElementById('d-name-nvl');
    if (d_name_nvl === null) { return; }
    let str = changeItem('lastname', 'data-last', d_name_nvl.innerHTML);
    str = changeItem('firstname', 'data-first', str);
    d_name_nvl.innerHTML = str;
    changeHiragana('lastname_hira', 'data-last-hira', 'last-hira');
    changeHiragana('firstname_hira', 'data-first-hira', 'first-hira');
}

/* 項目別 */
function changeItem(cookieId,attrName,str){
    const data_d = document.getElementById('d-name-default').getAttribute(attrName);
    const name = Cookies.get(cookieId);
    if(name && data_d) return str.replace(new RegExp(data_d,'g'),name);
    return str;
}

/* ひらがな対応 */
function changeHiragana(cookieId,attrName,className){
    const data_d = document.getElementById('d-name-default').getAttribute(attrName);
    const name = Cookies.get(cookieId);
    if(!(name && data_d)) return;
    let arr = document.getElementsByClassName(className);
    for(i = 0;i<arr.length;i++){
        let el = arr[i];

        let defHira = data_d.split('');
        let nameHira = name.split('');
        let str = el.innerText.split('');
        let txt ='';
        let nameCount = 0;
        for (k = 0; k < str.length; k++) {
            if(!str[k].match(/^[ぁ-んー ]+$/) || defHira.length <= nameCount){
                txt += str[k];
            }else{
                let replace;
                if(nameCount < nameHira.length){
                    replace = nameHira[nameCount];
                    txt += str[k].replace(defHira[nameCount], replace);
                    nameCount++;
                }else if(nameHira.length < defHira.length){
                    // 設定された名前のほうが短ければ以降はつけない
                    break;
                }
            }
        }
       
        // 不足分追加
        if(defHira.length < nameHira.length){
            let substr = name.substr(nameCount);
            txt += substr;
        }

        el.innerText = txt;
    }
}

/* 同じページに変換がある場合 */
function ajaxReload(){
    let d_name_nvl = document.getElementById('d-name-nvl');
    if (d_name_nvl) {
        let url = location.href + "?date="+new Date().getTime();
        let ajax = new XMLHttpRequest;
        ajax.open("GET",url,true);
        ajax.onload = function(){
            var res = ajax.responseText;
            var parse = new DOMParser().parseFromString(res,"text/html");
            d_name_nvl.innerHTML = parse.getElementById('d-name-nvl').innerHTML;
        };
        ajax.send(null);
    }
}

/* 読み込み直後 */
window.onload = function () {
    /* 入力フォームの設定 */
    keepName();
    /* 名前変換 */
    changeName();
};

同一ページに変換箇所がある場合の処理も追記しておきました。
もしない場合はその部分は削除して大丈夫です。
名前を変換する場合は文字を置き換え、リセットする場合は名前変換のあるタグ(d_name_nvl)の中だけをajaxをつかってリロードしています。
一部のみリロードについてはjavascriptでページを一部だけ更新する方法を参考にしました。
ajaxでもどってくる内容はテキストデータなので、htmlにパースして利用しています。テキストのパースは【JavaScript】DOMParserで文字列をHTMLElement・Nodeに変換するを参考にしました。

最後に
実装したのは割と前で記事にしようとしてなかなかできていなかったので、ようやく記事にできて嬉しいです。
「もっと汎用性がほしい!」「もっと使いやすい方がいい!」「全ページ同じにしたい!」と言った場合は、すでに配布されている素晴らしいスクリプトがありますのでそちらを使っていただくといいかもしれないです。
私の場合「名前にいちいちタグしたくない」「デフォルト名が小説によって違う」と自分で用意したほうが良さそうだったので用意してみました。
同じように自作しようとしている方の参考になれば幸いですっ

それと記事に関係ないですが、Twitter(現X)アカウントを作成しました!
Twitter(現X)アカウント てくてく@個人サイト向け情報共有サイト
よければフォローして下さいませ♪

参考
js-cookie
CDN js-cookie
javascriptでページを一部だけ更新する方法
JavaScript】DOMParserで文字列をHTMLElement・Nodeに変換する
DOMParser の parseFromString() メソッドの使い方
.htaccessやサーバー設定でBasic認証ができるわけですが、ブラウザからIDやパスワードを求められるとちょっとびっくりします。
昔そういう個人サイトを見たことがあるのですが、フォレストやnanoなどの認証ばかり触れていたせいでブラウザからの認証に「なんだこれ!怖い!」と避けていた記憶が蘇ります。
サイトを運営する立場になった今ならあれはそこまで恐れるものでもないとわかるのですが、せっかくならログイン周りもデザインしたいところ・・・
個人サイトで入り用だったのもあり、JavaScriptで簡単なログイン認証を自作してみました!
今回はログインに焦点を絞りましたが、流用すればログインに限らないパスワード認証にも使えると思います。

デモ
こちらのデモページから動作確認ができます。
仕様
①indexページでパスワード認証
成功:コンテンツページへ飛ぶ
失敗:「パスワードが違います」と表示

②ログインに成功したら、次回以降パスワードは自動入力
 今回はパスワード保存の期限を設定していないので、使用したライブラリのデフォルト期間(365日)はCookieで保存されます。

③ログインしていない状態でindex以外のページへいったら、内容を隠してログイン画面をポップアップ表示
成功:ポップアップが消えて中身が見える
失敗:画面はそのまま「パスワードが違います」と表示される

④ログインしていればindex以外のページへ直接いってもログイン画面が出ず中身を見れる

⑤コードからパスワードが読まれないようハッシュ化
暗号化:暗号化されたデータを元のデータに戻せるタイプ
ハッシュ化:暗号化されたデータは元のデータに戻せない

こんな感じですね。
こちらの作り方を解説していきます~

準備
  • jQuery…jquery-cookieのために必要です
  • jquery-cookie…jQuery用いたCookie操作用
  • jsSHA…パスワードのハッシュ化用

ハッシュ化はjsSHAを使います。
「Newest Release / Download」のGitHubにリンクがあるので、そこからDLページへ飛びます。
Source code(zip)かSource code(tar.gz)のどちらかを選んでDLしてください。
いろいろなファイルが入っていますが、必要なのは「jsSHA-3.3.0/jsSHA-3.3.0/dist」にあるsha256.jsファイルだけです。

ファイル構成
index.html
contents.html
css/style.css
js/
├login.js
└3rd/sha256.js
さきほどDLしたsha256.jsをこの位置に入れます。
自分が作ったものと区別できるよう3rdフォルダに入れていますが、パスが通っていればどこでもOKです。
login.jsにログインの処理を書いていきます。

JavaScriptの読み込み
まずJavaScript周りの読み込みしておきましょう。
ログイン認証したいページやログインしていなければ中を見せたくないページに各種読み込んでいきます。
今回だとindex.htmlとcontents.htmlですね。
htmlファイルのbodyの閉じタグ直前に下記を記述します。
<!-- jQuery -->
<script src="https://code.jquery.com/jquery-3.6.4.min.js" integrity="sha256-oP6HI9z1XaZNBrJURtCoUT5SUnxFr8s3BzRl+cbzUq8=" crossorigin="anonymous"></script>
<!-- 3rd -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-cookie/1.4.1/jquery.cookie.js"></script>
<script src="js/3rd/sha256.js"></script>
<!-- script -->
<script src="js/login.js"></script>

jQueryのCDNはこちらをコピペしてます。
今回はjQuery Core 3.6.4 minifiedを使いました。
配布プログラムを利用していてjQueryを入れてるよ!ということであればそちらを使うのが良いかと。

jquery-cookieのCDNはこちらの最新版を使ってます。
今回はVersion1.4.1を使いました。URLが2つありますが下の方を使ってます(どちらでも大丈夫です)。

sha256.jsは準備項目でDLしたファイルです。
login.jsはログイン周りの処理を書くファイルです。

index.html
ログイン周りに必要な部分だけ抜粋します。
<div id="loginResult">パスワードが違います</div>
<div>
    <input type="password" placeholder="password" id="loginPass">
    <input type="button" value="送信" id="login">
</div>

loginResultにはパスワードが異なるときの文章を記述します。
inputdivタグで囲っていますが、これはformにするとエンターキーでsubmitになってしまうことからdivにしてます。そのあたりの処理(エンターキーで認証処理を実行)を書けるようであればformでもOKかと!

そしてパスワードを入力するのが
<input type="password" placeholder="password" id="loginPass">
の部分です。type="password"で伏せ字にしてますがtype="text"でもOK。

パスワード認証の処理は
<input type="button" value="送信" id="login">
のクリックで実行するようにします。

contents.html
今回はわかりやすいようにcontents.htmlの名前になっていますが、ログインしないと見れないファイルに記述する内容です。
まずログインするまでぼかしておきたいタグにclass="passcheck"というクラスを追加します。
bodyに追加するとログイン用のポップアップもぼかしてしまうのでbodyに入れないようにします。
例えば
<body>
    <header class="passcheck">
        <!-- ヘッダーの記述 -->
    </header>

    <main class="passcheck">
        <!-- ここにコンテンツの記述 -->
    </main>
    
    <footer class="passcheck">
       <!-- ここにフッターの記述 -->
    </footer>

    <!-- 各種scriptの読み込み(省略) -->
</body>

といった感じです。
ぼかさなくていいなってものがあればクラスを外してください。

次にログイン用のポップアップを記述します。
<div class="overlay">
    <div class="popup-window">
        <h2>Login</h2>
        <div>
            <div id="loginResult">パスワードが違います</div>
            <div>
                <input type="password" placeholder="password" id="loginPass">
                <input type="button" value="送信" id="login">
            </div>
            <a href="index.html">indexへ</a>
        </div>
    </div>
</div>

index.htmlへ戻るリンクはindexページへ戻れるように貼ってます。不要なら削除してOK。
必ずpasscheckの外側に記述してください
demoだと下記のようにmainタグとfooterタグの間に記述してます。
<main class="passcheck">
    <!-- ここにコンテンツの記述 -->
</main>

<!-- ログイン用ポップアップ -->
<div class="overlay">
    <div class="popup-window">
        <h2>Login</h2>
        <div>
            <div id="loginResult">パスワードが違います</div>
            <div>
                <input type="password" placeholder="password" id="loginPass">
                <input type="button" value="送信" id="login">
            </div>
            <a href="index.html">indexへ</a>
        </div>
    </div>
</div>

<footer class="passcheck">
    <!-- ここにフッターの記述 -->
</footer>


css
#loginResult#loginResult.error.overlay.popup-windowを記述していきます。

ログイン失敗表示
#loginResult{
    display: none;
    /* 下記はデザイン用 */
    padding: 10px;
    margin: 10px auto;
    width: 80%;
    border: 1px solid transparent;
}

#loginResult.error{
    display: block;
    /* 下記はデザイン用 */
    border-color: #de9a9a;
    background: rgba(222, 154, 154, 0.25);
}

デフォルトは非表示で、errorクラスを追加したら表示するようにします。

ポップアップ
.overlay {
    display: none;
    position: fixed;
    z-index: 9999;
    width: 100%;
    height: 100vh;
    top: 0;
    left: 0;
    background: rgba(0, 0, 0, .5)
}

.popup-window{
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    position: fixed;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    /* 下記はデザイン用 */
    width: 90vw;
    max-width: 380px;
    padding: 20px 0;
    background: #3a3a3a;
}

デフォルトは非表示です。表示処理をJavaScriptで行います。

そしてぼかし用のクラスです。
.blur {
    filter: blur(10px);
}


login.js
ここが要ですね!
まずスクリプトを書いていく前にパスワードを用意します。
SHA256に変換してくれるサイトでSHA256変換したパスワードを用意します。
わかりやすさからこちらのサイトで用意しました。出力形式は小文字です。
今回使うライブラリのjsSHAページにあるデモを使ってもいいでしょう。
その場合はHasing Demoの欄に以下の設定で出力します。
Input Text: パスワードにしたい文字列を入力
Input Type: TEXT
SHA Variant: SHA-256
Number of 1
Rounds: Output Type: HEX
Output Hashに出力された文字列がハッシュ化されたパスワードです。

login.jsに記述するコード全文はこちらです。
$(function(){
    const PASS_HASH = 'さきほど出力したハッシュ化されたパスワード';

    /* index.htmlでない且つCookieのハッシュ化パスワードが異なっていたら
       passcheckクラスにぼかしをつける+ポップアップを表示 */
    if(!location.pathname.includes('index.html') && $.cookie('loginhash') != PASS_HASH){
        $('.passcheck').addClass('blur');
        $('.overlay').show();
    }
    
    /* Cookieにログインパスワードが残っていたら自動入力 */
    $('#loginPass').val($.cookie('loginpass'));

    /* ログインボタンをクリックしたら認証処理 */
    $('#login').click(function() {
        const pass = $('#loginPass').val();
        const shaObj = new jsSHA('SHA-256','TEXT');
        shaObj.update(pass);
        const hash = shaObj.getHash('HEX');
        if (PASS_HASH === hash) {
            /* 入力されたパスワードが合っていたら、Cookieに保存 */
            $.cookie('loginpass',pass);
            $.cookie('loginhash',hash);
            if(location.pathname.includes('index.html')){
                /* index.htmlにいたらコンテンツページへ飛ぶ */
                window.location.href = 'contents.html';
            }else{
                /* index.htmlでなければ、ぼかしを消してポップアップを非表示 */
                $('.passcheck').removeClass('blur');
                $('.overlay').hide();
            }
        }else{
            /* パスワードが不一致なら「パスワードが違います」のエラー表示 */
            $('#loginResult').addClass('error');
        }
    });
})

.htaccessで拡張子を表示しない設定をしている場合location.pathname.includes('index.html')の拡張子も消してください。
セキュリティ的にはまだまだかと思いますが、パッと見でパスワードがわからないくらいにはなってるかなと思います。
もっとしっかりやるならパスワード管理用のファイルを用意したほうがいいのですが、そこまでガチガチじゃないくていいかなというのと、ファイル読み込みなどの処理が面倒だったので省きました。

最後に
phpで作ってみようかな~と思ったのですが、ちょっとまだ勉強不足で時間がかかりそうだったのでJavaScriptで作りました。
ゆくゆくはきちんと中身が見られないようパスワード用のファイルを用意したり、パスワードの設定そのものをできるようにしたいところ・・・
とりあえずなものではあるものの、割と悪くないんじゃないかな?と個人的に思ってます。
上手く出来ると楽しい~~!

参考
【超シンプル】ポップアップをHTMLとCSSだけで実装する
JavaScriptを理解したいっ【変数編】の続きです。
前回はvarletconstについて学びましたので、今回は命名について勉強していきます。

命名規則
JavaScriptの命名での条件は以下のとおりです。
  • 1文字目は英字、_(アンダースコア)、$(ドル記号)のいずれかであること
  • 2文字目以降は1文字目で使える文字、もしくは数字のいずれかであること
  • 変数名に含まれる英字の大文字・小文字は区別される
  • JavaScriptで意味を持つ予約語ではないこと

このあたりはC系言語でも同じ…$を命名で使える…のか…?
C系で$を命名に使ったのを見たことがなく、C#で試してみたら案の定エラーが出ました。JavaScriptだから使えるのかな……?

さて、変数、関数、classなど任意に名前を付けられるものは規則性が重要になってきます。
これは別に上記の条件さえ満たせば「こういう規則で名前をつけろ!」と厳密に決まっているものではありません。
個人サイト運営のなかでの命名は、自分だけが使うものであれば自分がわかればいいかなと思います。とはいえ「3日前の自分が書いたプログラムは他人が書いたと思え」と持論があるので(もしかしたら誰の言葉かもしれない)、今の自分がわかるからと横着して適当な命名をすると後々痛い目を見ます。尚、経験談。
未来の自分が分かるプログラムを書くために、命名規則を自分の中で定めてみよう!

可読性を重視
JavaScriptに限らずどの言語でも恐らく同じだとは思いますが、ある程度共通認識があります。
  • 記法を統一する
  • 名前からそれが何であるか分かりやすくする
  • 長すぎず、省略しすぎない
  • 基本的に英単語を使う

「名前からそれが何であるか分かりやすい」「長すぎず、省略しすぎない」「基本的に英単語を使う」は基本として知っていたのですが、記法について私の知ってるものと少し異なっていたのでそのあたりを深掘りしていきます。
なお、記法は複合語で使用するものです。

camelCase記法
camelCaseはキャメルケースと読みます。
camel=ラクダでラクダのコブのように「最初の単語の頭は小文字、次以降の単語の頭は大文字」というルールの書き方です。記法名のcamelCaseと同じ書き方ですね。
例えば「名前をセットする」目的のデータにcamelCaseを適応するとsetNameとなるような感じです。
恐らく一番よく使われる記法なのではないでしょうか?
C系言語に触れていたときは、変数名は基本的にこのcamelCase記法でした。
※開発現場やプログラマーによります。

Pascal記法
プログラム言語PascalにちなんでいるらしいこちらのPascal記法。Pascal=パスカルです。
単語の頭は大文字にする書き方で、先程のsetNameをPascal記法にするとSetNameになります。「JavaScript」「Perl」という単語もPascal記法ですね。
C系言語に触れていたときは、クラス名や関数名などをこの記法で書いていました。
全体の統一性から変数名をPascal記法で書いた時もありましたが、変数名か関数かの区別をつきやすくするため、変数名はcamelCase記法、関数・クラス名はPascal記法で統一するようになりました(私個人の話です!)
テンプレートに同梱しているJavaScriptを眺めてるとPascal記法を見かけないので、この記法はマイナーなのかな?と感想を抱いています。

アンダースコア記法
単語と単語の間に_(アンダースコア/アンダーバー)を挟むこの記法。
私は「snake case記法」と覚えていたので言語によって言い方が異なるのかも知れません。
setNameだとset_nameSET_NAMEなどになります。
C系言語に触れていたときは、定数での命名は大文字+アンダースコア記法でした。
例えば#define WINDOW_WIDTH 1920とか#define WINDOW_HEIGHT 1080とか(C++ではconstではなく#defineで定数を設定することもできます)。この定数なら画面幅と画面高さを指定しているのが分かりますね。
JavaScriptだとconst WINDOW_WIDTH = 1920;const WINDOW_HEIGHT = 1080;となるでしょう。
参考にしている書籍だと「一般的に定数名で使用」とあるので、そのあたりは私の認識と共通していそうです。

JavaScriptライブラリjQueryを参考にしてみる
とってもお世話になっている便利ライブラリ「jQuery」の中身を見て、どんな命名規則なのか読み解いてみます。

変数名
jQuery v3.6.4 抜粋(48~71行目)
var arr = [];
var getProto = Object.getPrototypeOf;
var slice = arr.slice;
var flat = arr.flat ? function (array) {
    return arr.flat.call(array);
} : function (array) {
    return arr.concat.apply([], array);
};
var push = arr.push;
var indexOf = arr.indexOf;
var class2type = {};
var toString = class2type.toString;
var hasOwn = class2type.hasOwnProperty;
var fnToString = hasOwn.toString;

命名を見ていくので処理内容は省略します。
var arr = [];は配列定義ですね。arr=arrayの省略でしょう。
この省略は意味がわかるので使えそうです。

var getProto = Object.getPrototypeOf;はcamelCase記法なのがわかります。getは取得なのでProtoを取得した変数だと分かります。

var flat = arr.flat ? function (array) {
    return arr.flat.call(array);
} : function (array) {
    return arr.concat.apply([], array);
};
これはif文を使わない条件分岐の書き方です。
arr.flatが真なら
function (array) {
    return arr.flat.call(array);
}
を実行し、arr.flatが偽なら
function (array) {
    return arr.concat.apply([], array);
}
を実行するというものです。C系でも使いますね。
条件分岐の中身が少ない場合はこの書き方がスマートなのでお気に入りです。
……脱線してしまった。

var indexOfvar toStringvar hasOwnvar fnToStringでもcamelCase記法ですね。
indexOfは「配列の何番目か」、toStringは「文字列に変換」、hasOwnは「自身を持つかのフラグ」、fnToStringは「関数を文字列に変換」、といったところかなと思います。
indexOfやtoStringはC#でも使ったことがあるのですんなり意味を読み取れました。
JavaScriptは関数を示すときfunctionを記述するので、functionを省略してfnということでしょう。この省略の仕方も使えそうです。
ちなみにC#やC++は戻り値なしの関数を記述するときはvoidから始まります。
JavaScriptは戻り値があろうがなかろうがfunctionで指定できますが、C#やC++では戻り値がある関数を書きたいときは戻り値と同じデータ型で書き始める必要があります。
そう考えるとfunction万能すぎでは……?

var class2typeは「classをtypeで」といったところでしょうか。
「数字を文字列で」などのような変換系の命名ではnumberToStringではなくnumber2stringのように「2」を使って表すことがあります。number2stringのnumberやStringもnumやstrで省略しても分かりそうなのでnum2strでも良さそうです。
camelCaseでいくならclass2Typeでは?と思ったのですが、読みやすさ重視でclass2typeなのかもしれません。変換系のデータが他になかったので確認できませんでした。まあ読みやすいのでclass2typeがいいですね。

var toStringvar 2stringでないのは変数名の頭に数字は使えないからでしょう。

以上から、
  • 変数名は基本的にcamelCase記法
  • array、functionなどはarrやfnと省略
  • 変換系は「2」で挟みすべて小文字でcamelCase記法から外れる

だと分かりました。
ここまでやっておいてあれですが、「そもそもJavaScriptにある変数見れば早いのでは」と気づきました。
ということで事項関数名はJavaScriptの方を見ていきます。

関数名
JavaScriptの関数についてはなかなか特殊な書き方をすることがあるので関数についても勉強したいところ……。
document.getElementById()document.querySelector()からみても分かる通り、JavaScriptとして関数名はcamelCase記法の模様。
一応jQueryの中身も見てみたのですが、JavaScriptにラップ(元の機能やデータに機能やデータを追加したり削除したりして、同じ名前でも元とは別の内容で処理すること)してる形がほとんどっぽかったので省略します。

最後に
これまでを踏まえ、「変数名」「関数名」はcamelCase記法で今後は記述を心がけていこうと思います。
参考にした書籍によると定数をアンダースコア記法のが一般だそうです。C#やC++と同じですね。
お借りしたり作っていただいたりしたテンプレートに同梱されているJavaScriptファイルを見ると、基本的にcamelCase記法で統一されているみたいでした。テンプレート利用のサイトで使うJavaScriptはひとまずそちらに合わせていきます。
ただまあなるべくたくさん見て触れたほうが自分のためになるはずなので、いつもお世話になっているサイト様以外の、別のサイト様のテンプレートも勉強として見漁る予定です。
とりあえずまずは数年積み本にしてるリーダブルコードをちゃんと読みます!
目指せ!読みやすいコード!!

関連記事
JavaScriptを理解したいっ【変数編】

参考
改訂新版JavaScript本格入門モダンスタイルによる基礎から現場での応用まで
※私が参考にしたのは2019年発行のものですが、最新版があるのでご購入の際は最新版(改訂3版JavaScript本格入門
~モダンスタイルによる基礎から現場での応用まで
)が良いかと思います。
C#畑にいたころ、「C#とJavaScriptは似てる」というような話をたびたび聞きました。
有名なゲームエンジンUnityがかつてサポートしていた言語がC#とJavaScriptであったこと(※現在UnityはC#のみです)もあり、C#とJavaScriptは似てると先入観のまま触れるようになりました。

初めて見たJavaScriptのソースがjQuery使用のものだったので、
「全然違うじゃん!!なんだこの表記!!」
とたじろいだ記憶があります。
jQuery特有の記載方法であり、JavaScriptがすべてあの書き方ではないと今なら分かります。
実際JavaScriptに触れてみて
「ある程度基本的な部分はどの言語も恐らく同じ。配列の扱いは確かに似ているかもしれない」
と感想を抱きました。

とはいえ、言語が違えば”常識”も違う。
雰囲気で使っているあれこれを、C系言語と比較しながら今一度きちんと勉強して理解するぞ!おー!!
※記事が長くなったので命名については分けます。

変数宣言
JavaScriptで変数宣言するとき
varletconst
の3種類の命令から始まります。
違いをそこまで理解できていなかったので、まずはここからお勉強。

var
C#にも型推論のvarがあるので同じものだと思ってました。C++だとauto。
JavaScriptのvarもおおよそ挙動は同じ。
ただし、なんとこやつグローバルで宣言でき初期化しなくてもエラーにならず、しかも同じ名前で何度も宣言できてスコープ内で宣言したものを外でも使えるのである!
分かりますか奥様!この驚きたるや。

例えばC#で以下のように記述してみる。
エントリポイント(ソースが実行される開始点)が必要な関係上class内に入れている
class Program
{
    var test;

    static void Main()
    {
        var test2;

        var test3 = 0;
        var test3 = 2;

        var test4 = 0;
        test4 = 4;

        var test5 = 0;
        for (int i = 0; i < 10; i++)
        {
            test5++;
        }

        var test6 = 0;
        Console.WriteLine("test6は" + test6 + "です。");
    }
}

上記だと、test4~test6以外はエラーになる。
20230415223958-admin.png

これをJavaScriptで書き直してみよう。
classは一旦おいておく
var test;

function Main()
{
    var test2;

    var test3 = 0;
    var test3 = 2;

    var test4 = 0;
    test4 = 4;

    var test5 = 0;
    for (var i = 0; i < 10 ; i++) {
        test5++;
    }

    var test6 = 0;
    console.log("test6は" + test6 + "です。");
}

JavaScriptはなんとエラーにならない!!
202304152239581-admin.png
しゅごい……。
この挙動はJavaScript特有のものらしく、「巻き上げ」と呼ぶそうです。脳内でへえボタン連打しました。へえボタン…分かるかな…ハハ。
とはいえ、C#扱っていた頃はデータ型きっちり書きたいマンでvarを使う習慣がさほどなかったので、JavaScriptで記述する際にintを使おうとしてエラって「intがない…だと…?」と困惑した記憶があります笑
varの再宣言ができて便利だなと思う一方、
変数を簡単に書き換えられてしまうと、意図しないバグが発生する
letやconstに比べて、varは巻き上げ時のバグを生み出しやすい

記事を見つけたので肝に銘じます。

スコープ内で宣言したものを外でも使えるのスコープとは、for(条件文){...}if(条件文){...}など{ }で囲まれた部分のことを言います。
これがね…実に気持ち悪い面白い動きなんですよね。
C#でスコープ内で宣言した変数をスコープ外で使おうとするとエラーが出ます。
20230415233236-admin.png

JavaSciptさんはなんとえらーがでないんですねぇ。
202304152332361-admin.png

宣言以降も使えるというのはなんやかんや使いやすいんだろうなとは思います。ちょっと私はまだ慣れないけれど、必要になったところから宣言できるのは、「この宣言した変数どこから使い始めてるんだ?」となるよりソースの可読性が高くなると思えばいいものなのかもしれません。

let
Let It Go が思い浮かぶほど馴染みないものでした。なんやこれ。
なので実はあんま使ってなかった。これからきっと使いこなせるはず…!
varと使い方が似ているletの特徴は同じ名前の変数を作れないブロックスコープを意識していることです。
前項varで分かる通り、私が過去触れた言語(C、C#、C++など)は同じ名前の宣言ができません(別同士のブロックスコープであれば名前が同じでも可。ブロックスコープについては後ほど)。
なので私からするとletのほうが馴染みがあるものでした。びっくり!
ただまあ、例えば「タグ内のテキストを取得したい」とかだと変数名をtextとかにするのが分かりやすくて楽だし何かと多用してしまいそうなので、jsファイル内に1つだけの変数にしたいときに使うのがいいのかな?とか思いました。
…いや、下手なこと言っちゃいけないな…ううむ…

2つ目のブロックスコープを意識しているに触れていきます。
「ブロックスコープ?」と初めは疑問でしたが、C系時代は「当たり前すぎて一周回って意識しない」感じのものでした。
ブロックスコープとは{}で囲まれた領域内のことを指します。
昔はブロックレベルはなかったそうですが、ES2015(2015年に標準化されたJavaSciptの規格ECMASCriptのこと。6版であるためES6と呼ばれていたらしい)で新しくブロックレベルが追加されました。letが使えるようになったのもこのときです。
varではfor文やif文内で宣言した変数を外でも使えましたが、letは使えない…個人的に挙動としてはこちらのほうがしっくり来ます。

letもvarもデータの上書きが可能なので、どう使うのが良いかいろんなプログラム見てもう少し勉強が必要そうです。

const
これはC#やC++にあるのと同じものでした。
データ型の宣言がない点では違和感を覚えますが、JavaScriptはそういうものなんですね。
constは定数です。定数とは「値が変わらないもの」のことです。
サイトで使うJavaScriptはあまり数字が出てこない印象があるのですが、ゲームプログラムだと数字がたくさん出てきます。パラメーターあたりなんかは数字祭りですね。
プログラムを打つ中で数字を扱うとき、原則として数字の意味を明確にしなければなりません。パッと見てなにを表すかわからない数字のことをマジックナンバーといいます。魔法の数字、でもすっごく嫌われる数字です。初期化で使う0は例外だとは思いますが。
例えば、jQueryを使い「速度500ミリ秒(0.5秒)のスクロールアニメーションを実装しよう」とします。
当サイトでのやり方だと
$('a[href^="#"]').click(function () {
    let href = $(this).attr("href");
    let target = $(href == "#" || href == "" ? "html" : href);
    let position = target.offset().top;
    $("body,html").animate({ scrollTop: position }, 500, "swing");
    return false;
});

になるわけですが、上記だと「500」の数字がマジックナンバーです。
「なんの処理か分かるし500が何を意味してるか分かるから別にこのままでもいいんじゃ?」
と思うでしょう。自分ひとりで好きなようにやっているのであればそれでもかまわないと思います。
ただ、他に使う人がいる場合はたとえ相手が意味をわかったとしても定数化しておくべきでしょう。
上記のコードであれば
$('a[href^="#"]').click(function () {
    const animSpeed = 500;
    let href = $(this).attr("href");
    let target = $(href == "#" || href == "" ? "html" : href);
    let position = target.offset().top;
    $("body,html").animate({ scrollTop: position }, animSpeed, "swing");
    return false;
});

と言った感じにするのがいいかな?と思います。
横着してclickイベント内でconst宣言していますが、もし全体的によく使うものであればconstの宣言はファイルの一番最初にやるのが定石かなと思います。(C系で語ってるけどJavaScriptもそうだよね…?)
constで宣言されたものはデータの書き換えができません。これがvarやletとの大きな違いでしょう。
C系で使うときはデータ型が必要なのでconst float TAX = 1.1;みたいな使い方ですが、JavaScript はデータ型宣言がなくとも使えるので数字以外にタグやセレクタでも使えますね。(例:const TAX = document.getElementById("TAX");
何度も使うタグはconstで定義しておくと楽だと思います。

最後に
個人サイトを作った当初はなんとな~く「動けばいいや」と開設や運営に重きをおいていました。今ではJavaScriptで実装したいことがあればある程度自力で書けるようになったと思います。
そんな今だからこそ、基礎的な部分を学び直せば理解が深まるのではと(諸事情で買った)本を開きました。
まだまだ序盤しか読めていませんが、今の私にはちょうどよく分かりやすいので本で学んだことを自分の考えを添えて記事にしていこうと思います。
JavaScript勉強の旅は始まったばかりであるっ!

関連記事
JavaScriptを理解したいっ【命名編】

参考
JavaScriptでvarが非推奨な理由を整理してみた
改訂新版JavaScript本格入門モダンスタイルによる基礎から現場での応用まで
※私が参考にしたのは2019年発行のものですが、最新版があるのでご購入の際は最新版(改訂3版JavaScript本格入門
~モダンスタイルによる基礎から現場での応用まで
)が良いかと思います。

DASHBOARD

つぶやき

アカウント作成しました!
Twitter(現X)

全文検索

カレンダー

日付一覧を表示
2023年9月
12
3456789
10111213141516
17181920212223
24252627282930

Thanks !

Link

Contact

目次