サインインユーザと非サインユーザに対する文章表示切替

Created by C-takeC-take

構文の意義

2017年7月1日にSCP財団というサイトで行われた定例会で誰でも使えるギミック芸四天王の一角として

[[module ListUsers users="."]]

が挙げられていました。この構文は例えば

[[module ListUsers users="."]]
%%name%%
[[/module]]

と書けば、wikidotにサインインしたユーザが記事を閲覧した時は%%name%%の所に名前が表示されるというものです。

しかしこの構文には致命的な欠点があります。それは wikidotにサインインしていないユーザが記事を見た時、[[module ListUsers users="."]]~[[/module]]の間に書かれている文章が何も表示されなくなる事です。

SCP財団は非公式翻訳wikiと統合され、非公式翻訳wikiは閉鎖予定です。非公式翻訳wikiでは非wikidotユーザに対する配慮をおこなった記事作りしており、それを鑑みるとSCP財団のメンバーはそろそろ非サインインのユーザにも配慮した記事作りをしなければならないのかも知れません。

そこで今回は[[module ListUsers users="."]]を使ったサインイン時と非サインイン時の表示切替についてお伝えします。

説明

下記の構文です。赤字がミソ
構文:

[[module css]]
.textchange div.sitemember:nth-child(2) {
display:none;
}
[[/module]]

[[div class="textchange"]]
[[module ListUsers users="."]]
[[div class="sitemember"]]
ここがwikidotにサインインしているユーザに見える文章。
ようこそ%%name%%さん!
[[/div]]
[[/module]]
[[div class="sitemember"]]
ここが非サインインユーザに見える文章です。
ようこそゲストさん!
[[/div]]
[[/div]]テスト文章

表示例:

ここが非サインインユーザに見える文章です。
ようこそゲストさん!

テスト文章

上記の構文にあるcss

[[module css]]
.textchange div.sitemember:nth-child(2) {
display:none;
}
[[/module]]

を適用すれば、後は任意の数の

[[div class="textchange"]]
[[module ListUsers users="."]]
[[div class="sitemember"]]
ここがwikidotにサインインしているユーザに見える文章。
ようこそ%%name%%さん!
[[/div]]
[[/module]]
[[div class="sitemember"]]
ここが非サインインユーザに見える文章です。
ようこそゲストさん!
[[/div]]
[[/div]]テスト文章

という形の構文を書けば、その数分ページ切り替え箇所が作れます。

仕組みについては:nth-child(n)というCSSの機能そのままなので下記をご参照ください。

:nth-child - CSS | MDN

これと[[module ListUsers users="."]]に囲んだ文章は非サインインのユーザには表示されなくなる。正確に言えばhtmlに変換されなくなる特性を利用しています。

ただし、[[div class="textchange"]]の中に[[div class="sitemember"]]以外のdiv要素を置くと構文がきちんと機能しなくなります。その場合は:nth-childの機能を理解した上でご調整をお願いします。

最後に注意点として、文章切替箇所以降の文章(今回のサンプルで言えば「テスト文章」)は[[/div]]の後に改行を挟まず続けてご記入ください。そうしなければ文章切替箇所とそれ以降の文章に余分な改行が挟まります。

この構文を利用すれば、非サインインユーザには「不正閲覧」、サインインユーザには「ようこそ<アカウント名>様」と表示されるギミックも作る事ができます。ただこういうギミックを仕組んでも、気付く人はあまりいないと思いますし、私も実際にそんなギミックが仕込まれている記事を閲覧してもギミックの存在に気付かないと思いますが。

当面は非サインインのユーザにも配慮した記事を書く際に活用できるでしょう。

サンプル

構文例:
CSS

[[module css]]
.textchange div.sitemember:nth-child(2) {
display:none;
}
[[/module]]

表示切替部分

[[div class="textchange"]]
[[module ListUsers users="."]]
[[div class="sitemember"]]
ようこそ%%title%%さん!
[[/div]]
[[/module]]
[[div class="sitemember"]]
ようこそゲストさん!
[[/div]]
[[/div]]これは共通の文章です。
[[div class="textchange"]]
[[module ListUsers users="."]]
[[div class="sitemember"]]
あなたはサインインユーザです。
[[/div]]
[[/module]]
[[div class="sitemember"]]
あなたはサインインしていません。
[[/div]]
[[/div]]

表示例:

ようこそゲストさん!

これは共通の文章です。

あなたはサインインしていません。

閲覧者ユーザネームのスクリプトへの受け渡し例

これは比較的高度な技法になります。iframe間で通信を行う技法を前提にしています。

サンプル:
ボタンを押した時、ユーザの状態に応じて下記の文章をアラートします。

  • サインイン時: "サインイン : " + <user_name>
  • サインアウト時: "非サインイン : ゲスト"

ソースコード: 3つの構文で成り立ちます。

まずローカルコードを作ります。これは自身のURLにパラメータがついている場合、requestを受信した際、受信した相手にパラメータを渡すローカルコード(htmlファイル)です。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja" lang="ja">
<head>
<meta http-equiv="Content-Script-Type" content="text/javascript"/>
<meta http-equiv="Content-Style-Type" content="text/css"/>
<meta http-equiv="content-language" content="ja,jp-ja"/>
<meta charset="UTF-8"/>
<title>userNameを送る</title>
<script type="text/javascript">
//ユーザネームを取得
var userName = decodeURI(window.location.href.split("#")[1]);
var send = false;
var frames = window.parent.window.frames;
 
window.addEventListener("message",function(event){
    //リクエストを受け取るまでこのスクリプトは始動しない
    if(typeof(event.data) != "string")return;
    if(event.data.indexOf(",") < 0)return;
    var type = event.data.split(",")[0];
    switch(type){
        case "request":
            //リクエストを受け取った時
            if(send)return;
            send = true;
            sendUserName(Number(event.data.split(",")[1]));
        break;
        case "success":
            //受信完了を受け取った時
            send = false;
        break;
    }
});
 
function sendUserName(bro){
    //相手側のデータ受信失敗に備えた繰り返し処置
    frames[bro].window.postMessage(userName,"*");
    if(send)setTimeout(function(){sendUserName(bro)},50);
}
</script>
</head>
<body>
</body>
</html>


上記のローカルコードを呼ぶ際の形式です。

[[module ListUsers users="."]]
[[embed]]
<iframe src="http://shitake-crude-production.wikidot.com/sitemember-textchanger/code/1#%%title%%" name="userName" style="display:none;"></iframe>
[[/embed]]
[[/module]]


ローカルコードにリクエストを送り、尚且つ受信する場合の構文例です。上記のユーザネームを格納するiframeにリクエストを送る文章、"request,n"の内、nには受信側(自身)のiframe番号を記入してください。

[[html]]
<script type="text/javascript">
var request = false;
var target;
 
document.addEventListener("DOMContentLoaded",function(){
    target = document.getElementById("target");
    //存在しないiframeを取得しようとするとクロスオリジンエラーが発生する事を利用して条件分岐
    try{
        //ユーザがサインイン状態の時    
        var check = window.parent.window.userName;
        request = true;
        //リクエスト送信
        window.parent.window.userName.window.postMessage("request,0","*");
 
        window.addEventListener("message",function(event){
            //ユーザネームを受け取った際、データを格納し、送信先に受信完了のメッセージを送る
            window.parent.window.userName.window.postMessage("success,0","*");
            if(!request)return;
            target.style.display = "block";
            target.getElementsByTagName("button")[0].setAttribute("onclick",'alert("サインイン : ' + event.data +'");');
            request = false;
 
        });
        requestingUserName();
    }catch(e){
        //サインアウトの場合、デフォルトの文章を格納    
        target.style.display = "block";
        target.getElementsByTagName("button")[0].setAttribute("onclick",'alert("非サインイン : ゲスト");');
    }
});
 
function requestingUserName(){
    //相手側のリクエスト受信の失敗に備えた繰り返し処置
    window.parent.window.userName.window.postMessage("request,0","*");
    if(request)setTimeout(requestingUserName,50);
}
 
</script>
<div id="target" style="display:none;text-align:center;">
<button>UserName</button>
</div>
[[/html]]
Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License