OSDN Git Service

Safariでscrollが先頭にいっちゃう問題を修正
[ligheditor/tagget.git] / jquery.tagget.js
index bf1bc4c..fd72e5f 100644 (file)
@@ -6,7 +6,7 @@
  * Licensed under the MIT license.
  * Copyright (c) 2009 tagget.org
  *
- * version 0.1.0
+ * version 0.1.1
  */
 (function($) {
 
@@ -19,9 +19,6 @@
         */
        var Suggester = {
        
-               // 入力データを利用した補完を行うか
-               byInputs: true,
-
                keywords: {     
                
                        html: (function() {
@@ -64,6 +61,7 @@
                                        '<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;