テキストをクリック(タップ)するだけで読み上げてくれる便利なブックマークレット

POSTED BY  
2016年3月28日
eyecatch

また一つ悩みが解決しましたよ!

活字嫌いの私は、日頃から「テキスト読み上げ」機能を活用しまくっています。

だが、一つだけ深刻な問題が… それは、iOSのSafariでテキストを選択するのがストレスで嫌になっちゃうんです(分かりますよね… いくら指でグリグリやっても、全く思い通りにテキストを選択できない苦痛…)。

もう我慢の限界です!試しに「Web Speech API(Speech Synthesis API)」を使って、テキストをクリック(タップ)するだけで読み上げてくれる便利なブックマークレットを作ってみましたので、シェアします。

分かりにくいと思うので、20秒ほどの動画を撮りました。

ブックマークレットの使い方

以下のコードを全選択して、コピー。

javascript:!function(){function e(e){return document.querySelectorAll(e)}function n(e,n){Array.prototype.forEach.call(e,function(e,t,c){n.apply(this,[e,t,c])})}function t(e){for(var n,t=[],c=document.createTreeWalker(e,NodeFilter.SHOW_TEXT,null,!1);n=c.nextNode();)t.push(n);return t.filter(function(e){return null===e.nodeValue.match(/^\s+$/)})}function c(e){var n=["SCRIPT","P","H1","H2","H3","H4","H5","H6","DT","A","ABBR","ACRONYM","B","BASEFONT","BDO","BIG","BR","CITE","CODE","DFN","EM","FONT","I","IMG","INPUT","KBD","LABEL","Q","S","SAMP","SELECT","SMALL","SPAN","STRIKE","STRONG","SUB","SUP","TEXTAREA","TT","U","VAR","TIME"];e.forEach(function(e){var t=document.createElement("span"),c=e.parentNode;n.indexOf(c.tagName)>-1||(t.className="______span______",t.style.cssText="display: inline !important;",t.appendChild(document.createTextNode(e.nodeValue)),e.parentNode.replaceChild(t,e))})}function o(e){var n=new SpeechSynthesisUtterance;n.volume=1,n.rate=1.4,n.pitch=1,n.text=e,n.lang="ja-JP",window.speechSynthesis.cancel(),window.speechSynthesis.speak(n)}function a(){c(t(document.body));var a=document.createElement("style");a.innerHTML=".__speeching__{ color: #2B2B2B; background-color: rgba(255,245,157,0.90); }",document.querySelector("head").appendChild(a);var r=e("body *:not(script)"),i=document.createElement("span"),s=i;n(r,function(e){e.addEventListener("click",function(e){return e.stopPropagation(),this===s?(window.speechSynthesis.cancel(),s.classList.remove("__speeching__"),void(s=i)):(o(this.innerText),s.classList.remove("__speeching__"),s=this,void s.classList.add("__speeching__"))})})}a()}();

そして、ブックマークとして登録して下さい。

あとは動画のように、使いたいサイトで、先ほど登録したブックマークを呼び出し後、読み上げて欲しいところをタップして下さい。

同じところを再度タップすると止まります。

ちなみに、iOSのSafariでは、たまに止まらない場合があります。数回タップすると止まることも…
原因は分からないがデスクトップでは、ChromeもSafariも正常ですけどね。ブラウザのバグですかね?

Chrome 45、Safari 9.1、iOS Safari 8.4 から使えるはずです。それ以下のバージョンでは「Speech Synthesis API」をサポートしていないので、使えません。

minify前のコード

minify前のコードもご参考に載せておきます。「速さ」と「言語」は変えられます。

(function () {
    function $(selector) {
        return document.querySelectorAll(selector);
    }

    function each(array, callback) {
        Array.prototype.forEach.call(array, function (value, index, self) {
            callback.apply(this, [value, index, self]);
        })
    }

    function textNodesUnder(el) {
        var n, a = [], walk = document.createTreeWalker(el, NodeFilter.SHOW_TEXT, null, false);
        while (n = walk.nextNode()) a.push(n);
        return a.filter(function (node) {
            return node.nodeValue.match(/^\s+$/) === null;
        });
    }

    function wrapTextNodes(textNodes) {
        var excludedElements = ['SCRIPT', 'P', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'DT', 'A', 'ABBR', 'ACRONYM', 'B', 'BASEFONT', 'BDO', 'BIG', 'BR', 'CITE', 'CODE', 'DFN', 'EM', 'FONT', 'I', 'IMG', 'INPUT', 'KBD', 'LABEL', 'Q', 'S', 'SAMP', 'SELECT', 'SMALL', 'SPAN', 'STRIKE', 'STRONG', 'SUB', 'SUP', 'TEXTAREA', 'TT', 'U', 'VAR', 'TIME'];
        textNodes.forEach(function (textNode) {
            var span       = document.createElement('span'),
                parentNode = textNode.parentNode;
            if (excludedElements.indexOf(parentNode.tagName) > -1) {
                return;
            }
            span.className = '______span______';
            span.style.cssText = "display: inline !important;";
            span.appendChild(document.createTextNode(textNode.nodeValue));
            textNode.parentNode.replaceChild(span, textNode);
        });
    }
    
    function speach(text) {
        var msg = new SpeechSynthesisUtterance();

        msg.rate = 1.9; // 速さ
        msg.lang = 'ja-JP'; // 言語
        msg.volume = 1;
        msg.pitch = 1;
        msg.text = text;

        window.speechSynthesis.cancel();
        window.speechSynthesis.speak(msg);
    }

    function main() {
        wrapTextNodes(textNodesUnder(document.body));

        var style = document.createElement('style');
        style.innerHTML = ".__speeching__{ color: #2B2B2B; background-color: rgba(255,245,157,0.90); }";
        document.querySelector('head').appendChild(style);

        var elements      = $('body *:not(script)'),
            dummyElem     = document.createElement('span'),
            speechingElem = dummyElem;

        each(elements, function (element) {
            element.addEventListener('click', function (e) {
                e.stopPropagation();
                if (this === speechingElem) {
                    window.speechSynthesis.cancel();
                    speechingElem.classList.remove('__speeching__');
                    speechingElem = dummyElem;
                    return;
                }
                speach(this.innerText);

                speechingElem.classList.remove('__speeching__');
                speechingElem = this;
                speechingElem.classList.add('__speeching__');
            });
        });
    }

    main();

})();

Hi, 中国四川出身の王です。2008年に日本に渡り、大学卒業後Web制作会社勤務を経て、現在はフリーランスとしてゆるりと働いています。サイト制作の全般を担当しています。好きな生き物はプーティ(マイCat)です。趣味はアニメ鑑賞です。画家になるのが夢だったりします!

関連記事

「条件付き書式」で行全体の色を自動的に変える方法(Google スプレッドシート)
2016年11月27日
生産性向上
分単位での日報は生産性を上げるのか?作業内容の記録がもたらす4つの効果
2016年2月27日
生産性向上
企画書・事業計画書の書き方:アイデア編
2015年12月17日
生産性向上

Post a comment

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です