即吊ブックマークレット改善版2015年05月26日 20時48分50秒

iOSでうまくいかなかったので…

前のエントリに載せたブックマークレットはソースが長すぎてiCloudで同期できなくてiOSでの動作確認もままならなかったので、意地になって改善しました。なんとか使い物になるかなぁ、と。

改善版ブックマークレット

即吊ダイアログ[改]

デスクトップブラウザなら↑のリンクをブックマークツールバーにドラッグドロップしてください。リンクをクリックするとpromptでjavascript:なURLを表示するので、スマートフォンやらタブレットの場合はこれをコピーした上で適当なページをブックマーク、編集で貼り付けてください。

ソース

こんな感じです。ブックマークレットにするにあたってはこのソースをpackerで圧縮して<をエスケープしています。

即吊ブックマークレット2015年05月21日 01時35分49秒

またの名を「ソク吊嵐」

即吊☆キャプチャー|WEBキャプチャーをTwitterに投稿しちゃうアプリケーション ってなサイトがあってですな。サイトの画面をキャプチャしてさくっとTwitterに投げ込むわけですよ。いたく便利で。

投稿するキャプチャー画像にコメント、ハッシュタグを入れる。特定のツイートにリプライするなど出来ます。

勢いです。勢い。

オプションもいろいろあって、ブックマークレットも用意されてるんだけども、prompt()連発のウィザード形式で、少々戸惑っちゃうんですわ。すぐに慣れるんだけども。

そこでなんとなく勢いでダイアログベースのブックマークレットを作ってみたわけなんですわ。ええ。

即吊ダイアログ

※:2015.5.25 ダイアログにスタイル適用したり、実験中パラメータ「callback」に対応したりで更新しました。

※:2015.5.26 ブックマークレットのURIが長すぎるせいか、iCloudでの同期がうまくいきません&iOSだとうまく動かないかも。

iCloudで同期できるサイズまで小さくしてiOS 8で動作するバージョンを作成しました。

吊りたいページでブックマークレットを起動するとこんなダイアログが出ます。

Firefox 38とChrome 42(どちらもWindows)でしか試してないし、オプションも追加コメントとお仕事場モードくらいしか試してないんだけども、まぁ一応使えるのではないかと。サイトによってはレイアウト崩れたりいろいろ問題ありそうだけども。

中身はこんな感じ(雑です)。

(function(act){
  var w=window,
    d=w.document,
    u=w.location.href,
    ex=function(){
      var args=Array.prototype.slice.call(arguments),ds=(args.shift()||{}),sr=(args.shift()||{});
      for(var p in sr){
        ds[p]=sr[p]
      }
      return args.length?ex.apply(null,[ds].concat(args)):ds;
    },
    dc=function(n){
      return d.createElement(n);
    },
    esc=function(s) {
      return s
        .replace(/&/g,'&amp;')
        .replace(/</g,'&lt;')
        .replace(/>/g,'&gt;')
        .replace(/'/g,'&apos;')
        .replace(/"/g,'&quot;');
    },
    term=function(e){
      setTimeout(function(){
        e.parentNode.removeChild(e);
      },100)
    },
    st={
      d:{
        fontSize:'14px',
        lineHeight:1.4
      },
      fm:{
        textAlign:'left',
        backgroundColor:'#fff',
        color:'#000',
        position:'absolute',
        width:'600px',
        padding:'10px',
        top:0,
        right:0,
        zIndex:9999,
        border:'solid 1px #999'
      },
      ttl:{
        textAlign:'center',
        fontWeight:'bold',
        fontSize:'20px',
        margin:'-5px -5px 5px -5px',
        backgroundColor:'#f9c',
        color:'#c71585'
      },
      txt:{
        width:'360px',
        border:'solid 1px #999'
      },
      lbl:{
        width:'195px',
        marginRight:'5px',
        display:'inline-block',
        textAlign:'right'
      },
      btn:{
        width:'150px',
        margin:'5px 5px 0 5px',
        padding:'4px 10px',
        border:'solid 1px #666',
        backgroundColor:'#eee'
      }
    },
    trimFields=function(fm){
      for(var ls=fm.getElementsByTagName('input'),i=0,l=ls.length;i<l;i++){
        if((ls[i].type=='text'&&!ls[i].value.length)||(ls[i].type=='checkbox'&&!ls[i].checked)){
          ls[i].disabled=true;
        }
      }
      setTimeout(function(){fm.submit();term(fm)},0)
    };
  d.body.appendChild((function(){
    var fm=ex(dc('form'), {
        method:'get',
        action:act,
        target:'_blank',
        onsubmit:function(){trimFields(fm)}
      }),
      title=ex(dc('div'),{innerHTML:esc('ソク吊嵐ダイアログ')}),
      btn=null;
    ex(fm.style,st.d,st.fm);
      ex(title.style,st.d,st.ttl);
    fm.appendChild(title);
    var items=[
      {lbl:'吊るURL',ttl:'即吊したいURLを入れてください(必須です。)',ele:ex(dc('input'),{type:'text',name:'url',value:u,readonly:'readonly'})},
      {lbl:'ハッシュタグ',ttl:'ハッシュタグを付けます。全角半角空白、カンマで多重に付けることができます。',ele:ex(dc('input'),{type:'text',name:'hashtag'})},
      {lbl:'サイト全体キャプチャを試行',ttl:'allとリクエストすると出来る限りWEBサイト全体をキャプチャーしようと頑張ります。',ele:ex(dc('input'),{type:'checkbox',name:'images',value:'all'})},
      {lbl:'追加コメント',ttl:'コメントを付けることが出来ます。',ele:ex(dc('input'),{type:'text',name:'text'})},
      (function(){
        if(!/^https:\/\/twitter\.com/.test(u))return {};
        return {lbl:'このツイートにリプライ',ttl:'1とリクエストすると吊るサイトがツイートならば、そのツイートに.@でリプライを付けて投稿します。',ele:ex(dc('input'),{type:'checkbox',name:'reply',value:'1'})};
      })(),
      {lbl:'返信元ツイートURL',ttl:'吊るサイトを狙ったツイートに.@でリプライを付けて投稿します。(ツイートのURL入れてね。)',ele:ex(dc('input'),{type:'text',name:'status'})},
      {lbl:'職場モード',ttl:'1とリクエストするとターミナル風CSSモードで投稿します。お仕事場でも恥ずかしくありません。かも',ele:ex(dc('input'),{type:'checkbox',name:'terminal',value:'1'})},
      {lbl:'自分にナルト',ttl:'1とリクエストするとピリオド無しの@でこっそり魚拓したのを自分に向けてメンションします。',ele:ex(dc('input'),{type:'checkbox',name:'mention',value:'1'})},
      {lbl:'戻り先',ttl:'吊り終わったら飛びたいURIにを入れてください。ページ出力前にページ遷移しちゃうのでちょっと動作が早いですが><',ele:ex(dc('input'),{type:'text',name:'callback'})}
    ];
    for(var i=0,l=items.length,item=items[i],lbl;i<l;i++,item=items[i]){
      var ln=dc('div');ex(ln.style,{margin:'3px 0'});
      if('lbl' in item){
        lbl=ex(dc('span'),{innerHTML:esc(item.lbl)});
        ex(lbl.style,st.d,st.lbl);
        ln.appendChild(lbl);
      }
      if(('ttl' in item)&&lbl){
        ex(lbl,{'title':item.ttl});
      }
      if('ele' in item){
        if(item.ele.type=='text'){
          ex(item.ele.style,st.d,st.txt);
        }
        ln.appendChild(item.ele);
      }
      fm.appendChild(ln);
    }
    ln=dc('div');ex(ln.style,{marginTop:'10px',borderTop:'solid 1px #ccc'});
    ex(ln.style,{marginTop:'10px',textAlign:'center'});
    fm.appendChild(ln);
    btn=ex(dc('button'),{type:'submit',innerHTML:esc('吊る!')});ex(btn.style,st.d,st.btn);
    ln.appendChild(btn);
    btn=ex(dc('button'),{type:'button',innerHTML:esc('やめる'),onclick:function(){term(fm)}});ex(btn.style,st.d,st.btn);
    ln.appendChild(btn);
    return fm;
  })())
})('http://drinker.slfeed.net/archive/')


秀樹さん。2008年07月05日 15時44分21秒

ええ、貼らせていただきましたとも。すばらしすぎます。残すところ約6.8年、みんなで祝えるとよいですね。

gelatoを試してみたり。2008年02月25日 21時32分03秒

久々の更新なのに全然 Zend じゃないし。

前々から興味があったのだ

しばらく前にMOONGIFTで紹介されていて、激しく興味があったオープンソースCMS「gelato」。これ、要するにtumblrクローン。

まぁ、まだバージョンが0.95なので鋭意開発中、って感じなんだろうけど、tumblr感覚でローカルにぽこぽこPOSTできるとちょっといいよな、と思って試しにインストールしてみた。

インストール

インストールはこちらの記事を参考に。つか、まんまです。PHPのアプリケーションインストールしたことあるならほとんど迷わないと思うけど、install.phpでDBがらみの情報入力させる割りに先に「config.php」にDB設定書き込んどかなきゃなんなかったのがイマイチ腑に落ちないけど。

それから先ほどのLiner Noteさんとこから、日本語化ファイルをダウンロードできるのでそちらも忘れずに。ありがたや、ありがたや。

使ってみる

管理画面はtumblrのダッシュボードのようにはいかず、ちょっぴり使いづらいんだけど、まぁ普通にPOSTできるわな。

ただ、設定でタイムゾーン選択できるんだけど、POSTに上手く反映されてないような。

あと、わかりづらいけど一応ブックマークレットもついてます。図の赤枠のところがリンクになってて、これをブックマークすれば一応ブックマークレット。

POST画面
「一応」って断り書きをしたのは、ちょっとクセがあってtumblr感覚で使うとわりと戸惑うかと。 試した限りでは、
  • 普通にクリックするとlink
  • なにか選択してると、選択部分のテキストを本文にしてregular post
  • 画像を表示しているとphoto
といった感じ。tumblrみたいに親切にページ中の画像を列挙してくれたり、選択部分からquoteしてくれたりはしない上に、ブックマークレットから起動したPOSTフォームは単機能なので切替もできず。もうちょっとがんばって欲しいところ。

JSActionのスクリプトを書いてみる

んで、実はこっからが本番。そもそもローカルで使いたい動機は、社内に設置している内向きのブログ書くときに、スクリーンショットとかを手間なくホストしときたいなーってとこだったわけ。なので、

  1. まずはJSActionでphoto直行
  2. その次はcapture.tumblr.jsをローカルgelato対応に
なんて野望を抱いているわけで。

capture.tumblrはちとソース読むのが大変そうなので、まずはフォームの構造を調べがてらJSActionスクリプトを作ってみた。こんな感じ。

// post photo to gelato
new function(base) {
	function h2q(h) {
		var buf = [];
		for(var key in h) {
			if( typeof(h[key]) != "function" ) {
				buf.push( encodeURIComponent(key) + "=" + encodeURIComponent( h[key] == null ? "" : h[key].toString() ) );
			}
		}
		return buf.join( "&" );
	}
	var url = window.location.href;
	var title = window.title || window.document.title || window.location.href;
	var img = _jsaCScript.context.target;
	if( ! /^img$/i.test( img.localName ) ) return;
	
	var xhr = new XMLHttpRequest();
	xhr.open( "post", base, false );
	var hash = {
		title : title,
		url : img.src,
		date : parseInt( new Date().valueOf() / 1000 ),
		type : 2,
		description : "<a href=\"" + url + "\" title=\"" + title + "\">(via: " + title + " )</a>",
		btnAdd : "Create post"
	};
	xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
	xhr.send( h2q( hash ) );

} ( "http://localhost/gelato/admin/index.php" );

あ、gelatoってGPL v2なんだけど、こういうスクリプトってGPLに引きずられるのかなぁ、と心配になったのでこのスクリプトも「GPL v2」ということにします。

このスクリプトをJSActionのimageフォルダに保存して、一番最後の関数呼び出しに使ってる引数にPOST先のURLに変更して使う。この例では「http://localhost/gelato/」がgelatoのURLね。

実はちょっと注意点があって、POSTデータの「description」(linkのcaption)に元ページのURLをanchorでくっつけてるんだけど、gelatoはdescriptionをstrip_tags()しちゃうのでこのままだとリンクにならない。

そのままでもいいやってなら別になにもする必要はないけど、admin/index.phpの72行目あたりの

$_POST["description"] = strip_tags($_POST["description"]);
$_POST["description"] = $_POST['description'];
に変更すればHTMLタグ使い放題。あー、自己責任でおながいします。

あ、あとほんとに最低限の実装なので、例えばflickrで「all sizes」がある場合はそっちへ飛んでからじゃないと上手くPOSTできません。あとPOSTエラーも特に何もしてないので、「POSTされてなかったらなんかエラーでたんだなー」といった感じで使ってください。使う人いるかわからんけど。

その他の情報

  • 一応read apiも実装してるっぽいけど、コメントアウトの仕方が悪くてエラーになったり、そのあたり解消してもまともに情報返してくれなかったり。
  • なぜか編集ができない。新規POST扱いになる。
  • photoはlightbox使って表示するんだけど、上手く表示できないときがある。
  • lightboxとかで使ってる画像リソースのパス解決が上手くいかない場合があるっぽい。
  • アカウントを複数作れるけど、アカウント別に表示できたりするわけじゃないし、他のアカウントのPOST削除できちゃうし。
  • svnから最新ソースをチェックアウトしてみたけどクラスだか関数の重複定義とかでエラーがでて、もうぐだぐだ。
などなど、まだまだかなりバタバタした感じですが、ローカル(or イントラ)画像サーバと思えばなんとか使えなくもないかな。

次はがんばってcapture.tumblr.jsの改造だ。多分。

いまごろMyMiniCity始めてみたり。2007年12月27日 03時32分57秒

話題になりはじめてからもう結構たつと思うが、なんとなく今ごろ始めてみました。

まだ始めたばっかりなので人口わずか6人w なので、トップのURLしかないけど、人口増えてURL増えたら随時サイドバーに足してくつもり。

ちゃんと育つかなぁ...