はてなリンク記法を展開

    @@ -1,7 +1,7 @@ /* * @title はてなリンク記法を展開 - * @description はてなリンク記法をa要素に展開します。つまり [http://b.hatena.ne.jp/:title=hoge] 等を <a href="http://b.hatena.ne.jp/">hoge</a> に変換します。 - * @include http://blog.hatena.ne.jp/* + * @description はてなリンク記法をa要素に展開します。つまり [http://b.hatena.ne.jp/:title=hoge] 等を <a href="http://b.hatena.ne.jp/">hoge</a> に変換します。 + * @include http://*.hatena.ne.jp/ * @license MIT License * @require */ @@ -12,25 +12,26 @@ var start = text.lastIndexOf('[', caret); var end = text.indexOf(']', caret-1); var notation = text.substring(start, end+1); - return notation.indexOf('\n') != -1 ? undefined : notation; + return notation.indexOf('\n') != -1 ? undefined : { notation: notation, start: start, end: end }; } function parseHatenaLinkNotation(notation) { - var result = {}; - var m_url = notation.match(/https?:\/\/[^:\]]+/); + var notation_str = notation.notation; + var result = { notation: notation }; + var m_url = notation_str.match(/https?:\/\/[^:\]]+/); if (m_url) { result['url'] = m_url[0]; } - var m_title = notation.match(/:title(?:=([^:\]]+))?/); // [http://b.hatena.ne.jp/:title=hoge] + var m_title = notation_str.match(/:title(?:=([^:\]]+))?/); // [http://b.hatena.ne.jp/:title=hoge] if (m_title) { result['title'] = m_title[1] ? m_title[1] : true; } - var m_bookmark = notation.match(/:bookmark]/); // [http://b.hatena.ne.jp/:title=hoge:bookmark] + var m_bookmark = notation_str.match(/:bookmark]/); // [http://b.hatena.ne.jp/:title=hoge:bookmark] if (m_bookmark) { result['bookmark'] = true; } - var m_embed = notation.match(/:embed(:cite)?]$/); // [http://b.hatena.ne.jp/:embed:cite] + var m_embed = notation_str.match(/:embed(:cite)?]$/); // [http://b.hatena.ne.jp/:embed:cite] if (m_embed) { result['embed'] = true; if (m_embed[1]) { @@ -97,14 +98,16 @@ return frag; } -function expandHatenaLinkNotation(result) { +function expandHatenaLinkNotation(result, textarea) { var expanded = result['embed'] ? expandEmbedHatenaLinkNotation(result) : expandSimpleHatenaLinkNotation(result); - var comment = document.createComment(notation); + var notation = result['notation']; + var comment = document.createComment(notation['notation']); var div = document.createElement('div'); div.appendChild(comment); div.appendChild(expanded); var replaceHTML = div.innerHTML; - textarea.value = textarea.value.replace(notation, replaceHTML); + var text = textarea.value; + textarea.value = text.substring(0, notation['start']) + replaceHTML + text.substring(notation['end']+1); } function main() { @@ -113,7 +116,7 @@ if (!notation) return; var result = parseHatenaLinkNotation(notation); if (typeof(result['title']) == 'string') { - expandHatenaLinkNotation(result); + expandHatenaLinkNotation(result, textarea); } else if (location.hostname == 'blog.hatena.ne.jp') { var syntax = '[' + result['url'] + ':title]'; $.ajax({ @@ -125,10 +128,12 @@ }).fail(function() { result['title'] = 'ここにタイトルを入力'; }).always(function () { - expandHatenaLinkNotation(result); + expandHatenaLinkNotation(result, textarea); }); } else { result['title'] = typeof(result['title']) == 'boolean' || result['embed'] ? 'ここにタイトルを入力' : result['url']; - expandHatenaLinkNotation(result); + expandHatenaLinkNotation(result, textarea); } -} +} + +main();
  • /*
     * @title はてなリンク記法を展開
     * @description はてなリンク記法をa要素に展開します。つまり [http://b.hatena.ne.jp/:title=hoge]  等を <a href="http://b.hatena.ne.jp/">hoge</a> に変換します。
     * @include http://*.hatena.ne.jp/
     * @license MIT License
     * @require 
     */
    
    function getHatenaLinkNotationOnCursor(textarea) {
      var text = textarea.value;
      var caret = textarea.selectionStart;
      var start = text.lastIndexOf('[', caret);
      var end = text.indexOf(']', caret-1);
      var notation = text.substring(start, end+1);
      return notation.indexOf('\n') != -1 ? undefined : { notation: notation, start: start, end: end };
    }
    
    function parseHatenaLinkNotation(notation) {
      var notation_str = notation.notation;
      var result = { notation: notation };
      var m_url = notation_str.match(/https?:\/\/[^:\]]+/);
      if (m_url) {
         result['url'] = m_url[0];
      }
      var m_title = notation_str.match(/:title(?:=([^:\]]+))?/);  //  [http://b.hatena.ne.jp/:title=hoge] 
      if (m_title) {
         result['title'] = m_title[1] ? m_title[1] : true;
      }
      var m_bookmark = notation_str.match(/:bookmark]/);  //  [http://b.hatena.ne.jp/:title=hoge:bookmark]
      if (m_bookmark) {
         result['bookmark'] = true;
      }
    
      var m_embed = notation_str.match(/:embed(:cite)?]$/);  // [http://b.hatena.ne.jp/:embed:cite]
      if (m_embed) {
         result['embed'] = true;
         if (m_embed[1]) {
            result['cite'] = true;
         }
      }
      return result;
    }
    
    function expandSimpleHatenaLinkNotation(result) {
      var a = document.createElement('a');
      a.setAttribute('data-snf-link', 'keep');
      a.href = result['url'];
      if (result['title']) {
        if (typeof(result['title']) == 'string') {
          a.innerHTML = result['title'];
        } else {
          a.innerHTML = result['title'];
        }
      } else {
        a.innerHTML = result['url'];
      }
      var frag = document.createDocumentFragment();
      frag.appendChild(a);
    
      if (result['bookmark']) {
        var bookmarkLink = document.createElement('a');
        bookmarkLink.href = 'http://b.hatena.ne.jp/entry/' + result['url'];
        bookmarkLink.className = 'http-bookmark';
    
        var bookmarkCount = document.createElement('img');
        bookmarkCount.src = '//b.hatena.ne.jp/entry/image/' + result['url'];
        bookmarkCount.className = 'http-bookmark';
    
        bookmarkLink.appendChild(bookmarkCount);
        frag.appendChild(bookmarkLink);
      }
      return frag;
    }
    
    function expandEmbedHatenaLinkNotation(result) {
      var iframe = document.createElement('iframe');
      iframe.setAttribute('data-snf-link', 'keep');
      iframe.src = 'https://hatenablog-parts.com/embed?url=' + encodeURIComponent(result['url']);
      iframe.title = result['title'];
      iframe.className = 'embed-card embed-blogcard';
      iframe.scrolling = 'no';
      iframe.style.display = 'block';
      iframe.style.width = '100%';
      iframe.style.height = '190px';
      iframe.style.maxWidth = '500px';
      iframe.style.margin = '10px 0px';
      var frag = document.createDocumentFragment();
      frag.appendChild(iframe);
      if (result['cite']) {
        var cite = document.createElement('cite');
        cite.className = 'hatena-citation';
        var citeLink = document.createElement('a');
        citeLink.href = result['url'];
        citeLink.innerHTML = result['title'];
        cite.appendChild(citeLink);
        frag.appendChild(cite);
      }
      return frag;
    }
    
    function expandHatenaLinkNotation(result, textarea) {
      var expanded = result['embed'] ? expandEmbedHatenaLinkNotation(result) : expandSimpleHatenaLinkNotation(result);
      var notation = result['notation'];
      var comment = document.createComment(notation['notation']);
      var div = document.createElement('div');
      div.appendChild(comment);
      div.appendChild(expanded);
      var replaceHTML = div.innerHTML;
      var text = textarea.value;
      textarea.value = text.substring(0, notation['start']) + replaceHTML + text.substring(notation['end']+1);
    }
    
    function main() {
      var textarea = document.getElementsByTagName('textarea')[0];
      var notation = getHatenaLinkNotationOnCursor(textarea);
      if (!notation) return;
      var result = parseHatenaLinkNotation(notation);
      if (typeof(result['title']) == 'string') {
        expandHatenaLinkNotation(result, textarea);
      } else if (location.hostname == 'blog.hatena.ne.jp') {
        var syntax = '[' + result['url'] + ':title]';
        $.ajax({
          url: 'http://blog.hatena.ne.jp/api/external/json?url='+encodeURIComponent('http://d.hatena.ne.jp/api/syntax?syntax=' + encodeURIComponent(syntax)) 
        }).done(function(json) { 
          var div = document.createElement('div');
          div.innerHTML = json[syntax];
          result['title'] = div.firstChild.innerHTML;
        }).fail(function() {
          result['title'] = 'ここにタイトルを入力';
        }).always(function () {
          expandHatenaLinkNotation(result, textarea);     
        });
      } else {
        result['title'] = typeof(result['title']) == 'boolean' || result['embed'] ? 'ここにタイトルを入力' : result['url'];
        expandHatenaLinkNotation(result, textarea);
      }
    }
    
    main();
  • Permalink
    このページへの個別リンクです。
    RAW
    書かれたコードへの直接のリンクです。
    Packed
    文字列が圧縮された書かれたコードへのリンクです。
    Userscript
    Greasemonkey 等で利用する場合の .user.js へのリンクです。
    Loader
    @require やソースコードが長い場合に多段ロードする Loader コミのコードへのリンクです。
    Metadata
    コード中にコメントで @xxx と書かれたメタデータの JSON です。

History

  1. 2018/02/23 09:23:15 - 2018-02-23
  2. 2018/02/23 09:20:14 - 2018-02-23
  3. 2018/02/19 17:56:48 - 2018-02-19
  4. 2018/02/19 17:54:19 - 2018-02-19
  5. 2018/02/19 12:39:23 - 2018-02-19
  6. 2018/02/19 12:08:23 - 2018-02-19
  7. 2018/02/19 12:01:03 - 2018-02-19
  8. 2018/02/19 11:28:16 - 2018-02-19
  9. 2018/02/19 11:19:40 - 2018-02-19
  10. 2018/02/16 20:22:55 - 2018-02-16
  11. 2018/02/16 19:32:49 - 2018-02-16
  12. 2018/02/16 19:28:18 - 2018-02-16