3
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Qiitaで見つけた便利なJavaScript保管庫

Last updated at Posted at 2020-06-14

これまで私はHTMLのページを作る上で、何度もQiitaの記事にお世話になってきました。それはこの記事を見ているあなたも(おそらく)同じでしょう。

この記事は、そんなQiita巡りの最中に私が出会った、「なくてはならない機能」「あったら便利な機能」を自分なりに書き直したものの保管庫です。まだ数は少ないですが、これから時間をかけて、もっともっと拡充していこうと思います。

jQueryが肌に合わない残念人間なので、元記事ではjQueryで書かれていたコードであっても、全てピュアJavaScriptに書き直されています。ご了承ください。

#ユーザーエージェント判別
参考:
使用してるブラウザを判定したい@sakuraya さん)
UserAgentからOS/ブラウザなどの調べかたのまとめ@nightyknite さん)

var _ua = (function () {
    var u = window.navigator.userAgent;
    return {
        device: (function (){
            for(var a of ["IEMobile","Android","iPod","iPad","iPhone"]) {
                if(u.match(a)) return a;
            }
            return "PC";
        })(),
        browser: (function (){
            var b = {
                MSIE: {n: "IE", v: /rv:([0-9\.]+?)(?:[^0-9\.]|$)/},
                Trident: {n: "IE", v: /rv:([0-9\.]+?)(?:[^0-9\.]|$)/},
                Edge: {n: "Edge", v: /Edge\/([0-9\.]+?)(?: |$)/},
                Edg: {n: "Edge Chromium", v: /Edg\/([0-9\.]+?)(?: |$)/},
                Chrome: {n: "Chrome", v: /Chrome\/([0-9\.]+?)(?: |$)/},
                Firefox: {n: "Firefox", v: /Firefox\/([0-9\.]+?)(?: |$)/},
                Safari: {n: "Safari", v: /Version\/([0-9\.]+?)(?: |$)/},
                Opera: {n: "Opera", v: /(?:OPR|Opera)(?: |\/)([0-9\.]+?)(?: |$)/}
            }
            for(var a in b) {
                if(u.match(a)) return [b[a].n, (u.match(b[a].v) ? u.match(b[a].v)[1] : null)];
            }
            return undefined;
        })()
    }
})();

console.log(_ua);
// {device: "iPhone", browser: ["Safari", "13.1.1"]}

#textarea用補完機能(用ボックス)
参考: GitHubのようなtextareaの補完機能を実装する - カーソル位置の取得@yuku_t さん)

下図のborder: solid 1px rgba(0, 0, 0, 0);の末端にあるキャレットにピッタリ沿うようにして赤いボックスが現れる。
safgshdjf.png

HTML
<div class="wrap">
    <textarea></textarea>
</div>
CSS
.wrap {
    position: relative;
}
/*
    candidates (候補)のboxで"candy box"。
    我ながらいいセンスだと思う。
*/
.wrap .candyBox {
    position: absolute;

    /*サンプル用スタイル*/
    background:#b01;
    height: 100px;
    width: 100px;
}
JavaScript

candyBox();//textareaのoninputなどのイベントハンドラで呼び出し

function candyBox() {
    var p = document.querySelector(".wrap");
    var t = document.querySelector(".wrap textarea");
    for(var a of document.querySelectorAll(".candyBox")) {
        a.remove();
    }
    function getCaret(node) {
        if(node.selectionStart) {
            return node.selectionStart;
        }else if (!document.selection) {
            return 0;
        }
        var c = "\001",
            sel = document.selection.createRange(),
            dul = sel.duplicate(),
            len = 0;
        dul.moveToElementText(node);
        sel.text = c;
        len = dul.text.indexOf(c);
        sel.moveStart('character',-1);
        sel.text = "";
        return len;
    }
    var index = getCaret(t);

    //キャレット位置より前の文章。
    var before = t.value.substring(0, index);

    //キャレット位置から先の文章。今回は未使用。
    var after = t.value.substring(index);

    //textareaのイミテーション
    var div = document.createElement("div");

    //候補用ボックス
    var box = document.createElement("div");
    /*
        候補をboxに入れる
        候補はbeforeとafterに対しての正規表現マッチを元にリストを生成し、以下の作業をfor文で回す

        @@@@ @@@@ @@@@ @@@@

        候補となるaタグをcreateElementしてboxにappendChild
        var a = document.createElement("a");
        a.innerText = "候補の文字列";
        box.appendChild(a);

        作ったaタグにonclickイベントを適用
        a.onclick = function(e) {
            //候補をクリックされたら、textarea内を書き換え
            //"選択された候補の文字列"はe.target.innerTextなどに置き換える

            t.value = before + "選択された候補の文字列" + after;

            //候補の挿入後のキャレットの位置の修正
            var n = (before + "選択された候補の文字列").length;
            t.setSelectionRange(n, n);

            //一度フォーカスを外さないとスクロール位置が正常に修正されない
            t.blur();
            t.focus();
        }
    */

    box.classList.add("candyBox");

    //textareaに適用されているスタイルをスタイルシートも含めて全て取得し、divにコピー
    var t_style = window.getComputedStyle(t);
    for(var k in t_style) {
        div.style[k] = t_style[k];
    }
    var scale = t_style.transform.split(/[^\d\.]/).filter(function(v) {return v});
    var scale_x = scale[0];
    var scale_y = scale[3];

    //キャレットの直前までのテキストを入力
    div.innerHTML = before;
    var span = document.createElement('span');
    span.innerHTML = '&nbsp;';
    div.scrollTop = div.scrollHeight;
    div.appendChild(span);
    document.body.appendChild(div);
    var d = div.getBoundingClientRect();
    var s = span.getBoundingClientRect();
    var r = {top: s.top - d.top, left: s.left - d.left};
    div.remove();

    //注1
    box.style.top = (r.top - t.scrollTop * (scale_y ? Number(scale_y) : 1)) + 'px';
    box.style.left = (r.left - t.scrollLeft * (scale_x ? Number(scale_x) : 1)) + 'px';
    p.appendChild(box);
}

注1: iOSにおけるフォーカス時の自動拡大防止のためなどでtextareaをCSSのtransform: scale()で拡大縮小している場合(iOSでinputのフォーカス時に画面がズームするのを防ぐ@skwbr さん)は、t.scrollTopに拡大縮小比率を反映させてください。この値はtransformによる変更が適用されないためです。追記: 反映をオートにしました。)

サンプル: http://topia.wikidot.com/csssss/code/2

#Cookie操作
参考: Cookieの情報を【取得/保存/削除】する@mocha_xx さん)

JavaScript
var Cookie = {
    cookie: function() {
        var o = {};
        if(document.cookie.length){
            var tmp = document.cookie.split('; ');
            for(var t of tmp){
                var d = t.split('=');
                o[d.splice(0,1)] = (function() {
                    var a = decodeURIComponent(d.join('='));
                    try {
                        var b = JSON.parse(a);
                        if(!Object.prototype.toString.call(b).match(/\[object (Array|Object)\]$/)) {
                            return a;
                        }
                        return b;
                    }catch(e) {
                        return a;
                    }
                })();
            }
        }
        return o;
    },
    get: function(k) {
        return this.cookie()[k];
    },
    set: function(k, v, limit) {
        document.cookie = k + "=" + encodeURIComponent(Object.prototype.toString.call(v).match(/\[object (Array|Object)\]$/) ? JSON.stringify(v) : v) + ";" + (limit ? " max-age=" + limit + "; " : " ") + "path=/";
        return this;
    },
    remove: function(k) {
        document.cookie = k + "=; max-age=0; path=/";
        return this;
    }
};

Cookie.cookie();
//{key1: "aaa", key2: 0, key3: {a: 1}}

Cookie.get("key1");
//"aaa"

Cookie.set("key4", "value");
Cookie.set("key4", "value").set("key5", [0, 1, 2, 3], 7*24*60*60);//第3引数は期限(秒)

Cookie.remove("key4");
Cookie.remove("key4").remove("key5");
3
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?