コメントと更新履歴はゼロと無限の間のログ » Pryn.js & cssへどうぞ。
よく使う初期設定用のJavaScriptとCSSをまとめたもの。
主にユーザビリティの向上が目的。JavaScriptとCSSを読み込めば、あとは自動で設定される。
使いやすくするためにMITライセンスで公開した。
別ドメインへのリンクは別Windowで開く
ボタン系要素にマウスカーソルを当てた時にマウスカーソルが手になる
入力系要素にフォーカスを当てた時に背景色が変わる
テキストボックス・テキストエリアにヒント文を表示できる (classを”hint”にして、title属性にヒント文をセットする)
テキストボックス・テキストエリアをコピペ用のものにできる (classを”copy”にする)
ページ表示時にフォーカスを当てる要素を指定できる (classを”ready”にする)
formの二重送信を防止する
label要素にfor属性を書かなくても動作する
画像にtitle属性が無い場合、alt属性をtitle属性にコピーする
/**
* Pryn.js
* @see http://0-oo.net/sbox/javascript/pryn-js-css
* @version 0.2.2
* @copyright 2007-2008 dgbadmin@gmail.com
* @license http://0-oo.net/pryn/MIT_license.txt (The MIT license)
*
* 連携するCSSクラス
* (a, form).open 別Windowで開く
* (a, form).same-window 同じWindowで開く
* (input, textarea).focused 入力状態になった要素
* (input, textarea).ready デフォルトでfocusを当てる要素
* (input, textarea).hint ヒント付テキストボックス
* ・入力後のクラスは ex-hint になる
* ・ヒントはtitle属性にセットしておく
* (input, textarea).copy コピー用テキスト
* (input, textarea).clickable クリックできる要素
*/
/** IE高速化 @see http://d.hatena.ne.jp/amachang/20071010/1192012056 */
/*@cc_on _d = document; eval("var document = _d")@*/
/***** 組み込みオブジェクトの拡張 *****/
/**
* 文字列のtrim
* @return trim後の文字列
*/
String.prototype.trim = function() {
return this.replace(/(^\s+|\s+$)/g|>, "");
};
/**
* 1単語を表す正規表現を取得する
* @return 正規表現オブジェクト
*/
String.prototype.word2regexp = function() {
return new RegExp("(^|\\s)" + this + "(\\s|$)", "ig");
};
/**
* 子要素全てに関数の処理を実行する
* @param Object arr 子要素をループ処理できるオブジェクト
*/
Function.prototype.foreach = function(arr) {
for (var i = 0, len = arr.length; i < len; i++) {
this(arr[i]);
}
};
/***** グローバル関数/オブジェクト *****/
/**
* Firebugが無い場合はconsole.log()を空振りさせる
*/
if (!console) {
var console = {log: function(s){}, dummy: true};
}
/**
* html要素をidで取得する(既に$()があればそちらを使う)
* @param String id
* @retrun html要素
*/
var $ = $ || function(id) {
return document.getElementById(id);
};
/**
* html要素をタグ名で取得する
* @param String tagName
* @retrun NodeList
*/
function $T(tagName) {
return document.getElementsByTagName(tagName);
}
/**
* ページを遷移する
* @param String url
*/
function go(url) {
location.href = url;
}
/***** Pryn *****/
var Pryn = {
/** ページ表示時のユーザビリティ向上用の設定 */
Init: {
/** 別ドメインへの遷移を別Windowで開くかどうか */
keepThisSite: true,
/** input要素のtype属性をclass属性にコピーするかどうか */
copyInputType: false,
/** input要素のtype属性をclass属性にコピーする場合のプリフィクス */
inputTypePrefix: "input-",
/** formの二重送信防止を解除するまでの時間(秒) */
frozenTime: 3,
/** imageボタンの配列 */
inputImages: []
}
};
/**
* イベントを追加する。IEでもfunction内でthisで自分(elm)を参照できるようにしている
* @param HTMLElement elm
* @param String eventName
* @param Function fnc
*/
Pryn.addEvent = function(){
if (window.attachEvent) {
return function(elm, eventName, fnc){
elm.attachEvent("on" + eventName, function(){ fnc.call(elm); });
};
} else {
return function(elm, eventName, fnc){
if (elm == window && eventName == "load") {
document.addEventListener("DOMContentLoaded", fnc, false);
} else {
elm.addEventListener(eventName, fnc, false);
}
};
}
}();
/**
* リンクのURLからドメイン部分を取り出す
* @param HTMLElement link
* @return メイン(ドメインを含んでいない場合はnull)
*/
Pryn.getDomain = function(link) {
var href = link.href;
if (href.match(/^http(|s):/i|>)) {
return href.split("/")[2];
} else {
return null;
}
};
/***** Pryn.ClassAccessor *****/
/**
* html要素のclass属性へのアクセサクラス
* @param HTMLElement elm
*/
Pryn.ClassAccessor = function(elm) {
/**
* html要素にclassがあるか確かめる
* @param String cName
*/
this.hasClass = function(cName) {
var cn = elm.className;
return (cn && cn.match(cName.word2regexp()));
};
/**
* html要素にclassを追加する
* @param String cName
*/
this.addClass = function(cName) {
if (!this.hasClass(cName)) {
elm.className += " " + cName;
}
};
/**
* html要素からclassを削除する
* @param String cName
*/
this.removeClass = function(cName) {
elm.className = elm.className.replace(cName.word2regexp(), " ").trim();
};
/**
* html要素のclassを変更する
* @param String oldClass
* @param String newClass
*/
this.convertClass = function(oldClass, newClass) {
this.removeClass(oldClass);
this.addClass(newClass);
};
};
/***** Pryn.Init *****/
/**
* 別Windowで開くリンク・formの設定
* @param HTMLElement link a要素 or form要素(自動判断にはhref属性が必要)
*/
Pryn.Init.setTarget = function(link) {
var acs = new Pryn.ClassAccessor(link);
var ext = false;
if (Pryn.Init.keepThisSite && !acs.hasClass("same-window")) {
var next = Pryn.getDomain(link);
ext = (next && next != Pryn.getDomain(location)); //外部へのリンクかどうか
}
if (ext || acs.hasClass("open")) { //classがopenの場合も
link.target = "_blank";
}
};
/**
* formの子要素のstyle等の設定
* CSSにてclass "clickable" "focused" のstyleを定義すること
* @param HTMLElement fElm formの子要素
*/
Pryn.Init.setStyles = function(fElm) {
var acs = new Pryn.ClassAccessor(fElm);
if (Pryn.Init.copyInputType && fElm.tagName == "INPUT") { //有効にされている場合は
acs.addClass(Pryn.Init.inputTypePrefix + fElm.type); //inputのtypeをclassにコピー
}
if (acs.hasClass("ready")) { //デフォルトでfocusを当てる
fElm.focus();
}
//ボタン系
if (fElm.type.match(/^(submit|button|reset|image)$/i|>)) {
if (fElm.type == "image") {
Pryn.Init.setImageTitle(fElm);
Pryn.Init.inputImages.push(fElm);
}
acs.addClass("clickable");
return;
}
//ボタン系以外
Pryn.addEvent(fElm, "focus", function() { //フォーカスされた時
if (!fElm.readOnly) {
acs.addClass("focused");
}
if (acs.hasClass("hint")) { //ヒント付テキストボックス
this.value = "";
acs.convertClass("hint", "ex-hint");
} else if (acs.hasClass("copy")) { //コピー用テキスト
setTimeout(function() {fElm.select(); }, 100); //selectし損ねるのを防ぐ
}
});
Pryn.addEvent(fElm, "blur", function() { //フォーカスが外れた時
acs.removeClass("focused");
if (acs.hasClass("ex-hint") && !fElm.value) { //ヒント付テキストボックスで未入力
acs.convertClass("ex-hint", "hint");
fElm.value = fElm.title;
}
});
if (fElm.type == "file") { //ファイルアップロード(IEのみ適用される)
acs.addClass("clickable");
} else if (acs.hasClass("hint")) { //ヒント付テキストボックス
if (fElm.value && fElm.value != fElm.title) { //既に値がある場合
acs.convertClass("hint", "ex-hint");
} else {
fElm.value = fElm.title; //title属性をテキストボックスに表示
}
} else if (acs.hasClass("copy")) { //コピー用テキスト
fElm.readOnly = true;
acs.addClass("clickable");
}
};
/**
* formの二重送信防止設定
* @param HTMLElement frm
*/
Pryn.Init.setSmartSubmit = function(frm) {
Pryn.addEvent(frm, "submit", function() {
Pryn.Init.setSubmitStyles.foreach(this);
Pryn.Init.setSubmitStyles.foreach(Pryn.Init.inputImages); //imageボタンはformの子要素にならない
});
frm.href = frm.action; //別Windowで開くための前処理
Pryn.Init.setTarget(frm); //必要に応じて別Windowで開く
};
/**
* formのsubmit時の処理
* @param HTMLElement formの子要素
*/
Pryn.Init.setSubmitStyles = function(fElm) {
var acs = new Pryn.ClassAccessor(fElm);
if (acs.hasClass("hint")) { //送信前にヒントをクリア
fElm.value = "";
}
//操作不可にして、しばらくしたら戻す
switch (fElm.type) { //戻ってきた時にFirefoxでdisabledを解除できないtypeを峻別
case "text":
case "file": //fileはFirefoxではreadOnlyは効かないがIE用に
if (!fElm.readOnly) {
setTimeout(function() { fElm.readOnly = true; }, 1);
setTimeout(function() { fElm.readOnly = false; }, Pryn.Init.frozenTime * 1000);
}
break;
case "checkbox":
case "radio":
case "hidden":
break;
default:
if (!fElm.disabled) {
setTimeout(function() { fElm.disabled = true; }, 1);
setTimeout(function() { fElm.disabled = false; }, Pryn.Init.frozenTime * 1000);
}
}
};
/**
* label要素のクロスブラウザ対応
* @param HTMLElement label
*/
Pryn.Init.setSmartLabel = function(label) {
var input;
var forId = label.htmlFor;
if (forId) {
input = document.getElementById(forId);
} else { //for属性省略ならlabel内のinputを対象にする
input = label.getElementsByTagName("INPUT")[0];
}
if (input) {
label.onclick = function() { input.click(); };
}
};
/**
* img要素にtitle属性をセットする(IEの動きに合わせる)
* @param HTMLElement img
*/
Pryn.Init.setImageTitle = function(img) {
if (!img.title && img.alt) {
img.title = img.alt;
}
};
/**
* 初期処理
*/
Pryn.addEvent(window, "load", function() {
Pryn.Init.setTarget.foreach($T("a"));
Pryn.Init.setStyles.foreach($T("input"));
Pryn.Init.setStyles.foreach($T("textarea"));
Pryn.Init.setStyles.foreach($T("button"));
Pryn.Init.setSmartSubmit.foreach($T("form"));
Pryn.Init.setSmartLabel.foreach($T("label"));
Pryn.Init.setImageTitle.foreach($T("img"));
});
@charset "UTF-8";
/**
* Pryn.css
* @see http://0-oo.net/sbox/javascript/pryn-js-css
* @version 0.2.2
* @copyright 2007-2008 dgbadmin@gmail.com
* @license http://0-oo.net/pryn/MIT_license.txt (The MIT license)
*/
/***** YUIのimport *****/
/*
* Yahoo!によるホスティングを利用
* @see http://developer.yahoo.com/yui/articles/hosting/
*/
@import "http://yui.yahooapis.com/2.5.2/build/reset-fonts-grids/reset-fonts-grids.css";
@import "http://yui.yahooapis.com/2.5.2/build/base/base-min.css";
/* httpsのページではYUIを自サーバに置いて使う(httpのCSSをimportすると警告が出るため)
@import "/yui/reset-fonts-grids/reset-fonts-grids.css";
@import "/yui/base/base-min.css";
*/
/**
* YUI適用後の調整
*/
input, textarea{
margin-right:2px;
padding: 1px;
}
/**
* YUIをSticy Footer化
* @see http://0-oo.net/sbox/css-small-box/yahho-sticky-footer
*/
html, body{
height: 100%;
}
div#doc, div#doc2, div#doc3, div#doc4{
position: relative;
min-height: 100%;
_height: 100%; /* for IE6 */
}
div#ft{
position: absolute;
bottom: 0;
width: 100%;
}
/* フッターの高さはサイトに合わせて変えること */
div#bd{
padding-bottom: 4em; /* フッターの高さと同じか、それより大きくする */
}
div#ft{
height: 3em;
}
/***** 汎用的なstyle *****/
html{
overflow: -moz-scrollbars-vertical; /* Firefox:常にスクロールバーを表示 */
}
select, label, button, .clickable{
cursor: pointer; /* マウスカーソルを手にする(IEはselectに非対応) */
}
textarea{
overflow: auto; /* IE:スクロールバー不要なら非表示 */
}
input, textarea{
ime-mode: active; /* IE, Firefox3:IME有効 */
}
input.han, input.number, textarea.han{
ime-mode: inactive; /* IE, Firefox3:IME無効 */
}
input.number{ /* 数値 */
text-align: right;
}
.left{
float: left;
}
.right{
float: right;
}
.center{
text-align: center;
}
.clear{ /* floatのクリア */
clear: both;
}
hr.mobile{ /* 携帯専用区切りライン(PCでは見せない) */
display: none;
}
/***** サイトごとのstyle(サイトに合わせて 変更 or 上書き する) *****/
div#bd{
font-size: 116%; /** @see http://developer.yahoo.com/yui/fonts/#using */
line-height: 1.7; /* 単位を付けない */
}
div.error, span.error{ /* 入力エラーメッセージのフォント */
color: #f00;
font-weight: bold;
}
input.error, textarea.error, select.error{
background-color: #f99; /* 入力エラーの要素の背景色 */
}
input.focused, textarea.focused{
background-color: #feb; /* 入力要素のfocus時の背景色 */
}
input.hint, textarea.hint{ /* テキストボックス内の説明 */
color: #999;
}
input.copy, textarea.copy{
background-color: #ddd; /* コピー用テキストの背景色 */
}
optgroup{
color: #999;
}
option{
color: #000; /* optgroupから引き継ぐcolorを元に戻す */
}