SQLの窓

2016年10月03日


Firebase API + Android Studio : Database のデータを Java に取得する方法は3通りあります。(orderByChild 使う場合は、getChildren してから)

2016/10/03 : orderByChild の処理 を追加しました
記事末に、@IgnoreExtraProperties アノテーションの説明を追加しました。
記事末に、『JSON データを直接使用する』もあります。

ArrayList として取得
HashMap として取得
Userクラスとして取得
全体ソース
まず、環境とプロジェクトの作成方法は、『Firebase API + Android Studio : Database 処理の基本設定』にまとめました。そちらを参照して下さい。 Firebase の Database は、JSON をイメージした格納方法になっており、データはツリー構造の末端にあると考えて、そこまでのパスを指定して読み出します。ここでは、以下のようなデータを想定しており、0、1、2、の部分は配列のインデックスを意味しています。 ArrayList として取得 users を パスとして与えて取得すると、その下は配列なので ArrayList として取得する事ができます。また、users/0 のパスで取得するデータは クラス(User)を作成して、User.class を使用して Userクラスのインスタンスに直接セットする事ができます。そして、users を パス とした場合は ArrayList<User> としても取得する事ができます。
GenericTypeIndicator<ArrayList<User>> t = new GenericTypeIndicator<ArrayList<User>>() {};

ArrayList<User> user = dataSnapshot.getValue(t);
Iterator<User> it = user.iterator();
while( it.hasNext() ) {
	User work = it.next();
	Log.i("lightbox", work.getCode() );
	Log.i("lightbox", work.getName() );
}


DataSnapshot dataSnapshot は、Database のデータを取得する onDataChange イベントのパラメータとして使用可能なもので、この中にデータがセットされています。

そして、ArrayList は 以下のようにして配列に変換して利用してもいいでしょう。
User[] users = user.toArray(new User[0]);

for( int i = 0; i < users.length; i++){
	Log.i("lightbox", users[i].getCode() );
	Log.i("lightbox", users[i].getName() );
}


HashMap として取得

User クラスを作成しない場合、users を パスとした場合の一般的な方法として ArrayList<HashMap<String,Object> として取得する事ができます。
GenericTypeIndicator<ArrayList<HashMap<String,Object>>> t2
	= new GenericTypeIndicator<ArrayList<HashMap<String,Object>>>() {};

ArrayList<HashMap<String,Object>> useList = dataSnapshot.getValue(t2);

Iterator<HashMap<String,Object>> it2 = useList.iterator();
while( it2.hasNext()) {
	HashMap<String,Object> userMap = it2.next();
	Log.i( "lightbox", userMap.get("code").toString() );
	Log.i( "lightbox", userMap.get("name").toString() );
}


Userクラスとして取得
User user = dataSnapshot.getValue(User.class);

TextView tv1 = (TextView) MainActivity.this.findViewById(R.id.textCode);
tv1.setText(user.getCode());
TextView tv2 = (TextView) MainActivity.this.findViewById(R.id.textName);
tv2.setText(user.getName());

※ クラスで定義するフィールドの整数は long で定義して下さい。(関連 API ドキュメント情報)

クラス内の変数は、public のフィールドで定義してもかまいませんし、setter / getter で定義してもかまいません。排除したいフィールドは、@Exclude アノテーションを使用できます。

また、クラスには引数の無い処理の無いデフォルトコンストラクタを定義しておいて下さい。以下のような但し書きがあります
Default constructor required for calls to DataSnapshot.getValue(User.class)
※ 概要印刷用 PDF ※ ソース全体印刷用 PDF データを取得する為の addListenerForSingleValueEvent ドキュメントには、『Read data once』とタイトルして解説されていますが、必要な時にデータを取得する為のイベントの登録処理です。他のリスナーは、状態が変化した時に取得可能なもので、上のリンク先のページの『Listen for events』で解説されています。 addListenerForSingleValueEvent は、一般的にサーバよりデータを取得するメソッドとして使用され、この中のイベントで DataSnapshot を使ってデータにアクセスします。 3種類の取得パターンの全体ソース
public class MainActivity extends AppCompatActivity {

	private FirebaseDatabase database;
	private DatabaseReference mDatabase;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		database = FirebaseDatabase.getInstance();
		mDatabase = database.getReference();

		Button readButton = (Button) MainActivity.this.findViewById(R.id.readButton);
		readButton.setOnClickListener(new View.OnClickListener() {
			@Override
			public void onClick(View v) {

				mDatabase.addListenerForSingleValueEvent(new ValueEventListener() {
					@Override
					public void onDataChange(DataSnapshot dataSnapshot) {
						if ( dataSnapshot.exists() ) {
							Log.i("lightbox", dataSnapshot.getValue().toString());
						}
					}

					@Override
					public void onCancelled(DatabaseError databaseError) {

					}
				});


				mDatabase.child("users").addListenerForSingleValueEvent(new ValueEventListener() {
					@Override
					public void onDataChange(DataSnapshot dataSnapshot) {
						if ( dataSnapshot.exists() ) {
							Log.i("lightbox", "-- users の状態");
							Log.i("lightbox", dataSnapshot.getValue().toString());
							Log.i("lightbox", "-- ArrayList<User>");

							GenericTypeIndicator<ArrayList<User>> t = new GenericTypeIndicator<ArrayList<User>>() {};
							ArrayList<User> user = dataSnapshot.getValue(t);
							Iterator<User> it = user.iterator();
							while( it.hasNext() ) {
								User work = it.next();
								Log.i("lightbox", work.getCode() );
								Log.i("lightbox", work.getName() );
							}

							Log.i("lightbox", "-- 配列");

							User[] users = user.toArray(new User[0]);
							for( int i = 0; i < users.length; i++){
								Log.i("lightbox", users[i].getCode() );
								Log.i("lightbox", users[i].getName() );
							}

							Log.i("lightbox", "-- ArrayList<HashMap<String,Object>>");

							GenericTypeIndicator<ArrayList<HashMap<String,Object>>> t2
								= new GenericTypeIndicator<ArrayList<HashMap<String,Object>>>() {};
							ArrayList<HashMap<String,Object>> useList = dataSnapshot.getValue(t2);
							Iterator<HashMap<String,Object>> it2 = useList.iterator();
							while( it2.hasNext()) {
								HashMap<String,Object> userMap = it2.next();
								Log.i( "lightbox", userMap.get("code").toString() );
								Log.i( "lightbox", userMap.get("name").toString() );
							}
						}
						else {
							Log.i("lightbox","データを読み込めませんでした");
						}
					}

					@Override
					public void onCancelled(DatabaseError databaseError) {
						Log.i("lightbox","onCancelled");
						StringWriter sw = new StringWriter();
						PrintWriter pw = new PrintWriter(sw);
						databaseError.toException().printStackTrace(pw);
						pw.flush();
						String stackTrace = sw.toString();
						Log.i("lightbox",stackTrace);

					}
				});

			}
		});

		Button readUserButton = (Button) MainActivity.this.findViewById(R.id.readUserButton);
		readUserButton.setOnClickListener(new View.OnClickListener() {
			@Override
			public void onClick(View v) {

				mDatabase.child(String.format("users/%d",0)).addListenerForSingleValueEvent(new ValueEventListener() {
					@Override
					public void onDataChange(DataSnapshot dataSnapshot) {
						if ( dataSnapshot.exists() ) {
							Log.i("lightbox", dataSnapshot.getValue().toString());

							User user = dataSnapshot.getValue(User.class);

							TextView tv1 = (TextView) MainActivity.this.findViewById(R.id.textCode);
							tv1.setText(user.getCode());
							TextView tv2 = (TextView) MainActivity.this.findViewById(R.id.textName);
							tv2.setText(user.getName());
						}
					}

					@Override
					public void onCancelled(DatabaseError databaseError) {

					}
				});

			}
		});


	}

	public static class User {

		private String code;
		private String name;

		public User() {}

		public User(String code, String name) {
			this.code = code;
			this.name = name;
		}

		public String getCode() {
			return code;
		}
		public String getName() {
			return name;
		}
		public void setCode(String code) {
			this.code = code;
		}
		public void setName(String name) {
			this.name = name;
		}

	}

}


orderByChild の処理

ツリーが 配列では無くHashMap で構成されているデータは、直接 HashMap に格納できますが、順序が保証されないので、orderByChild メソッドを使用してデータをソートしてから取得します。その場合は、DataSnapshot から getChildren メソッドで一覧を取得する必要があります
				mDatabase.child("class").orderByChild("code").addListenerForSingleValueEvent(new ValueEventListener() {
					@Override
					public void onDataChange(DataSnapshot dataSnapshot) {
						if ( dataSnapshot.exists() ) {

							userList = new ArrayList<User>();

							Iterator<DataSnapshot> child = dataSnapshot.getChildren().iterator();
							while(child.hasNext()) {
								DataSnapshot next = child.next();
								User user = next.getValue(User.class);

								userList.add(user);
							}


						}
						else {
							Log.i("lightbox","データを読み込めませんでした");
						}
					}

					@Override
					public void onCancelled(DatabaseError databaseError) {
						Log.i("lightbox","onCancelled");

					}
				});


※ 印刷用 PDF
※ 印刷用 PDF(Module Gradle)

@IgnoreExtraProperties アノテーションについて



結局付けても付けなくても直接の動作には影響ありません。ただ、付けない場合はログにワーニングが表示され、付けるとワーニングは表示されません。

これは、開発中に Database 側にあって、クラス側に無いデータをクラスを使って読み込んだ時に確認できる内容になると思います。

Firebase ドキュメント : Update your Java model objects

@Exclude アノテーションについて

上のリンク先では、@Exclude についても記述されています。これを使用すると、意図的にそのフィールドを排除できます。サンプルでは、public なフィールドに設定されていますが、setter/getter に対して指定できます。

補足 : JSON データを直接使用する

データベースのルールが ".read": true になっている場合は、Firebase のプロジェクトの Database の URL で直接 JSON 文字列を使用できます。ルートは https://プロジェクトid.firebaseio.com/.json で取得でき、他のパスは、.json を拡張子として付加すると取得できます。
※ ?print=pretty というパラメータを指定できます(整形します)

▼ 公開サンプル
https://json-sample-b69b7.firebaseio.com/.json?print=pretty
https://json-sample-b69b7.firebaseio.com/users/0.json
▼ JSONLint にて整形
http://jsonlint.com/?json=https://json-sample-b69b7.firebaseio.com/.json

また、このアクセスは、Access-Control-Allow-Origin:* を返すので、jQuery で簡単に利用可能です。(ルールが要ログインの場合は、アクセストークンが必要になり、Android だけで利用するのは結構面倒になります)

関連する記事

Firebase API + Android Studio : Database にデータを保存は単純で、DatabaseReference の setValue メソッドを使用します

Firebase API + Android Studio : Database 処理の基本設定

Android Studio 2.2 で新規プロジェクトを作成すると『Could not reserve enough space for 1572864KB object heap』というエラーが出る場合の対処方法



posted by lightbox at 2016-10-03 19:04 | 2016 Android Studio | このブログの読者になる | 更新情報をチェックする

jQuery で既存 table より Firebase Database のデータを作成する

サンプルページ


このページでは実際には更新できませんが、自分のスニペットをコピーして貼り付けて使用すると更新できます。このデータは Wikipedia にあるテーブルをデベロッパーツールでコピーして貼り付けたものです。欲しい行を限定したい場合は、先頭の TD に class="result" を入れておくというスタイルです。

二番目の処理は、TR の中に TD が無いので、JSON の中に jojo0 は作成されますが、値が空のオブジェクトとなるのでデーターベースにデータは作成されません

更新部分のソースコード
<script>

var jojo = { };

$(function(){

	$("#update1").on("click",function(){
		
		if ( confirm( config.authDomain + "へ更新しますか? \n(ルールで更新を許す必要があります)" ) ) {

			$(".result").each( function( idx ){
			
				jojo["jojo" + (idx+1) ] = {};
				
				$(this).parent().find("td").each( function( idx2 ){
				
					jojo["jojo" + (idx+1) ]["data" + idx2] = $(this).text();
				
				} );
				
			
			} );
			
			firebase.database().ref("jojo").set(jojo).then(
					function(){
						alert( "更新に成功しました" );
					}
			);

		}
	});

	$("#update2").on("click",function(){
		
		if ( confirm( config.authDomain + "へ更新しますか? \n(ルールで更新を許す必要があります)" ) ) {

			$("tr").each( function( idx ){
			
				jojo["jojo" + idx ] = {};
				
				$(this).find("td").each( function( idx2 ){
				
					jojo["jojo" + idx ]["data" + idx2] = $(this).text();
				
				} );
				
			
			} );
			
			firebase.database().ref("jojo").set(jojo).then(
					function(){
						alert( "更新に成功しました" );
					}
			);

		}
	});

	$("#update3").on("click",function(){
		
		if ( confirm( config.authDomain + "へ更新しますか? \n(ルールで更新を許す必要があります)" ) ) {

			$("tr").each( function( idx ){
			
				jojo["jojo" + idx ] = {};
				
				$(this).find("td,th").each( function( idx2 ){
				
					jojo["jojo" + idx ]["data" + idx2] = $(this).text();
				
				} );
				
			
			} );
			
			firebase.database().ref("jojo").set(jojo).then(
					function(){
						alert( "更新に成功しました" );
					}
			);

		}
	});

});

</script>
※ データベースルールを書き込み可能にしておく必要があります


タグ:jquery Firebase
posted by lightbox at 2016-10-03 02:17 | Google | このブログの読者になる | 更新情報をチェックする

jQuery + Bootstrap(css) + mmenu : Firebase Database 参照と更新サンプル( 新規登録テンプレートより )

デモ( ログインはハンバーガメニューより選んで下さい )
 
※ 実際の更新はできません



新規登録テンプレートを元に、クラスメンバを修正する2会話のアプリケーションのサンプルです。新規登録と違う所は殆ど無く、データの存在チェックで内容を表示しています。
			// データベース参照
			var myFirebaseRef = firebase.database().ref('class/' + $("#key_fld").val() );

			// **************************************
			// データ存在チェック
			// **************************************
			myFirebaseRef.once('value', 
				function(snapshot) {

					if ( !snapshot.exists() ) {
						options.error( "データが存在しません" );
						return;
					}

					// 第二会話へ変更
					options.pass2();

					// フォーカス
					if ( !$.isMobile ) {
						$("#row2_fld").focus();
					}

					var user_data = snapshot.val();
		
					$("#row2_fld").val(user_data.name);
					$("#row3_fld").val(user_data.furi);
					$("#row4_fld").val(user_data.kyuyo);
					$("#row5_fld").val(user_data.sex);
					$("#row6_fld").prop( "checked", user_data.kanri );

				},
				function(error){
					$(".result").each(function(){
						$(this).next().text( error[ options[ $(this).prop("id") ].title ] );
					});
					options.error( "Firebase エラーです" );

					console.dir(error);
				}
			);
※ データの更新は、新規も修正も同じです。

左の画像は、toastr.js で表示されたエラーメッセージを表示したところですが、PC の場合は、ページ上部の中央に表示されます。

右の画像は、HTML の pattern 属性によるチェックが行われ、メッセージが表示されています。

データフォーマット



ソースコード

ダウンロードパッケージの中は、php としてテンプレート化されています。メインのコードは、view_main.php で、index.php から読み込まれます。
<?php
// *************************************
// セッション変数
// *************************************
session_start();

// *************************************
// ブラウザに対する指示
// *************************************
header( "Content-Type: text/html; charset=utf-8" );
header( "Expires: Wed, 31 May 2000 14:59:58 GMT" );
header( "x-ua-compatible: IE=11" );

require_once("view_main.php");
?>


view_main.php
<?php
// *************************************
// 表示コントロール
// *************************************
$GLOBALS['title'] = "2会話・テンプレート(修正)";
$GLOBALS['comment'] = 'ようこそ jQuery + Bootstrap(css) + mmenu + Firebase';

?>
<!DOCTYPE html>
<html lang="ja">
<head>
<meta content="width=device-width initial-scale=1.0 minimum-scale=1.0 maximum-scale=1.0 user-scalable=no" name="viewport">
<meta charset="utf-8">
<title><?= $GLOBALS['title'] ?></title>

<?php require_once('../std/libs.php') ?>

<link rel="stylesheet" href="../std/mmenu.css">
<link rel="stylesheet" href="../std/basic.css">

<?php require_once('../std/firebase.php') ?>

<style>
.fields {
	width: 90px;
	font-size: 12px;
	vertical-align: middle!important;
}

legend {
	font-size: 18px;
	padding-left: 6px;
}
</style>

<script>
<?php require_once('../std/js.php') ?>
var options = {
	key : { title :"クラス", css : { width : "100px" }, attr : { pattern : "[0-9]+", type: "tel" } },
	row2 : { title : "氏名"  },
	row3 : { title : "フリガナ"  },
	row4 : { title : "給与", attr : { pattern : "[0-9]+", type: "tel" } },
	row5 : { title : "性別", css : { height : "40px" } },
	row6 : { title : "管理者", label : "部下の有無"  },
	row_last : { title :"メッセージ" },
	erow1 : { title : "code"  },
	erow2 : { title : "message"  },

	curbtn: "",
	pass1 : function(){
		// 第一会話へ変更
		$("#form_head").prop("disabled", false );
		$("#form_body").prop("disabled", true );
	},
	pass2 : function(){
		// 第二会話へ変更
		$("#form_head").prop("disabled", true );
		$("#form_body").prop("disabled", false );
	},
	clear : function(){
		// 全てクリア
		$(".fields").next().find("input[type='text'],input[type='tel']").val("");
		$(".fields").next().find("input[type='checkbox']").prop("checked", false);
		$(".fields").next().find("select").prop("selectedIndex", 0);
	},
	error : function(message){
		$("#row_last").next().text( message );
		toastr.error(message);
	},
	info : function(message){
		$("#row_last").next().text( message );
		toastr.success(message);
	}
};

$(function(){

	// 1) options による行とフィールドの設定
	// 2) Bootstrap 用 form-control クラスの追加
	$(".fields").each(function(){
		if ( options[ $(this).prop("id") ] ) {
			$(this).text( options[ $(this).prop("id") ].title );
			// 個別 css
			if ( options[ $(this).prop("id") ].css ) {
				$(this).next().find("input,select").css( options[ $(this).prop("id") ].css );
			}
			// 入力チェック用属性
			if ( options[ $(this).prop("id") ].attr ) {
				$(this).next().find("input,select").attr( options[ $(this).prop("id") ].attr );
			}
			// 行内個別 ラベル
			if ( options[ $(this).prop("id") ].label ) {
				$(this).next().find("label").text( options[ $(this).prop("id") ].label );
			}
		}
		// Bootstrap form
		$(this).next().find("input,select").addClass("form-control");
	});
	// スマホでロード時の処理のチラつき防止用
	$("#wrapper").css("visibility","visible"); 

	// 第一会話
	options.pass1();

	// 初期フォーカス
	setTimeout( function(){$('#key_fld').focus();}, 100 );

	// 確認処理
	$("#frm").submit( function(event){
		// 本来の送信処理はキャンセル
		event.preventDefault();

		// エラーメッセージエリアをクリア
		$(".error").next().text( "" );

		// 確認ボタン
		if ( options.curbtn == "button_head" ) {

			// **************************************
			// 第一会話入力チェック
			// **************************************
			if ( $("#key_fld").val().trim() == "" ) {
				options.error( options['key'].title + " を入力して下さい" );
				return;
			}

			// **************************************
			// Firebase ログインチェック
			// **************************************
			user = firebase.auth().currentUser;
			if ( user == null ) {
				options.error( "ログインされていません" );
				return;
			}

			// データベース参照
			var myFirebaseRef = firebase.database().ref('class/' + $("#key_fld").val() );

			// **************************************
			// データ存在チェック
			// **************************************
			myFirebaseRef.once('value', 
				function(snapshot) {

					if ( !snapshot.exists() ) {
						options.error( "データが存在しません" );
						return;
					}

					// 第二会話へ変更
					options.pass2();

					// フォーカス
					if ( !$.isMobile ) {
						$("#row2_fld").focus();
					}

					var user_data = snapshot.val();
		
					$("#row2_fld").val(user_data.name);
					$("#row3_fld").val(user_data.furi);
					$("#row4_fld").val(user_data.kyuyo);
					$("#row5_fld").val(user_data.sex);
					$("#row6_fld").prop( "checked", user_data.kanri );

				},
				function(error){
					$(".result").each(function(){
						$(this).next().text( error[ options[ $(this).prop("id") ].title ] );
					});
					options.error( "Firebase エラーです" );

					console.dir(error);
				}
			);

		}

		// 更新ボタン
		if ( options.curbtn == "button_body" ) {

			// **************************************
			// 第ニ会話入力チェック
			// **************************************
			if ( $("#row2_fld").val().trim() == "" ) {
				options.error( options['row2'].title + " を入力して下さい" );
				return;
			}

			// **************************************
			// Firebase ログインチェック
			// **************************************
			user = firebase.auth().currentUser;
			if ( user == null ) {
				options.error( "ログインされていません" );

				alert("第一会話へ移動します");

				// 第一会話へ変更
				options.pass1();

				return;
			}

			// データベース参照
			var myFirebaseRef = firebase.database().ref('class/' + $("#key_fld").val() );

			// **************************************
			// データ存在チェック
			// **************************************
			myFirebaseRef.once('value', function(snapshot) {

				if ( !snapshot.exists() ) {
					options.error( "データが存在しません" );

					alert("第一会話へ移動します");

					// 第一会話へ変更
					options.pass1();

					return;
				}

				if ( !confirm("更新してよろしいですか?") ) {
					return false;
				}

				// **************************************
				// 更新
				// **************************************
				// 更新用 JSON
				var update_data = {
					"code" : $("#key_fld").val(),
					"name" : $("#row2_fld").val(),
					"furi" : $("#row3_fld").val(),
					"kyuyo" : $("#row4_fld").val(),
					"sex" : $("#row5_fld").val(),
					"kanri" : $("#row6_fld").prop("checked")
				}
				// 更新
				myFirebaseRef.set(update_data).then(
					function(){

						options.info( "更新に成功しました" );

						// 第一会話へ変更
						options.pass1();

						// 全てクリア
						options.clear();

						// フォーカス
						$("#key_fld").focus();

					},
					function(error){
						$(".result").each(function(){
							$(this).next().text( error[ options[ $(this).prop("id") ].title ] );
						});
						options.error( "Firebase エラーです" );

						console.dir(error);
					}
				);

			});

		}

	} );

	// **************************************
	// mmenu
	// **************************************
	$("#mmenu_left").mmenu({
		navbar: {
			title: "メニュー"
		},
		offCanvas: {
			position  : "left",
			zposition : "next"
		}
	});


});

</script>
</head>
<body>

<div id="wrapper">
<script>
// スマホでロード時の処理のチラつき防止用
$("#wrapper").css( "visibility", "hidden" );
</script>

	<div id="head">
		<?php require_once('../std/view_hamburger.php') ?>
		<div id="title"><?= $GLOBALS['title'] ?></div>
	</div>

	<div id="body">
		<form id="frm" class="form-inline">

			<fieldset id="form_head">
				<table class="table table-condensed">
			
					<tr>
						<td class="fields" id="key"></td>
						<td>
							<div class="input-group">
								<input type="text" id="key_fld" name="key_fld">
								<button id="button_head" type="submit" class="btn btn-primary btn-sm m-l" onclick="options.curbtn=this.id">確認</button>
							</div>
						</td>
					</tr>
			
				</table>

			</fieldset>

			<fieldset id="form_body">
				<table class="table table-condensed">
			
					<tr>
						<td class="fields" id="row2"></td>
						<td>
							<input type="text" id="row2_fld" name="row2_fld">
						</td>
					</tr>
					<tr>
						<td class="fields" id="row3"></td>
						<td>
							<input type="text" id="row3_fld" name="row3_fld">
						</td>
					</tr>
					<tr>
						<td class="fields" id="row4"></td>
						<td>
							<input type="text" id="row4_fld" name="row4_fld">
						</td>
					</tr>

					<tr>
						<td class="fields" id="row5"></td>
						<td>
							<select name="row5_fld" id="row5_fld">
								<option value="0">男性</option>
								<option value="1">女性</option>
							</select>
						</td>
					</tr>

					<tr>
						<td class="fields" id="row6"></td>
						<td>
							<div class="input-group">
								<label for="row6_fld">有り無し</label>
								<input
									type="checkbox"
									id="row6_fld"
									name="row6_fld">
							</div>
						</td>
					</tr>

					<tr>
						<td></td>
						<td>
							<button id="button_body" type="submit" class="btn btn-primary btn-sm" onclick="options.curbtn=this.id">更新</button>
							<button
								type="button"
								class="btn btn-primary btn-warning btn-sm m-l-lg"
								value="キャンセル"
								 onclick='location="index.php"'>キャンセル</button>
						</td>
					</tr>


					<tr>
						<td class="fields error" id="row_last"></td>
						<td></td>
					</tr>
			
				</table>

			</fieldset>

			<fieldset>
				<legend>Firebase エラー</legend>
				<table class="table table-condensed">

					<tr><td class="fields result error" id="erow1"></td><td></td></tr>
					<tr><td class="fields result error" id="erow2"></td><td></td></tr>

				</table>

			</fieldset>

		</form>
	</div>

	<div id="comment">
	<?= $GLOBALS['comment'] ?>
	</div>

</div>


<?php require_once('unit_menu.php') ?>


</body>
</html>


minimum-scale=1.0 maximum-scale=1.0 user-scalable=no は、スマホで mmenu を表示する場合に必要です。

25行目の width: 90px; で、フィールドのタイトル幅が決定します。

options.curbtn は、submit ボタンが submit 前に click イベントで自身の id をセットし、どのボタンで submit されたか判定する為にあります。(314行 と 371行)

スマホでのロード時のちらつきを、$("#wrapper").css( "visibility", "hidden" ); で、画面表示を消していますが、JavaScript が無効の場合に画面がなくならないように、JS で非表示にしています。元々、addClass("form-control"); を後から jQuery  で設定する為に発生するちらつきですが、画面定義に一様にクラス設定してしまうと汎用性に欠けると思ったのでそうしました。

関連する記事

jQuery + Bootstrap(css) + mmenu : Firebase ログインテンプレート

jQuery + Bootstrap(css) + mmenu : Firebase 新規登録テンプレート




posted by lightbox at 2016-10-03 00:33 | Google | このブログの読者になる | 更新情報をチェックする

2016年10月02日


jQuery + Bootstrap(css) + mmenu : Firebase Database 新規登録テンプレート

2019/10/02 : テンプレートを変更しました

1) toastr.js を追加し、それに伴ってメッセージ表示をメソッド化して options に追加しました。

2) iPhone5 のサイズに合わせて、入力フィールドのタイトル幅を 90px に変更しました。
2019/10/01 : テンプレートを変更しました

1) HTML のチェックを使用できるように、form の submit イベントで処理した上で、submit しないようにしています。

2) options に、画面コントロール用の共通関数を追加しました

3) スマホ画面でちらつかないように、初期画面を非表示にして画面作成完了後に表示するようにしました

4) JavaScript のモバイルチェックを追加し、スマホで画面が隠れるフォーカス処理はしないようにしました。

5) ソースコードのインデントを減らし、可読性を上げる為に、エラーチェック等ではすぐ脱出するようにして、else をなくすようにしました。
デモページ ※ 0001 のデータが存在しています ▼ 以下のテンプレートのデモページでログインして、更新以外をテストできます jQuery + Bootstrap(css) + mmenu : Firebase ログインテンプレート このログインユーザは Database のルールで更新できないようにしています。この設定は、コンソールから直接 check ツリーのデータを変更する事によって、更新可能へと変更できます。
{
  "rules": {
      ".read": "root.child('check').hasChild(auth.uid)",
      ".write": "root.child('check').child(auth.uid).child('isAdmin').val() == true"
    }
}



テンプレートの構造と機能の概要を印刷する PDF

ソースコード

<!DOCTYPE html>
<html lang="ja">
<head>
<meta content="width=device-width initial-scale=1.0 minimum-scale=1.0 maximum-scale=1.0 user-scalable=no" name="viewport">
<meta charset="utf-8">
<title>2会話・テンプレート(新規)</title>

<script src="//ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
<link id="link" rel="stylesheet" href="//ajax.googleapis.com/ajax/libs/jqueryui/1.10.1/themes/base/jquery-ui.css">
<script src="//ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-alpha/css/bootstrap.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jQuery.mmenu/5.5.3/core/js/jquery.mmenu.min.all.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jQuery.mmenu/5.5.3/core/css/jquery.mmenu.all.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/toastr.js/2.1.3/toastr.min.css">
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/toastr.js/2.1.3/toastr.min.js"></script>

<link rel="stylesheet" href="../std/mmenu.css">
<link rel="stylesheet" href="../std/basic.css">

<script src="https://www.gstatic.com/firebasejs/3.4.0/firebase.js"></script>
<script>
  // Initialize Firebase
  var config = {
    apiKey: "AIzaSyD9vub84g_ckSvglTzMdLjXe1TV6WC8LCo",
    authDomain: "lightbox-1c915.firebaseapp.com",
    databaseURL: "https://lightbox-1c915.firebaseio.com",
    storageBucket: "lightbox-1c915.appspot.com",
    messagingSenderId: "694762121907"
  };
  firebase.initializeApp(config);
</script>

<style>
.fields {
	width: 90px;
	font-size: 12px;
	vertical-align: middle!important;
}

legend {
	font-size: 18px;
	padding-left: 6px;
}
</style>

<script>
jQuery.isMobile = (/android|webos|iphone|ipad|ipod|blackberry|iemobile|opera mini/i.test(navigator.userAgent.toLowerCase()));
toastr.options={"closeButton":false,"debug":false,"newestOnTop":false,"progressBar":false,"positionClass":"toast-bottom-center","preventDuplicates":false,"onclick":null,"showDuration":"300","hideDuration":"1000","timeOut":"3000","extendedTimeOut":"1000","showEasing":"swing","hideEasing":"linear","showMethod":"fadeIn","hideMethod":"fadeOut"}
if ( !$.isMobile ) {
	toastr.options.positionClass = "toast-top-center";
}
var options = {
	key : { title :"キー項目", css : { width : "80px" }, attr : { pattern : "[0-9]+", type: "tel" } },
	row2 : { title : "明細A"  },
	row3 : { title : "明細B"  },
	row4 : { title : "明細C", attr : { pattern : "[0-9]+", type: "tel" }  },
	row5 : { title : "選択", css : { height : "40px" } },
	row6 : { title : "チェック"  },
	row_last : { title :"メッセージ" },
	erow1 : { title : "code"  },
	erow2 : { title : "message"  },

	curbtn: "",
	pass1 : function(){
		// 第一会話へ変更
		$("#form_head").prop("disabled", false );
		$("#form_body").prop("disabled", true );
	},
	pass2 : function(){
		// 第二会話へ変更
		$("#form_head").prop("disabled", true );
		$("#form_body").prop("disabled", false );
	},
	clear : function(){
		// 全てクリア
		$(".fields").next().find("input[type='text'],input[type='tel']").val("");
		$(".fields").next().find("input[type='checkbox']").prop("checked", false);
		$(".fields").next().find("select").prop("selectedIndex", 0);
	},
	error : function(message){
		$("#row_last").next().text( message );
		toastr.error(message);
	},
	info : function(message){
		$("#row_last").next().text( message );
		toastr.success(message);
	}
};

$(function(){

	// 1) options による行とフィールドの設定
	// 2) Bootstrap 用 form-control クラスの追加
	$(".fields").each(function(){
		if ( options[ $(this).prop("id") ] ) {
			$(this).text( options[ $(this).prop("id") ].title );
			// 個別 css
			if ( options[ $(this).prop("id") ].css ) {
				$(this).next().find("input,select").css( options[ $(this).prop("id") ].css );
			}
			// 入力チェック用属性
			if ( options[ $(this).prop("id") ].attr ) {
				$(this).next().find("input,select").attr( options[ $(this).prop("id") ].attr );
			}
		}
		$(this).next().find("input,select").addClass("form-control");
	});
	// スマホでロード時の処理のチラつき防止用
	$("#wrapper").css("visibility","visible"); 

	// 第一会話
	options.pass1();

	// 初期フォーカス
	setTimeout( function(){$('#key_fld').focus();}, 100 );

	// 確認処理
	$("#frm").submit( function(event){
		// 本来の送信処理はキャンセル
		event.preventDefault();

		// エラーメッセージエリアをクリア
		$(".error").next().text( "" );

		// 確認ボタン
		if ( options.curbtn == "button_head" ) {

			// **************************************
			// 第一会話入力チェック
			// **************************************
			if ( $("#key_fld").val().trim() == "" ) {
				options.error( options['key'].title + " を入力して下さい" );
				return;
			}

			// **************************************
			// Firebase ログインチェック
			// **************************************
			user = firebase.auth().currentUser;
			if ( user == null ) {
				options.error( "ログインされていません" );
				return;
			}

			// データベース参照
			var myFirebaseRef = firebase.database().ref('class/' + $("#key_fld").val() );

			// **************************************
			// データ存在チェック
			// **************************************
			myFirebaseRef.once('value', 
				function(snapshot) {

					if ( snapshot.exists() ) {
						options.error( "データが既に存在します" );
						return;
					}

					// 第二会話へ変更
					options.pass2();

					// フォーカス
					if ( !$.isMobile ) {
						$("#row2_fld").focus();
					}

				},
				function(error){
					$(".result").each(function(){
						$(this).next().text( error[ options[ $(this).prop("id") ].title ] );
					});
					options.error( "Firebase エラーです" );

					console.dir(error);
				}
			);

		}

		// 更新ボタン
		if ( options.curbtn == "button_body" ) {

			// **************************************
			// 第ニ会話入力チェック
			// **************************************
			if ( $("#row2_fld").val().trim() == "" ) {
				options.error( options['row2'].title + " を入力して下さい" );
				return;
			}

			// **************************************
			// Firebase ログインチェック
			// **************************************
			user = firebase.auth().currentUser;
			if ( user == null ) {
				options.error( "ログインされていません" );

				alert("第一会話へ移動します");

				// 第一会話へ変更
				options.pass1();

				return;
			}

			// データベース参照
			var myFirebaseRef = firebase.database().ref('class/' + $("#key_fld").val() );

			// **************************************
			// データ存在チェック
			// **************************************
			myFirebaseRef.once('value', function(snapshot) {

				if ( snapshot.exists() ) {
					options.error( "データが既に存在します" );

					alert("第一会話へ移動します");

					// 第一会話へ変更
					options.pass1();

					return;
				}

				if ( !confirm("更新してよろしいですか?") ) {
					return false;
				}

				// **************************************
				// 更新
				// **************************************
				// 更新用 JSON
				var update_data = {
					"code" : $("#key_fld").val(),
					"name" : $("#row2_fld").val(),
					"furi" : $("#row3_fld").val()
				}
				myFirebaseRef.set(update_data).then(
					function(){

						options.info( "更新に成功しました" );

						// 第一会話へ変更
						options.pass1();

						// 全てクリア
						options.clear();

						// フォーカス
						$("#key_fld").focus();

					},
					function(error){
						$(".result").each(function(){
							$(this).next().text( error[ options[ $(this).prop("id") ].title ] );
						});
						options.error( "Firebase エラーです" );

						console.dir(error);
					}
				);

			});

		}

	} );

	// **************************************
	// mmenu
	// **************************************
	$("#mmenu_left").mmenu({
		navbar: {
			title: "メニュー"
		},
		offCanvas: {
			position  : "left",
			zposition : "next"
		}
	});


});

</script>
</head>
<body>

<div id="wrapper">
<script>
// スマホでロード時の処理のチラつき防止用
$("#wrapper").css( "visibility", "hidden" );
</script>

	<div id="head">
		<a id="hamburger" href="#mmenu_left">
	<span class="top-bar"></span>
	<span class="middle-bar"></span>
	<span class="bottom-bar"></span>
</a>
		<div id="title">2会話・テンプレート(新規)</div>
	</div>

	<div id="body">
		<form id="frm" class="form-inline">

			<fieldset id="form_head">
				<table class="table table-condensed">
			
					<tr>
						<td class="fields" id="key"></td>
						<td>
							<div class="input-group">
								<input type="text" id="key_fld" name="key_fld">
								<button id="button_head" type="submit" class="btn btn-primary btn-sm m-l" onclick="options.curbtn=this.id">確認</button>
							</div>
						</td>
					</tr>
			
				</table>

			</fieldset>

			<fieldset id="form_body">
				<table class="table table-condensed">
			
					<tr>
						<td class="fields" id="row2"></td>
						<td>
							<input type="text" id="row2_fld" name="row2_fld">
						</td>
					</tr>
					<tr>
						<td class="fields" id="row3"></td>
						<td>
							<input type="text" id="row3_fld" name="row3_fld">
						</td>
					</tr>
					<tr>
						<td class="fields" id="row4"></td>
						<td>
							<input type="text" id="row4_fld" name="row4_fld">
						</td>
					</tr>

					<tr>
						<td class="fields" id="row5"></td>
						<td>
							<select name="row5_fld" id="row5_fld">
								<option value="27">大阪</option>
								<option value="26">京都</option>
								<option value="29">奈良</option>
							</select>
						</td>
					</tr>

					<tr>
						<td class="fields" id="row6"></td>
						<td>
							<div class="input-group">
								<label for="row6_fld">有り無し</label>
								<input
									type="checkbox"
									id="row6_fld"
									name="row6_fld">
							</div>
						</td>
					</tr>

					<tr>
						<td></td>
						<td>
							<button id="button_body" type="submit" class="btn btn-primary btn-sm" onclick="options.curbtn=this.id">更新</button>
							<button
								type="button"
								class="btn btn-primary btn-warning btn-sm m-l-lg"
								value="キャンセル"
								 onclick='location="index.php"'>キャンセル</button>
						</td>
					</tr>


					<tr>
						<td class="fields error" id="row_last"></td>
						<td></td>
					</tr>
			
				</table>

			</fieldset>

			<fieldset>
				<legend>Firebase エラー</legend>
				<table class="table table-condensed">

					<tr><td class="fields result error" id="erow1"></td><td></td></tr>
					<tr><td class="fields result error" id="erow2"></td><td></td></tr>

				</table>

			</fieldset>

		</form>
	</div>

	<div id="comment">
	ようこそ jQuery + Bootstrap(css) + mmenu + Firebase	</div>

</div>


<div id="mmenu_left">
<ul>
	<li class="mm_user_title">ページ選択</li>
	<li><a class="mm_link_left" href="#" onclick="location='index.php';void(0)">リセット</a></li>
	<li><a class="mm_link_left" href="https://lightbox.sakura.ne.jp/demo/firebase/static/pass1/index.php">ログイン</a></li>
	<li><a class="mm_link_left" href="#" onclick="firebase.auth().signOut()">ログアウト</a></li>
	<li><a class="mm_link_left" 
			href="http://getbootstrap.com/css/"
			onclick="location='index.php';void(0)"
			target="_blank"
		>Bootstrap(css)</a></li>
	<li><a class="mm_link_left"
			href="http://api.jquery.com/"
			onclick="location='index.php';void(0)"
			target="_blank"
		>jQuery ドキュメント</a></li>
</ul>
</div>


</body>
</html>


関連する記事

jQuery + Bootstrap(css) + mmenu : Firebase ログインテンプレート



posted by lightbox at 2016-10-02 22:31 | Google | このブログの読者になる | 更新情報をチェックする

2016年10月01日


jQuery + Bootstrap(css) + mmenu : Firebase ログインテンプレート

2016/10/01 : IE 用に 縦スクロールバー用の設定を basic.css に追加しました
デモページ Bootstrap の css 部分のみ使用しています。なので、スマホでそのまま大差無く使用可能です。他ページへの移動や簡単な処理オプションの為、mmenu を使用して、スマホでも動作します。
ログイン情報の保持について Firebase の ログイン情報は localStorage に保存される為、ブラウザを閉じてもログインは保持されます。 テンプレートの mmenu と ハンバーガーアイコン部分 直接の動作とは関係無いので省いても問題はありません ( ソースコードの 13 〜 14 行, 118 〜 129 行, 142 〜 146 行, 220 〜 235 行 ) Firebase 実装部分 自分のコントロールパネルから『ウェブアプリに Firebase を追加』で取得可能な firebase.js と firebase.initializeApp( config ) 部分を該当部分に貼り付け直すだけです。 ( ソースコードの 17 〜 28 行 ) テンプレートの構造と機能の概要を印刷する PDF テンプレートの構造と機能の概要を印刷する PDF(ソースコードレベル) ソースコード

<!DOCTYPE html>
<html lang="ja">
<head>
<meta content="width=device-width initial-scale=1.0 minimum-scale=1.0 maximum-scale=1.0 user-scalable=no" name="viewport">
<meta charset="utf-8">
<title>1会話・テンプレート(ログイン)</title>

<script src="//ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
<link id="link" rel="stylesheet" href="//ajax.googleapis.com/ajax/libs/jqueryui/1.10.1/themes/base/jquery-ui.css">
<script src="//ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-alpha/css/bootstrap.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jQuery.mmenu/5.5.3/core/js/jquery.mmenu.min.all.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jQuery.mmenu/5.5.3/core/css/jquery.mmenu.all.css">
<link rel="stylesheet" href="std/mmenu.css">
<link rel="stylesheet" href="std/basic.css">

<script src="https://www.gstatic.com/firebasejs/3.4.0/firebase.js"></script>
<script>
  // Initialize Firebase
  var config = {
    apiKey: "AIzaSyD9vub84g_ckSvglTzMdLjXe1TV6WC8LCo",
    authDomain: "lightbox-1c915.firebaseapp.com",
    databaseURL: "https://lightbox-1c915.firebaseio.com",
    storageBucket: "lightbox-1c915.appspot.com",
    messagingSenderId: "694762121907"
  };
  firebase.initializeApp(config);
</script>

<style>
.fields {
	width: 120px;
	font-size: 12px;
	vertical-align: middle!important;
}

legend {
	font-size: 18px;
	padding-left: 6px;
}
</style>

<script>
var options = {
	row1 : { title : "ユーザ", css: { "background-color": "azure", "font-weight": "bold" }  },
	row2 : { title : "パスワード"  },
	row3 : { title : ""  },
	row_last : { title :"メッセージ" },
	rrow1 : { title : "uid"  },
	rrow2 : { title : "email"  },
	rrow3 : { title : "emailVerified"  },
	rrow4 : { title : "displayName"  },
	rrow5 : { title : "isAnonymous"  },
	erow1 : { title : "code"  },
	erow2 : { title : "message"  }
};
var login_user_info = null;

$(function(){

	// 1) options による行とフィールドの設定
	// 2) Bootstrap 用 form-control クラスの追加
	$(".fields").each(function(){
		$(this).text( options[ $(this).prop("id") ].title );
		if ( options[ $(this).prop("id") ].css ) {
			$(this).next().find("input,select").css( options[ $(this).prop("id") ].css );
		}
		$(this).next().find("input,select").addClass("form-control");
	});


	// 初期フォーカス
	setTimeout( function(){$('#row1_fld').focus();}, 100 );

	// ログイン処理
	$("#login").on("click", function(){

		// 結果の表示エリアを全てクリア
		$(".result").next().text( "" );

		// 入力チェック
		if ( $("#row1_fld").val().trim() == "" ) {
			$("#row_last").next().text("ユーザを入力して下さい");
			return;
		}

		// **************************************
		// Firebase ログイン
		// **************************************
		var auth = firebase.auth();
		auth.signInWithEmailAndPassword($("#row1_fld").val(), $("#row2_fld").val())
		.then(
			// ログイン成功
			function( user ) {
				login_user_info = user;

				$(".result").each(function(){
					$(this).next().text( user[ options[ $(this).prop("id") ].title ] );
				});

				console.dir( user );

			},
			// ログイン失敗
			function( error ) {

				error["メッセージ"] = "ログインに失敗しました";

				$(".error").each(function(){
					$(this).next().text( error[ options[ $(this).prop("id") ].title ] );
				});

				console.dir( error );
			}
		);
	} );

	// **************************************
	// mmenu
	// **************************************
	$("#mmenu_left").mmenu({
		navbar: {
			title: "メニュー"
		},
		offCanvas: {
			position  : "left",
			zposition : "next"
		}
	});


});

</script>
</head>
<body>

<div id="wrapper">

	<div id="head">
		
<a id="hamburger" href="#mmenu_left">
	<span class="top-bar"></span>
	<span class="middle-bar"></span>
	<span class="bottom-bar"></span>
</a>
		<div id="title">1会話・テンプレート(ログイン)</div>
	</div>

	<div id="body">
		<form class="form-inline">

			<fieldset>
				<legend>ログイン</legend>
				<table class="table table-condensed">
			
					<tr>
						<td class="fields" id="row1"></td>
						<td>
							<input type="text" id="row1_fld" name="row1_fld" value="abc@test.jp">
						</td>
					</tr>
					<tr>
						<td class="fields" id="row2"></td>
						<td>
							<input type="text" id="row2_fld" name="row2_fld" value="20160828">
						</td>
					</tr>

					<tr>
						<td class="fields" id="row3"></td>
						<td>
							<input id="login" type="button" class="btn btn-primary btn-sm" value="送信">
						</td>
					</tr>

					<tr>
						<td class="fields error" id="row_last"></td>
						<td></td>
					</tr>

				</table>

			</fieldset>

			<fieldset>
				<legend>結果</legend>
				<table class="table table-condensed">

					<tr><td class="fields result" id="rrow1"></td><td></td></tr>
					<tr><td class="fields result" id="rrow2"></td><td></td></tr>
					<tr><td class="fields result" id="rrow3"></td><td></td></tr>
					<tr><td class="fields result" id="rrow4"></td><td></td></tr>
					<tr><td class="fields result" id="rrow5"></td><td></td></tr>

				</table>

			</fieldset>

			<fieldset>
				<legend>Firebase エラー</legend>
				<table class="table table-condensed">

					<tr><td class="fields result error" id="erow1"></td><td></td></tr>
					<tr><td class="fields result error" id="erow2"></td><td></td></tr>

				</table>

			</fieldset>

		</form>
	</div>

	<div id="comment">
	ようこそ jQuery + Bootstrap(css) + mmenu + Firebase	</div>

</div>


<div id="mmenu_left">
<ul>
	<li class="mm_user_title">ページ選択</li>
	<li><a class="mm_link_left" href="#" onclick="location='index.php';void(0)">リセット</a></li>
	<li><a class="mm_link_left" 
			href="http://getbootstrap.com/css/"
			onclick="location='entry.php';void(0)"
			target="_blank"
		>Bootstrap(css)</a></li>
	<li><a class="mm_link_left"
			href="http://api.jquery.com/"
			onclick="location='entry.php';void(0)"
			target="_blank"
		>jQuery ドキュメント</a></li>
</ul>
</div>


</body>
</html>



mmenu と hamburger アイコン設定
( mmenu.css )
#hamburger {
	vertical-align: bottom;
	border: 1px solid #999;
	display: inline-block;
	width: 50px;
	padding: 5px 10px;
	margin: 0 20px 0 8px;
}
#hamburger span {
	background: #999;
	display: block;
	height: 3px;
	margin: 5px 0;
}

html.mm-opened #hamburger span.top-bar {
	transform: rotate( 45deg );
	top: 8px;
}
html.mm-opened #hamburger span.middle-bar {
	opacity: 0;
	left: -40px;
}
html.mm-opened #hamburger span.bottom-bar {
	transform: rotate( -45deg );
	top: -8px;
}

#hamburger {
	overflow: hidden;
}
#hamburger span {
	position: relative;
	transform: rotate( 0 );
	top: 0;
	left: 0;
	opacity: 1;

	transition: none 0.5s ease;
	transition-property: transform, top, left, opacity;
}


.mm-menu {
	background-color: #DAEEF2;
	color: #444444;
}
.mm-title {
	color: #222222!important;
	font-size: 16px;
	font-weight: bold;
}
.mm_user_title {
	padding: 20px!important;
}


テンプレート用 CSS
( basic.css )
@charset "UTF-8";

* {
	font-family: Arial, Helvetica, Verdana, "ヒラギノ角ゴPro W3", "Hiragino Kaku Gothic Pro", Osaka, "メイリオ", Meiryo, "MS Pゴシック", sans-serif!important;
}

#head {
	background-color: #404040;
}
#title {
	color: white;
	display: inline-block;
	line-height:40px;
}

#body {
	margin: 20px 0 0 0;
}

td {
	word-break: break-all;
}

.error {
	background-color: #FFE8EC;
}

#comment {
	padding: 20px;
	border: solid 1px #ccc;
	margin: 40px;
	border-radius: 10px;
}

@-ms-viewport {
	width: auto;
}

関連する記事

jQuery + Bootstrap(css) + mmenu : Firebase Database 新規登録テンプレート



posted by lightbox at 2016-10-01 16:38 | Google | このブログの読者になる | 更新情報をチェックする
Seesaa の各ページの表示について
Seesaa の 記事がたまに全く表示されない場合があります。その場合は、設定> 詳細設定> ブログ設定 で 最新の情報に更新の『実行ボタン』で記事やアーカイブが最新にビルドされます。

Seesaa のページで、アーカイブとタグページは要注意です。タグページはコンテンツが全く無い状態になりますし、アーカイブページも歯抜けページはコンテンツが存在しないのにページが表示されてしまいます。

また、カテゴリページもそういう意味では完全ではありません。『カテゴリID-番号』というフォーマットで表示されるページですが、実際存在するより大きな番号でも表示されてしまいます。

※ インデックスページのみ、実際の記事数を超えたページを指定しても最後のページが表示されるようです

対処としては、このようなヘルプ的な情報を固定でページの最後に表示するようにするといいでしょう。具体的には、メインの記事コンテンツの下に『自由形式』を追加し、アーカイブとカテゴリページでのみ表示するように設定し、コンテンツを用意するといいと思います。


※ エキスパートモードで表示しています

アーカイブとカテゴリページはこのように簡単に設定できますが、タグページは HTML 設定を直接変更して、以下の『タグページでのみ表示される内容』の記述方法で設定する必要があります

<% if:page_name eq 'archive' -%>
アーカイブページでのみ表示される内容
<% /if %>

<% if:page_name eq 'category' -%>
カテゴリページでのみ表示される内容
<% /if %>

<% if:page_name eq 'tag' -%>
タグページでのみ表示される内容
<% /if %>
この記述は、以下の場所で使用します
container 終わり



フリーフォントで簡単ロゴ作成
フリーフォントでボタン素材作成
フリーフォントで吹き出し画像作成
フリーフォントではんこ画像作成
ほぼ自由に利用できるフリーフォント
フリーフォントの書体見本とサンプル
画像を大きく見る為のウインドウを開くボタンの作成

CSS ドロップシャドウの参考デモ
イラストAC
ぱくたそ
写真素材 足成
フリーフォント一覧
utf8 文字ツール
右サイド 終わり
base 終わり