アナログCPU:5108843109

ゲームと音楽とプログラミング(酒と女とロックンロールのノリで)

('ω') < イザユケエンジニャー

CSV取り込み時に日本語が無視される問題

初歩的な気がするけど。

諸々UTF-8に揃えているつもりなのに、
fgetcsvでCSVを取り込もうとすると日本語が無視される。
ローカル環境(windows/xampp)は大丈夫なのにサーバで動かすとダメ。

setlocaleされてないのが原因でした。
とりあえず処理の直前に入れてやっつけ解決。

setlocale(LC_ALL, 'ja_JP.UTF-8');

$csv_list = array();
while (($csv_list[] = fgetcsv($fp)) !== FALSE) { }

更なるやっつけ解決をするなら
csvのデータにはダブルクォートを付ける」でもOKだった。

SQX #7:原始ノ大密林/巨人の遺跡 その2

プレイ6~8日目。

気合入れて巨人の遺跡のマップは(ゴーレム部屋以外)埋めました。
f:id:honey8823:20180812155424j:plain:w400

全員Lv20になり、スキルもveteran枠が取れるようになりました。
f:id:honey8823:20180812155436j:plain:w400
f:id:honey8823:20180812155442j:plain:w400
そして宿代が最初の10倍。

巨人の遺跡はとりあえずここまでとして、探索司令部に行くとミッションが発令されました。
f:id:honey8823:20180812160035j:plain:w400

続きを読む

正規表現にマッチするかどうかを調べる

これも書き方を忘れるのでメモ。

基本的に

var pattern = new RegExp(正規表現);
pattern.test(文字列); // ←ここの戻り値がtrue/false

という二段構えになるようです。

具体例はこんな感じ。

var str1 = "1234";
var str2 = "123a";

var pattern = new RegExp(/[0-9]+/g); // 「数字のみ1字以上」の正規表現
console.log( pattern.test(str1) ); // true(「1234」はマッチする)
console.log( pattern.test(str2) ); // false(「123a」はマッチしない)

正規表現を使わず単純な文字列を含むかどうか、もいけます。

var str1 = "1234";
var str2 = "123a";

var pattern = new RegExp("3a");
console.log( pattern.test(str1) ); // false(「3a」を含まない)
console.log( pattern.test(str2) ); // true(「3a」を含む)

配列のjQuery式foreach

覚えられないのでメモ

その他配列処理は以前に書いたやつ参照
jsで配列操作いろいろ - アナログCPU:5108843109

基本

var list = [
    {"id" : 1, "value" : 100},
    {"id" : 2, "value" : 200},
    {"id" : 3, "value" : 300},
];

$(list).each(function(index, element) {
    console.log(index, element.id, element.value);
});

単純なループです。console.logの中身は
 index:何番目の要素か。0始まり。
 element.id:配列内の「id」の中身
 element.value:配列内の「value」の中身
ということで結果はこんな感じ。

0 1 100
1 2 200
2 3 300

breakする

途中でループから抜けたい場合は「return false;」です。
なるほどね。

// (配列定義部分は省略:さっきと同じやつ)

$(list).each(function(index, element) {
	if (element.id == 2){
		return false;
	}
    console.log(index, element.id, element.value);
});

id が2のときに抜けているので結果はこんな感じ。

0 1 100

continueする

ループの中身の処理を途中から無視して次の周に行きたい場合は「return true;」です。
なんでやねん。

// (配列定義部分は省略:さっきと同じやつ)

$(list).each(function(index, element) {
	if (element.id == 2){
		return true;
	}
    console.log(index, element.id, element.value);
});

id が2のときに無視するので結果はこんな感じ。

0 1 100
2 3 300

CSSで画面の一部だけをスクロール可能にする

デザイン的には諸刃の剣な感じがしますが、
新着情報やちょっとした一覧など、特定部分のみをスクロールさせたいとき。

スタイルに「overflow: auto;」もしくは「overflow: scroll;」を入れればOKです。
ただし、heightを指定しておく必要あり。
(ここでheightにパーセンテージ指定を使用したい場合は、
 上位要素のheightも指定する必要があることに注意)

尚、「auto」は必要なときだけスクロールバーが表示され、
「scroll」は強制的にスクロールバーが表示されます。

<div style="width: 200px; height: 50px; overflow: auto;">
内容
</div>

サンプル


あいうえお
かきくけこ
さしすせそ
たちつてと
なにぬねの
はひふへほ

みかんおいしい

iframeの親子間・子同士の操作いろいろまとめ

苦戦した~~~。

以下、こんな感じの構造を想定していきます。

<親 parent.html>

<div id="header">ヘッダ</div>

<iframe id="iframe_1" src="child_1.html">

<iframe id="iframe_2" src="child_2.html">

<子 child_*.html>

<div id="child_1_content">子1</div>
<div id="child_2_content">子2</div>

子から親を書き換える

<JS(子)>

$("#header", parent.document).text("ヘッダを更新");

親が、書き換えられたタイミングでアクションを起こす

<JS(子)>

parent.$("#header", parent.document).text("ヘッダを更新").change();

<JS(親)>

$("#header").change(function(){
	alert($("#header").text());
});

これはちょっと悩んだ。
子側で、明示的にchangeイベントを送ることと、先頭の「parent.」がポイント。

親から子を書き換える

<JS(親)>

$("#iframe_1").contents().find("#child_1_content").text("子1を更新");

書き換えだけならこれでOK。

ついでに、書き換えられたときに子側でアクションを起こしてみたかったのだがうまくいかなかった。
iframeに「name="hoge"」を足して
「document.hoge.$(document.hoge.document).find("#child_1_content").text("子1を更新").change();」
みたいなのを試してみたのだが「document.hoge は未定義」みたいなエラーになる。
とりあえず今は困ってないので未解決だけど一旦放置。
参考:jQueryでiframeと親window同士でイベントをtriggerする

子1から子2を書き換える

<JS(子1)>

parent.$("#iframe_2").contents().find("#child_2_content").text("子1から子2を更新");

子から子を書き換えるのが必要になってる時点で設計がおかしい気がしなくもない

子だけリロード(親側で操作)

<JS(親)>

$("#iframe_1")[0].contentDocument.location.reload(true);

子だけリロード(子自身で操作)

<JS(子)>

location.reload();

まあこれはフレーム関係ないんですけどね。
特に気にせず、フレーム内でリロードしてくれますということで。

子だけリロード(子1が子2を操作)

<JS(子)>

parent.$("#iframe_2")[0].contentDocument.location.reload(true);

子から子を書き換えるのが必要になってる時点でry

子だけページ遷移(親から操作)

<JS(親)>

$("#iframe_1")[0].contentDocument.location.replace("child_2.html");

子だけページ遷移(子自身で操作)

<JS(子)>

location.href = "child_2.html";

これもフレームは関係ないんですが、フレーム内で遷移してくれます。

子だけページ遷移(子1から子2の遷移を操作)

<JS(子1)>

parent.$("#iframe_2")[0].contentDocument.location.replace("child_1.html");

子から子を書き換えるのがry

SQX #6:原始ノ大密林/巨人の遺跡 その1

プレイ4~5日目。

前回、碧照ノ樹海を無事踏破。
さて次の迷宮は…と外に出てみると、碧照ノ樹海のそばに採集ポイントができました。
f:id:honey8823:20180806224509j:plain:w400
効率はよろしくないようですが、安全に採集できるところ、という様子。

キャンプに寄ると、ウィラフさんが次の迷宮について教えてくれます。
f:id:honey8823:20180806224520j:plain:w400
f:id:honey8823:20180806224626j:plain:w400
テンション上がってきた。

続きを読む

CSSでheightにパーセンテージを使えなくて困った話

CSS初心者は毎日色々困っています。

諸々のサイズ指定をするのに、
とりあえずわかりやすくパーセンテージ指定をしたいことが結構あるのですが
効くときと効かないときがある。

どういうことかと思って調べてたらたぶんこれだ…。

CSSでheight:100%を使う方法について。 | Ginpen.com

html要素とbody要素にheight:100%を指定

html, body {
  height: 100%;
}

親である要素のサイズが指定されていないとパーセンテージが使えないらしいので、
htmlやbodyを100%にしてしまえばOK、ということらしい。

長時間というか長期間?ハマってたのがやっと解決した…。
(めちゃくちゃ初歩的っぽい空気を感じる)

iframeのデメリットを無理矢理消化した実装(JS+PHP+Smarty版)

iframeの二大デメリット
「URLが切り替わらない(常にフレームの外側ページのもの)」
「内側ページのURLを直接叩くとフレームが出ない」
を解決すべく

とりあえず↑を検討した後、やっぱ微妙だなと思って
PHPSmartyの力も借りて実装したバージョン。

仕組みはそれなりに変わっていますが
HTMLとJSのコードは変わってないので(減っただけなので)
そのへんは省略します。上記の記事も併せて参考にしてください。

まずは完成サンプル

構成としては、JS版で作ったときと同じく
フレームページ(以下、親)と
iframe内側のコンテンツページ(以下、子)を作ることになりますが、
PHPSmartyも利用するので

  • 親テンプレート(Smarty, HTML, JS)
  • 親コントローラ(PHP, Smarty
  • 子ページ(HTML, JS)

を用意します。

親テンプレート(frame_parent.html)

ここはJS版とほぼ同じ。
Smartyテンプレートなので、iframeのsrc部分のみ「child_uri」で置換可能にしています。

JS部分はURLの書き換え処理のみ。(JS版の記事を参照)

<HTML+Smarty

<!-- header -->
<div style="height: 100px; background-color: #CCC">
  <div>
    <span><a href="frame_parent.html">親の再読み込み</a></span>
    <span><a href="frame_child_1.html" target="content_iframe">子1</a></span>
    <span><a href="frame_child_2.html" target="content_iframe">子2</a></span>
  </div>
</div>

<!-- iframe -->
<iframe id="content_iframe" name="content_iframe" src="{$child_uri}" style="width: 100%; height: calc(100% - 100px); border: 0;"></iframe>

<JS>

$('#content_iframe').load(function(){
    var contents = $("#content_iframe").contents();
    var url = contents[0].URL;
    var domain = "//" + contents[0].domain;
    var url_child = url.slice(url.indexOf(domain) + domain.length);
    history.replaceState("", "", url_child);
});
親コントローラ(frame.php

使用しているフレームワークなどによっていろいろと書き換える必要はありますが
簡単に、最低限必要な部分を記載。
PHP

<?
// $param_child_uriという変数に、
// 子から渡された子自身のパス(例:/frame_child_1.html)が入っているものとします。
// そのへんの処理は適宜…

// 子
// セットされている場合はそれを採用、
// セットされていない場合や空文字の場合はデフォルトページを指定
$child_uri = isset($param_child_uri) ? $param_child_uri : "";
$child_uri = ($child_uri == "") ? "frame_child_1.html" : $child_uri;

// テンプレートに表示対象の子ページパスをセットして呼び出し
$this->template->assign("child_uri" , $child_uri);
$this->template->display("smarty/template/frame_parent.html");
子ページ

HTML部分はなんでもいいので省略。
JSも、リダイレクト先が親のHTMLから親のPHPに変わっただけ。
もちろん子がPHPSmarty環境であってもOKです。とにかく↓のJSがあればOK。

<JS>

if(window == window.parent) {
    var childUri = location.pathname + location.search;
    location.href = "frame.php?child=" + childUri;
}

解説?

HTMLやJSについてはJS版の記事を参照してください。
JS版と異なるのは
「子のURLを直接指定されたときに、その子ページに親のフレームをくっつけて表示する」方法を
PHPSmartyを用いてちょっとキレイにした点のみです。

JS版では「指定された子を表示→親にリダイレクト→親のiframe内書き換え」となかなかアレな感じでしたが
こちらの方法では「指定された子を表示→親にリダイレクト(ただしiframeの中身は指定された子)」なので
一応ワンステップ減っています。

iframeのデメリットを無理矢理消化した実装(JS版)

iframeの二大デメリットといえば
「URLが切り替わらない(常にフレームの外側ページのもの)」
「内側ページのURLを直接叩くとフレームが出ない」
なんですが
これを解決しつつもiframeしたいと言われたのでちょっと考えました。

しかも新規開発ではなく既存のサイトにiframeを付けるという改修だったので
既存機能への影響や諸々のコストを考えて
JSのみで解決したいな…と思ってやってみたバージョン。

…ただ、あんまり格好良くなかったので、実務ではボツにしました。
JS+PHPSmarty版で実装したのがこちら。

JS版も使えなくはなさそうなので残しておきます。

JavaScriptは基本的にjQuery前提で書いています

まずは完成サンプル

フレームページ(以下、親)と
iframe内側のコンテンツページ2つ(以下、子1/子2)の
計3ファイルを用意します。

親(frame_parent.html)

ベタ書きでスタイル付けているのは見やすくするためだけのものなので消してOK。

<HTML>

<!-- header -->
<div style="height: 100px; background-color: #CCC">
  <div>
    <span><a href="frame_parent.html">親の再読み込み</a></span>
    <span><a href="frame_child_1.html" target="content_iframe">子1</a></span>
    <span><a href="frame_child_2.html" target="content_iframe">子2</a></span>
  </div>
</div>

<!-- iframe -->
<iframe id="content_iframe" name="content_iframe" src="frame_child_1.html" style="width: 100%; height: calc(100% - 100px); border: 0;"></iframe>

<JS>

$('#content_iframe').load(function(){
    var contents = $("#content_iframe").contents();
    var url = contents[0].URL;
    var domain = "//" + contents[0].domain;
    var url_child = url.slice(url.indexOf(domain) + domain.length);

    history.replaceState("", "", url_child);
});

var child = getParam("child");
if (child != null && child != ""){
    $("#content_iframe")[0].contentDocument.location.replace(child);
}

function getParam(name) {
    var url = window.location.href;
    name = name.replace(/[\[\]]/g, "\\$&");
    var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)");
    var results = regex.exec(url);
    if (!results) return null;
    if (!results[2]) return '';
    return decodeURIComponent(results[2].replace(/\+/g, " "));
}
子1/子2(frame_child_1.html / frame_child_2.html)

<HTML 子1>

<div>子1</div>
<div><a href="frame_child_2.html">→子2へフレーム内遷移</a></div>

<HTML 子2>

<div>子2</div>
<div><a href="frame_child_1.html">→子1へフレーム内遷移</a></div>

<JS 共通>

if(window == window.parent) {
    var childUri = location.pathname + location.search;
    location.href = "frame_parent.html?child=" + childUri;
}


以下は解説・メイキングです。

とりあえず親となるiframeページを用意する

HTML部分は完成品と同じなので省略します。そちらを参照。

ポイントは以下。

  • iframeにname(content_iframe)を付けている
    • 同名のidも付けている。あとで使う。
  • 共通部分からの子1・子2へのリンクtargetにはiframeの名前を指定
    • これでフレームの中に表示する。省略するとページ遷移が起こる(親へのリンク部分参照)
  • iframe内にはデフォルトで子1を表示するよう指定

子となるページを用意する

これもHTML部分は完成品と同じなので省略。
こちらは区別がつけば何でもOK。
一応、確認用にリンクタグを設置。target省略でフレーム内遷移します。

親と子が揃ったら簡単に動作を確認。
各リンクを踏んで、意図通りであればOK。

親のURLを子のものに書き換える

リンク遷移は正常ですが、
当然ながらブラウザに表示されているURLは常に親のものです。

これを、ページ遷移が起こるごとに子のものに書き換えてみます。

まず、iframeとか関係なく
URLを書き換えるだけのJSはこちら。ルートを意識して書きます。

// example.com/test/fuga.html → example.com/test/hoge.html
history.replaceState("", "", "hoge.html");

// example.com/test/fuga.html → example.com/hoge.html
history.replaceState("", "", "/hoge.html");

これをベースにしつつ、実際は子のURLに書き換えたいので
必要な処理をがつがつ加えます。
<親(JS)>

// iframeの中身を取得
var contents = $("#content_iframe").contents();
// iframeの中身のURLとドメイン部分を取得
// ドメイン部分は後で文字列操作するので「//」を加えておく
var url = contents[0].URL;
var domain = "//" + contents[0].domain;
// ドメインより後の部分を切り出す(example.com/test/hoge.html → /test/hoge.html)
var url_child = url.slice(url.indexOf(domain) + domain.length);
// 切り出したURLで書き換える
history.replaceState("", "", url_child);

これを親のHTML内に置いて再読み込みしてみると、
デフォルトで表示される子1のURLに書き換わります。

さらに子が切り替わるたびにこのスクリプトを動作させたいので、
「iframeの中身が読み込まれたら実行する」という処理にします。
<親(JS)>

$('#content_iframe').load(function(){
    var contents = $("#content_iframe").contents();
    var url = contents[0].URL;
    var domain = "//" + contents[0].domain;
    var url_child = url.slice(url.indexOf(domain) + domain.length);
    history.replaceState("", "", url_child);
});

一番上と一番下の行が追加部分です。
これで各リンクを踏んでみると、意図したとおり、
子の読み込み時にURLが切り替わるようになりました。

子のURLに直接アクセスされたときにフレームを表示する

厄介なのがここ。

まずは親ページにリダイレクトさせる

これはめちゃくちゃ簡単。
子に以下のJSを設置するだけ。
<子(JS)>

if(window == window.parent) {
    location.href = "frame_parent.html";
}

「自身がiframeの中に入っていない場合、親にリダイレクト」をしています。
場合によってはこれで充分かもしれませんが、
今回は指定されたURLの子ページを表示させたいのでもう少し考えます。

子から親に、自身の情報を渡す

先ほどのJSを少し書き換えて、リダイレクト時に自身のパスを渡してみます。
<子(JS)>

if(window == window.parent) {
    // ドメインより後の部分を取得
    var childUri = location.pathname + location.search;
    location.href = "frame_parent.html?child=" + childUri;
}

リダイレクトした後に親側でReferrerで子ページのURLを取得することもできますが、
必ずしもフレームを付ける処理を行いたいとも限らないので、
明示的に渡すようにしました。
(例えば、フレームなしのログインページから
 フレームありのデフォルト親ページに遷移したいとき、
 ログインページにフレームを付けられても困る)

親側で、子の情報を受け取った場合のみiframeの中身を書き換える

子から渡したパラメータ「child」ですが、
親側でこれを確認できた場合のみ、iframeの中身をそれに書き換える、という方法をとります。

パラメータ取得関数「getParam」は詳しい解説を省略しますが、
例えば「?hoge=abc&fuga=def」のようなパラメータをうまいこと分割してくれるやつです。
今回は、「?child=frame_child_2.html」を
「childというパラメータの中身はframe_child_2.html」と認識するために使っています。

<親(JS)>

// 渡されたパラメータを取得
var child = getParam("child");
// パラメータが存在する場合、iframeの中身を書き換える
if (child != null && child != ""){
    $("#content_iframe")[0].contentDocument.location.replace(child);
}

// パラメータ取得関数(stackoverflowより拝借)
// https://stackoverflow.com/questions/901115/how-can-i-get-query-string-values-in-javascript
function getParam(name) {
    var url = window.location.href;
    name = name.replace(/[\[\]]/g, "\\$&");
    var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)");
    var results = regex.exec(url);
    if (!results) return null;
    if (!results[2]) return '';
    return decodeURIComponent(results[2].replace(/\+/g, " "));
}
動作確認して完了

URLを直接指定したときにチラチラして鬱陶しいですが
(指定された子を表示→親にリダイレクト→親のiframe内書き換え)
通常のフレーム内遷移では問題ないので、
直接指定される機会が少ない場合はアリかなと思いました。