2016年11月5日土曜日

Blogger でリアルタイム プレビュー (クロスブラウザー対応)

イメージ

前回の記事で紹介した、Blogger でリアルタイム プレビューをするためのブックマークレットを、クロスブラウザー対応しました。

これにより、Chrome 以外のブラウザーでもリアルタイム プレビューができます。

動作確認ブラウザ (すべて Windows 10)

  • Chrome 54
  • Internet Explorer 11
  • Microsoft Edge
  • Mozilla Firefox 49.0.2

ブックマークレットの登録

以下のリンクをブラウザーのブックマーク バー (IE の場合はお気に入りバー、FF の場合はブックマークツールバー) までドラッグして、ブックマークレットとして登録します。

リアルタイム プレビュー

Microsoft Edge の場合は、ブックマークレットを直接登録することができないため、任意のブラウザーでブックマークレットを登録し、そのブラウザーからお気に入りとしてインポートしてください (参考: Microsoft Edge でお気に入りをインポートする - Microsoft Support)。

使い方

前回の記事を参照してください。

ソース コード (圧縮前)

このブックマークレットは前回同様に MIT ライセンスで公開しています。

/**
 * Copyright (c) 2016 Toshiya Asai.
 *
 * License: The MIT License (https://opensource.org/licenses/MIT)
 */

// デバッグ用
// debugger;

(function () {
  var framePost;           // 投稿用のフレーム
  var framePreview;        // プレビュー用のフレーム
  var title;               // 「タイトル」テキスト フィールド
  var previewButton;       // 「プレビュー」ボタン
  var postingComposeBox;   // 投稿用のリッチ テキスト エディタ
  var postingHtmlBox;      // 投稿用のテキストエリア
  var prevTitle;           // 比較用のタイトルの内容
  var prevRichTextContent; // 比較用のリッチ テキスト エディタの投稿内容
  var prevContent;         // 比較用のテキストエリアの投稿内容
  var timerId = 0;         // プレビューを更新するために使うタイマー

  // 初期処理
  var init = function () {
    framePost = frames[0];
    framePreview = frames[1];

    // 投稿用のフレームから開かれるウィンドウをプレビュー用のフレームにする
    framePost.window.open = function (url, name, params) {
      framePreview.location.href = url;
      return framePreview.window;
    }

    waitUntilLoad(function () {
      waitUntilLoaded(function () {
        // 必要な要素を取得する
        title = framePost.document.querySelector('input[type=text][title=タイトル]');
        previewButton = findElement('.blogg-button', 'プレビュー');
        postingComposeBox = framePost.document.getElementById('postingComposeBox')
          .contentDocument.getElementById('postingComposeBox');
        postingHtmlBox = framePost.document.getElementById('postingHtmlBox');

        // タイトルと投稿内容を取得する
        prevTitle = title.value;
        prevRichTextContent = postingComposeBox.innerHTML;
        prevHtmlContent = postingHtmlBox.value;

        // 「プレビュー」ボタンを擬似的にクリックしてプレビュー
        previewButton.click();

        // 監視を開始する
        watch();
      });
    });
  };

  // 「読込中...」が表示されるまで待機
  var waitUntilLoad = function (loadFunc) {
    var loading = findElement('.gwt-HTML', '読込中...');
    if (loading !== null) {
      loadFunc();
      return;
    }

    // 500 ミリ秒ごとに確認する
    setTimeout(function () { waitUntilLoad(loadFunc); }, 500);
  }

  // 「読込中...」が非表示になるまで待機
  var waitUntilLoaded = function (loadedFunc) {
    var loading = findElement('.gwt-HTML', '読込中...');
    if (loading === null) {
      loadedFunc();
      return;
    }

    // 500 ミリ秒ごとに確認する
    setTimeout(function () { waitUntilLoaded(loadedFunc); }, 500);
  }

  // 要素を検索
  var findElement = function (selectors, text) {
    var elements = framePost.document.querySelectorAll(selectors);
    for (var i = 0; i < elements.length; i++) {
      if (elements[i].textContent === text) {
        return elements[i];
      }
    }
    return null;
  }

  // 監視
  var watch = function () {
    // タイトルか投稿内容が変更されていたらプレビューを更新する
    if (title.value !== prevTitle
        || postingComposeBox.innerHTML !== prevRichTextContent
        || postingHtmlBox.value !== prevHtmlContent) {
      updatePreview();
    }

    // 比較用のタイトルと投稿内容を更新する
    prevTitle = title.value;
    prevRichTextContent = postingComposeBox.innerHTML;
    prevHtmlContent = postingHtmlBox.value;

    // 500 ミリ秒ごとに確認する
    setTimeout(watch, 500);
  }

  // プレビューの更新
  var updatePreview = function () {
    // 1 秒以内に投稿内容が更新された場合には、前回のタイマーをキャンセルする
    clearTimeout(timerId);

    // プレビューを更新する
    timerId = setTimeout(function () { previewButton.click(); }, 1000);
  }

  // フレームに置き換える
  var fs = document.createElement('frameset');
  var f1 = document.createElement('frame');
  var f2 = document.createElement('frame');
  fs.cols = "*,*";
  f1.src = location.href;
  f1.addEventListener('load', init);
  fs.appendChild(f1);
  fs.appendChild(f2);
  document.documentElement.innerHTML = '';
  document.body.appendChild(fs);
  document.body.style.margin = '0px';

  // IE、MS Edge 用
  document.documentElement.style.height = '100%';
  document.body.style.height = '100%';
  frames[0].location.href = location.href;
})();

0 件のコメント:

コメントを投稿