* Licensed under the MIT license.
* Copyright (c) 2009 tagget.org
*
- * version 0.1.0
+ * version 0.1.1
*/
(function($) {
*/
var Suggester = {
- // 入力データを利用した補完を行うか
- byInputs: true,
-
keywords: {
html: (function() {
'<br />',
'<div>#{c}</div>\n',
'<span>#{c}</span>',
+ '<p>#{c}</p>\n',
'<h1>#{c}</h1>\n',
'<h2>#{c}</h2>\n',
'<dt>#{c}</dt>\n',
'<dt>#{c}</dd>\n',
+ '<table>\n#{c}\n</table>\n',
+ '<tr>#{c}</tr>',
+ '<th>#{c}</th>',
+ '<td>#{c}</td>',
+
'<strong>#{c}</strong>',
'<em>#{c}</em>',
'<form>\n#{c}\n</form>',
+ '<fieldset>#{c}</fieldset>',
'<input type="#{c}" />',
'<!--',
// 属性
var attributes = [
'href="#{c}"',
+ 'src="#{c}"',
+ 'cols="#{c}"',
+ 'rows="#{c}"',
'id="#{c}"',
'class="#{c}"',
'style="#{c}"',
+ 'colspan="#{c}"',
+ 'rowspan="#{c}"',
+ 'border="#{c}"',
+
'onload="#{c}"',
'onclick="#{c}"',
'onmouseover="#{c}"',
'margin-left: ',
'margin-top: ',
'margin-bottom: ',
+
'padding: ',
+ 'padding-right: ',
+ 'padding-left: ',
+ 'padding-top: ',
+ 'padding-bottom: ',
+
+ 'border: ',
+ 'border-right: ',
+ 'border-left: ',
+ 'border-top: ',
+ 'border-bottom: ',
+
+ 'background: ',
+ 'background-color: ',
+ 'background-repeat: ',
+
'float: ',
'clear: '
];
// 入力内容で補完
if (Wrapper.checkIntelli(t)) {
- var a = t.value.match(/[^<>\s '"#\=:;{}\(\)!?,*]+/g) || [];
+ // 変数名とかを抽出
+ // 記号じゃない連続文字列
+ var a = t.value.match(/[^<>\s '"#\=:;{}\(\)!?,*]{2,}/g) || [];
// 重複削除
var temp = [];
toolbar.append(
$('<p class="tagget_replace"></p>')
.append('<input type="text" value="Before" title="置換前" />')
- .append('<img src="img/v_arrow010102.gif" />')
+ .append('<img src="tagget/img/v_arrow010102.gif" />')
.append('<input type="text" value="After" title="置換後" />')
.append('<input type="button" value="Replace All" title="全て置換" />')
);
},
+ getToolbar: function(t) {
+
+ return $(t).parents('.tagget_wrapper').children('.tagget_toolbar');
+
+ },
// wrap要素にeventを設定する。
// 既にHTMLがあった場合は、こちらだけを行う。
relate: function(t) {
- var toolbar = $(t).parents('.tagget_wrapper').children('.tagget_toolbar');
-
+ var toolbar = this.getToolbar(t);
+
// 選択範囲変換
// onchangeイベント設定
toolbar.find('.tagget_encode select').change(function() {
var before = inputs.eq(0).val();
var after = inputs.eq(1).val();
+ // フラグはデフォルトでg(Replace All)
var flag = 'g';
+ // TODO: 一応動くけどもっとみやすいコードに
+
+ // /before/gim形式で入力されたらフラグを抽出
+ // それ以外は全体を正規表現として扱う
if (before.match(/^\/.+\/([^\/]+)$/)) {
+ // フラグ上書き
flag = RegExp.$1;
+ // 行頭の/、/以降の文字(フラグ、スラッシュ連続など形式外の入力)を除去
before = before.replace(/^\/|\/[^\/]+?$/g, '');
}
return (new RegExp(currentType)).test(type);
},
+
+ checkCookie: function(t) {
+ var cookie = $(t).parents('.tagget_wrapper')
+ .find('.tagget_cookie input').attr('checked');
+ return cookie;
+ },
+
+ // 入力データを利用した補完を行うか
checkIntelli: function(t) {
var intelli = $(t).parents('.tagget_wrapper')
.find('.tagget_intelli input').attr('checked');
},
// suggestionを表示
+ // TODO: 候補数制限 or 高さ設定してスクロール
showPopup: function(t) {
var popup = this.getPopup(t);
// if (!r) r = /[^<>\s '"#\.=;]+?$|<[^<>\n=]*?$/;
if (!r) {
+ // 補完対象
+ // 変な記号で始まらない文字列
+ // <で始まる文字列(タグ)
r = /[^<>\s '"#\.=;]+?$|<[^<>\s '"#\.=;]*?$/;
}
// 改行がたくさんある場合スクロールバーを下にずらす
if (/\n/g.test(s) && s.match(/\n/g).length > 2) {
- top += parseInt(getComputedStyle(t, '').getPropertyValue('line-height'), 10);
+ top += parseInt(getComputedStyle(t, '').getPropertyValue('font-size'), 10) + 3;
}
// スクロールバーを戻す
// TODO:できれば一文でやりたい
var sTags = Cursor.getText(t, /^[\s\S]*$/)[0]
.replace(/<[!\?\/][\s\S]*?>/g, '') // <!?/を除去
- .replace(/<[^\>]*?\/>/g, '') // 空要素/>を除去
- .match(/<[\s\S]*?>/g); // タグ抽出
+ .replace(/<[^>]*?\/>/g, '') // 空要素/>を除去
+ .match(/<[^>]+?>/g); // タグ抽出
var eTags = Cursor.getText(t, /<\/[^?]+?>/g);
if (sTags) {
for (; i >= 0 && eTags.length > 0; i--) {
// <までとタグ名以降を除去
+ // >と\s始まり(属性と閉じ括弧)を除去
+ // TODO:もうちょっと改善すれば改行された要素にも対応できる?
var sTag = sTags[i].replace(/^.*<|[\s>].*/g, '');
var j = 0;
- for (; j < eTags.length > 0; j++) {
+ for (; j < eTags.length; j++) {
var eTag = eTags[j].replace(/^.*<\/|[\s>].*/g, '');
+
+ // マッチしたらその閉じタグを配列から消して除外
if (sTag == eTag) {
break;
}
}
- console.log(eTags[j]);
- eTags.splice(j, 1);
-
- console.log(sTag + ':' + eTag);
- // 閉じタグとマッチしなければその開始タグを閉じる
- if (sTag != eTag) {
+ if (j < eTags.length) {
+ eTags.splice(j, 1);
+
+ // マッチしなかったらその開始タグを閉じる
+ } else {
break;
}
-
+
}
+ // 現在の開始タグを閉じる
// 全てマッチしたら何もしない
if (i >= 0) {
Cursor.insert(t, '</' + sTags[i].replace(/^.*<|[\s>].*/g, '') + '>');
top: top
};
+ },
+
+ fillZero: function(s) {
+ return ('0' + s).slice(-2);
+ },
+
+ now: function() {
+
+ var date = new Date();
+ var y = date.getFullYear();
+ var m = this.fillZero(date.getMonth() + 1);
+ var d = this.fillZero(date.getDate());
+ var h = this.fillZero(date.getHours());
+ var min = this.fillZero(date.getMinutes());
+ var sec = this.fillZero(date.getSeconds());
+
+ return y + '/' + m + '/' + d + '/' + ' ' + h + ':' + min + ':' + sec;
+
}
+
};
/* ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- */
};
-
/* ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- */
- // tagget初期化
- var init = function(t, i) {
+ /**
+ * textareaのEventに設定する関数群
+ */
+ Event = {
- // 被らないコードを振る
- while ($('textarea').is('.tagget_' + i)) {
- i = '0' + i;
- }
- $(t).addClass('tagget_' + i);
-
- Wrapper.wrap(t);
- Wrapper.absolutes(t);
-
-// setTimeout(function() {
-//
-// });
-
- // イベント設定
-
- // keyup(発生タイミングが一番少ない)で候補表示
- $(t).keyup(function(e) {
+ // keyupは発生タイミングが一番少ない
+ // 候補表示に使用
+ keyup: function(e) {
- if(!(37 <= e.which && e.which <= 40)) {
+ var t = this;
+
+ // 十字キー、Enterの時は補完を表示しない
+ if(!(37 <= e.which && e.which <= 40) && !(e.which == 13)) {
Wrapper.showPopup(t);
- } else if(e.which == 37 || e.which == 39) {
+
+ }
+ // 左右キーで補完を非表示化
+ else if(e.which == 37 || e.which == 39) {
Wrapper.getPopup(t).hide();
}
Wrapper.setLine(t);
- })
-
- // 入力キーに応じた処理
- .keydown(function(e) {
+ },
+
+ // 入力内容に応じた処理はdownで
+ // press,upだとおかしくなるものもこっちで
+ keydown: function(e) {
+
+ var t = this;
// タブキャンセル
// keydown以外だとうまくいかない
}
// Shift+Enterで改行 or <br />入力
- // 補完却下も可能
if (e.shiftKey && e.which == 13) {
var n = '\n';
- if (!Wrapper.isPopup(t) && Wrapper.checkType(t, 'html')) {
+ if (Wrapper.checkType(t, 'html')) {
n = '<br />';
}
Cursor.insert(t, n);
+ // 補完処理終了。
+ // 以下同様で後続処理は行わない
return false;
}
// Ctrl+Enterで閉じタグ補完
if (e.ctrlKey && e.which == 13) {
- Cursor.closeTag(t);
+ if (Wrapper.checkType(t, 'html')) {
+
+ Cursor.closeTag(t);
+ return false;
+
+ }
- return false;
}
// 十字キーで候補選択
var indent = Cursor.getText(t, /^[\t ]*/mg);
Cursor.insert(t, '\n' + (indent ? indent[indent.length - 1] : ''));
+ // TODO:もっとちゃんとスクロールの高さ直す
var $t = $(t);
if (window.getComputedStyle) {
- $t.scrollTop($t.scrollTop() + parseInt(getComputedStyle(t, '').getPropertyValue('line-height'), 10));
+ $t.scrollTop($t.scrollTop() + parseInt(getComputedStyle(t, '').getPropertyValue('font-size'), 10) + 3);
}
return false;
}
- });
+ }
+
+ };
+
+
+ /* ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- */
+ // tagget初期化
+ var init = function(t, i) {
+
+ // 被らないコードを振る
+ while ($('textarea').is('.tagget_' + i)) {
+ i = '0' + i;
+ }
+ $(t).addClass('tagget_' + i);
+
+ Wrapper.wrap(t);
+ Wrapper.absolutes(t);
+
+ // イベント設定
+
+ // keyup(発生タイミングが一番少ない)で候補表示
+ $(t).keyup(Event.keyup)
+
+ // 入力キーに応じた処理
+ .keydown(Event.keydown);
// 最初に1回だけ呼び出し。
- t.value = Cookie.unzip(Cookie.load(Wrapper.getId(t)));
+ var data = Cookie.load(Wrapper.getId(t));
+ if (data) {
+ t.value = Cookie.unzip(data);
+ }
Wrapper.setLine(t);
}; // init
self.each(function() {
- Cookie.save(Wrapper.getId(this), Cookie.zip(this.value));
+ if (Wrapper.checkCookie(this)) {
- var fillZero = function(s) {
- return ('0' + s).slice(-2);
- };
- var status = Wrapper.getStatus(this);
- var date = new Date();
- var y = date.getFullYear();
- var m = fillZero(date.getMonth() + 1);
- var d = fillZero(date.getDate());
- var h = fillZero(date.getHours());
- var min = fillZero(date.getMinutes());
- var sec = fillZero(date.getSeconds());
- status.children('.tagget_time')
- .html('Draft Saved At ' +
- y + '/' + m + '/' + d + '/' + ' ' + h + ':' + min + ':' + sec);
+ Cookie.save(Wrapper.getId(this), Cookie.zip(this.value));
+
+ var status = Wrapper.getStatus(this);
+ status.children('.tagget_time').html('Draft Saved At ' + Util.now());
+
+ }
setTimeout(timer, interval);
});
}, interval);
-
// This is jQuery!!
return this;