]>
DSiブラウザー (Opera 9.50) で便利に使える ブックマークレット集です。
追加用補助リンクを各項目に置いてあります。
クリックするとエラーが出ますが、かまわず ★お気に入りに「ページを追加」し、
「編集」で頭の
opera:を削ってください。
タイトルも各自で勝手につけてください。
DSiブラウザーではPC用のように リンクをブックマークバーへドラッグで追加、
みたいな器用な操作ができないため、こうしています。
$Id: bookmarklet.html,v 1.72 2019-07-31 00:11:04+09 kabe Exp $
DSiブラウザーはコピーペーストができないので、 <A HREF> になっていないベタ書きURLに簡単にアクセスできません。
テキスト部分をタッチペンで長押しすると、文字列を領域選択できます。 普通はこれを検索エンジンに食わせて検索するんですが、
以下のようなURL (Bookmarklet)を「お気に入り」の「編集」で入れておけば、 ベタ書きURLをテキスト選択後にその お気に入りを選択することで そのURLに飛べるようになります。
javascript:function(w,u){w.location=(u=w.getSelection()+'').indexOf('://')<0?'http://'+u:u;}(window);
DSiブラウザにはステータスバーがないので、<A href>のリンク先が どんなURLかを簡単に確認できません。
以下のようなURL (Bookmarklet)を「お気に入り」の「編集」で入れておけば、 リンクを選択 ( /L◘] もしくは [◘R\ ボタンを押しながら十字キー) 後に その お気に入りを選択することで そのURLを確認できます。
javascript:alert(document.activeElement.href)
リンク先のアドレス(URL)を確認のうえ、 ちょっと編集した後にそこへ飛ぶ、といった操作に使います。 PCブラウザなら、 リンクを右クリック→「リンクのコピー」→アドレスバーに貼り付け→編集→Enter、 としているような操作を可能にします。
<A href> だけでなく、 ベタテキストをタッチペン長押しで選択した文字列や、 フォーム部品 (textboxやSubmitボタン) のリンク先も 一応表示・編集できます。 onclickも拾えるものは表示。
サンプル画面:
javascript:
## Show HREF of the selected element in TEXTAREA.
## Selected document.activeElement could be
## - <A>
## - <FORM><INPUT>
## - <LI><A><block>
function(d,h){
function U(s){return s.toUpperCase()}
var a=d.activeElement,p=a.parentNode;
if(!h){
//h is getSelection(). if null, try activeElement
h=a.href;
if(U(a.nodeName)!='A'&&U(p.nodeName)=='A'){
## When <LI><A href><block></A></LI>, or <LI onclick>,
## <block> will be the activeElement. Use parent's href.
h=p.href;
}
}
if(!h&&a.form){
## <FORM><INPUT>
## try use <FORM action="..."> as the URL
h=a.form.action;
for(var q=0;q<a.form.length;q++){h+=(q?'&':'?')+a.form[q].name+'='+a.form[q].value;} //build full QUERY_STRING
}
## Try getting onclick string.
## Only explicit <INPUT onclick="<code>"> is extractable via getAttribute();
## dynamically set hooks are only .toString()="[ECMA script code]"
var c;
for(p=a;p;p=p.parentNode){ //iterate up the hierarchy for onclick hook
if('function'==typeof p.onclick){
c=p.getAttribute('onclick');
if(!c)c=p.onclick+''; //try toString() method anyway
break;
}
}
//'?'; // prevent \ to be / below
//function e(s){return s.replace(/[&<>"]/g,function(c){return '\&#'+c.charCodeAt(0)+';'})}
d.write('<SCRIPT>
function $(id){return document.getElementById(id);}
</SCRIPT>'+
(a.outerHTML?a.outerHTML:'')+'<br>
<FORM>
<TEXTAREA cols=48 rows=5 name=8 id=8>'+h.replace(/[&<>]/g,function(c){return '\&#'+c.charCodeAt(0)+';'})+'
</TEXTAREA><br>
<INPUT type=button name="goto" value="Jump as URL" onclick="location.href=$(8).value" />
<INPUT type=button name="unescape" value="unescape" onclick="$(8).textContent=$(8).value=decodeURIComponent($(8).value)" />'+
(c?'<br>onclick:'+c:'')+'
</FORM>
')
}(document,getSelection()+'');
[unescape]ボタンで、URL中の %E6%A4%9C といった
エンコード文字列をベタ文字列に戻します。UTF-8のみ対応。
中身を確認したい用途です。URLとしてジャンプは不可能になることが多いです。
今見ているページが重すぎて途中でレンダリングが止まる場合は、 Google Wireless Transcoder 経由にすれば見れる可能性があります。
以下のようなURL (Bookmarklet)を「お気に入り」の「編集」で入れておけば、 現在のページをGWT経由で表示できます。 サイトによってはアクセス拒否したりリダイレクトされたりと、必ずしもうまくいく わけではないようですが。
javascript:window.location.href='http://www.google.co.jp/gwt/x?gl=JP&hl=ja-JP&oe=sjis&u='+escape(window.location.href);
軽量変換には googleweblite もあります。 こっちのほうが軽量です。 Cookieは消されます。
javascript:window.location.href='http://googleweblight.com/?f=1&lite_url='+escape(window.location.href);
transcode されたHTMLでは <meta content="width=device-width"> でタテ長表示が強制されます。 iPhone用しか考えてない典型例ですね。 User-Agent も Mobile Safari になります。
DSiブラウザでは字がかなり大きくなってしまうので、 タテ長表示を解除 ブックマークレットと 併用したほうが良いかもしれません。
javascript:window.location.href='http://mgw.hatena.ne.jp/?split=0&url='+encodeURIComponent(location.href);追加用補助リンク
ケータイ向けだけあり、はてなモバイルゲートウェイのほうが軽いです。 cookieも削除されます。ちょっとした広告がつくのと、 < > の処理が変な気がしますが。
javascript:window.location.href='http://servermobile.net/index.php?'+encodeURIComponent(location.href);追加用補助リンク
フィーチャフォン風にページを再フォーマットしてくれるサービス。 DSiでも重いページを見るのに使えます。 字が全部青色になるのが謎ですが。
普段は画像の読み込み オフ で使っている人用のブックマークレットです。 [画像]を、画像へのリンクに変換します。 ちょっとその画像だけ見たい、ときに重宝します。 (画像オフでも直接画像へのリンクを踏めば画像だけは見れます)
| → |
|
javascript:
## Bookmarklet to make <IMG> to be clickable,
## which directly jumps to the image.
## Also fills in blank <IMG alt> by filename.
## Useful for viewing in no-image mode.
##
## ex. http://www.nintendo.co.jp/ds/dsilink/ , which is the
## first bookmark in default Favorites, is
## totally uncomprehensible in no-image mode.
##
function(){
var id=document.images,
is=[],
i,p,g;
// Images come in 2 flavors:
// <IMG> (document.images)
// <INPUT type=image>
// collect them into is[]
// collect <IMG>
// document.images exposes .length etc, so we can't "for(i in ..)"
for(i=0;i<id.length;i++)
is.push(id[i]);
// collect <INPUT type=image>
for(i in (g=document.getElementsByTagName('input'))){
if(g[i].type=='image')
is.push(g[i]);
}
// img2link for collected images
for(i in is){
if(!(g=is[i]).alt){
// Add at least a filename on blank <IMG alt="">
g.alt=g.src.slice(g.src.lastIndexOf('/')+1);
}
// Set border with <IMG style="...">, as
// DSi browser doesn't have blue border on <A><IMG></A>.
// Setting style on outer <A> doesn't work properly
// if inner <IMG> has style="position:relative|absolute".
// Caveat: you won't get purple for A:visited link.
// (alt text will be purple)
// This style may not be still effective on vertical (SSR) mode,
// unless <META name=viewport content="width=device-width">
g.style.border='1px solid blue';
// onclick die die die
g.onclick=null;
if((p=g.parentNode)&&p.nodeName=='A'){
// Already <A href="..."><IMG src="..."></A>;
// Rewrite the parent <A href>
p.href=g.src;
//p.style.border='2px solid'; // doesn't work properly
p.onclick=null;
continue;
}
// Plain <IMG>. Wrap it with <A>
// This assignment will rewrite <IMG> element to <A>,
// which isn't very nice on DOM
g.outerHTML='<A href="'+g.src.replace(/&/g,'&')+'">'+g.outerHTML+'</A>';
}
alert(++i +' image links'); //it worked!
}()
追加用補助リンク
画像が他所へのリンクやsubmitボタンや余計なonclickつきだったなど、 元の機能は失われるので、戻す際はリロードしてください。
DSiブラウザーでは右クリック→画像を読み込み、のような操作ができないので、 こういうブックマークレットが必要です。
DSiブラウザーを初期化した際に、お気に入りの最初に入っている 「ニンテンドーDSi リンク集」は、画像だけで alt も何も ついていないので、画像オフにしていると全く意味不明です。 なお、このページはDSiブラウザー以外はホームページに飛ばされるよう 細工されているので、PCなどで見る際は すぐ読み込み停止させるか、 いったんダウンロードしてからエディタで編集してリダイレクトロジックを潰します。
欧州用DSiリンク集は ちゃんとしたaltがついてるし、 北米用DSiリンク集では DSi以外を締め出すこともしてないんですけど…
小型端末のブラウザは <META name=viewport> を設定することで 表示のされ方を変更できます。
DSiブラウザーでは content="width=240" もしくは
width=device-width
を指定することで、タテ長表示モードに強制的に変更できます。
opera:about なんかでは画面モードの
変更ができないようになっていますが、それと同じです。
javascript:function(){var w=prompt('Set viewport to (768/240/device-width)','width=device-width');if(w)document.getElementsByTagName('head')[0].innerHTML+='<meta name="viewport" content="'+w+'" />';}()
副作用で、タテ長表示にしていてもスタイルシートが完全に有効になります
が、小型端末用のスタイルシートを準備しているサイトは
ほとんどないので、大抵は見るも無残な状態になります。
要は2画面モードの拡大画面を無理やり240pxに狭めた状態になる。 横幅800px決めうちでレイアウトしているサイトがちゃんとレンダリング できるはずがないので、 一般サイトでは笑いを取る以外の実用性はない、かも。
逆に、DS用サイトを謳っていたり、モバイル対応を自称しつつ iPhone専用サイトになっていてちゃんと見れないサイトで、 強制されたタテ長表示を解除する、という用途には 実用性があるかもしれません。
ブックマークレットを起動するとprompt()で設定値を
聞かれますが、そのまま「決定」すれば強制 タテ長表示 になります。
width=768を指定すれば、2画面モードのデフォルト値になります。
DSiブラウザーは CSSの @media type や Media Queries に 対応していて、しかるべき CSS を準備してやれば 同じページでPC用と小型端末用の両対応ができることになってます。 width切替テストのページ を作ってみましたので、つつきまわしてみてください。 (Opera 9.5といえど完璧でもないことがわかる)
iPhoneで見ることしか考えていないサイトなど、
強制的にタテ長表示モードにされているのを解除して
通常表示にできるようにします。
タテ長にするよりは使う頻度は高そうです。
タテ長表示を常用しているのであればSSRモードが有効になるので、
iPhone専用サイトではより見やすくなります。
javascript:function(){document.getElementsByTagName('head')[0].innerHTML+='<meta name="viewport" content="width=768" />'}()
Cookieを見るブックマークレットは色々ありますが、
見るだけなら alert()を使うのが簡単でしょう。
動作も軽い。
javascript:alert(document.cookie);
Cookieには name=value の他に
;path=/... ;domain=.domain ;expires=date
といった属性がありますが、JavaScriptからはアクセスできません。
(なので、「Cookieを消す」ブックマークレットは色々苦労している模様)
今見ているページのCookieを全部消します。 標準機能では「設定」→「Cookieの削除」での 全サイトの全消去しかできないので、 個別のサイト、あるいはウェブページの単位で消したい、 今消したい、 時に使います。
サンプル画面:
javascript:
(function(_d,_l){
## Delete a cookie
function d(c){
var h,
o=_d.cookie;
c+='=;expires=Thu, 01-Jan-1970 00:00:00 GMT';
function r(c){
## Iterate up /path/to/here
## "_d.cookie==o" checks if the cookie is actually deleted,
## in incomplete attempt to delete only the
## cookie of same name with deeper path.
## This check also significantly reduced exec time.
for(var v=_l.pathname.split('/');_d.cookie==o&&v.length;v.pop()){
## delete the cookie
_d.cookie=c+';path='+(v.length==1?'/':v.join('/'));
}
}
## Try erasing without ";domain"
r(c);
## Try erasing with ";domain=..."
//detail.chiebukuro.yahoo.co.jp
// .chiebukuro.yahoo.co.jp
// .yahoo.co.jp
// .co.jp
## "_d.cookie==o" also here to halt at longer domain
for(h=_l.hostname;_d.cookie==o&&h.split('.').length>2;h=/[.]?[^.]*(.*)/.exec(h)[1]){
r(c+';domain='+h);
}
}
var i,cs=_d.cookie.split(/ *; */);
if(!cs||!cs[0]){ ## if no cookie, cs[0] will be ''
alert('no cookies');return;
}
if(!confirm('Delete '+cs.length+' cookies?\n'+_d.cookie))return;
for(i in cs)d(cs[i]);
})(document,location); ## top wrapper
追加用補助リンク
制限: 今見ているサイトのCookieしか消せません。
これは JavaScript (というかDOMのdocument.cookie) の制限です。
PC用のブラウザのようにオフラインでCookieの閲覧編集は
DSiブラウザではできません。
DSiブラウザーはCookie保持数に制限があるみたいなので、 2度と来ないようなページを見た際は こまめにCookieを消したほうがいいのかもしれません。
今見ているページのCookieの一覧を表示し、個別に[delete]ボタンで消します。
サンプル画面:
javascript:
### Bookmarklet to show and selectively delete a Cookie of current page
document.write('<SCRIPT>
_dc=document;
## Read the current cookie, build a table, and
## re-inject the HTML into _cKp element
function t(){
function e(s){
## we need to escape ' also to prevent Cookie-based attack
return s.replace(/[&<>`"]/g,function(c){return `&#`+c.charCodeAt(0)+`;`;})
}
var q="`",
h=`<TABLE border=1><CAPTION>Cookies on `+e(location.href)+`</CAPTION>`,
cs=_dc.cookie.split(`;`),
i,v;
if(!cs||!cs[0]){ ## if no cookie, cs[0] will be ``
## Showing nothing isn't nice, so say so
cs=[`---=no cookies`];
}
## Build a table of |name|value|[delete]|
for(i in cs){
if(v=/ *([^=]*)=(.*)/.exec(cs[i])){
h+=`<TR><TD>`+e(v[1])+`<TD><INPUT type=text value="`+e(v[2])+`"><TD><INPUT type=button value=delete onclick="javascript:this.disabled=true;d(`+q+e(v[1])+q+`);">`;
}
}
## re-inject HTML
_cKp.innerHTML=h+`</TABLE>`;
}
## Delete a cookie
function d(c){
var h,
o=_dc.cookie;
c+=`=;expires=Thu, 01-Jan-1970 00:00:00 GMT`;
function r(c){
## Iterate up /path/to/here
## "_dc.cookie==o" checks if the cookie is actually deleted,
## in incomplete attempt to delete only the
## cookie of same name with deeper path.
## This check also significantly reduced exec time.
for(var v=location.pathname.split(`/`);_dc.cookie==o&&v.length;v.pop()){
## delete the cookie
_dc.cookie=c+`;path=`+(v.length==1?`/`:v.join(`/`));
}
}
## Try erasing without ";domain"
r(c);
## Try erasing with ";domain=..."
//detail.chiebukuro.yahoo.co.jp
// .chiebukuro.yahoo.co.jp
// .yahoo.co.jp
// .co.jp
## "_dc.cookie==o" also here to halt at longer domain
for(h=location.hostname;_dc.cookie==o&&h.split(`.`).length>2;h=/[.]?[^.]*(.*)/.exec(h)[1]){
r(c+`;domain=`+h);
}
t(); ## regenerate table
}
_dc.write(`<P id=_cKp></P>`);
_cKp=_dc.getElementById(`_cKp`);
t();
</SCRIPT>'.replace(/`/g,"'")
);
追加用補助リンク
同名で ;domain= や ;path= が異なる
Cookieが複数ある場合、
[delete] を押したほうでないCookieが消えることもあります
がそんなCookieの使い方をしているサイトは少ないので
実質問題はないでしょう。
DSiブラウザーのJavaScriptはエラーがあると何も言わずそこで 止まってしまうので、デバッグは難しかったです。 このブックマークレットは長いので、改造するにしても1000文字制限には注意。
DSiブラウザではクッキーの削除は「設定」→「Cookieの削除」での 全消去しかできないので、 せめてCookieを使っていることが分かっているサイトのCookieだけでも 保存しておきたい、時に使います。
javascript:
## Bookmarklet to save cookie of the current site.
## JavaScript cannot catch ";path=/...;expires=...", so
## the saved cookie will always be "path=/"(root path, session cookie)
##
document.write('<A href="opera:javascript:'+
// inside href="PCDATA" region. No " allowed(should be ")
('(function(){
if(location.host!=`'+location.host+'`){
alert(`not for this site`);return
}
var c=['+
// create ['NAME=VALUE','name=value',...], with each escape()ed
function(d){
c=d.cookie.split(/ *; */);
if(!c||!c[0]){return ''}
for(var i in c){
c[i]="'"+escape(c[i])+"'"
}
return c.join(',')
}(document)+
'];
if(confirm(`Restore following cookies?\\n`+c.join(`\\n`))){
for(var i in c){
document.cookie=unescape(c[i])+`;path=/`
}
}
})();').replace(/`/g,"'")+
'">Save cookie</A> << Click,Bookmark,Edit and delete "Opera:"<br>'+
c.length+' cookies for site '+location
)
追加用補助リンク
opera:を削ります。
名前(タイトル)も適当につけておきます。
このブックマークが、当該Cookie復帰用のブックマークレットになります。
path=/ (大抵はこれで問題ない)
opera:を削る編集操作で途中が切れてしまう)
現実には、どこのサイトのどのCookieを保存しておきたいか、 なんてのは DSiブラウザ単体では知りようがないので、 あらかじめPC用ブラウザでアタリをつけてからでないと 実運用は難しいと思います。
Cookie復帰で path= や expires= を含めて
復帰できない (保存時に読み出せていない) のは、
JavaScriptのセキュリティ上の仕様です。
session Cookieしか持てない (本体リセットで消えてしまう) DSブラウザー で 使えるかどうかは試していません。
以下のようなURL (Bookmarklet)を「お気に入り」の「編集」で入れておけば、 現在のページのHTMLソースコードを表示できます。
javascript:function(d){
d.write('<PRE style="white-space:pre-wrap;font-size:xx-small">'+
(d.documentElement.outerHTML||d.documentElement.innerHTML).
replace(/[&<>]/g,function(c){return '&#'+c.charCodeAt(0)+';'})+
'</PRE>');
}(document);
DSiブラウザーは view-source:URL や
server:source に対応してないので、
ソースを見るにはこの方法しかなさげです。
このブックマークレットを使えば opera:aboutの
ソースコードも見れます。
(なぜか file:///scripts/ などのソースは見れない)
他のブラウザでいう「ページ情報」を表示します。
文字エンコーディング、
最終更新時間、
使っている<SCRIPT>
など。
Size: はDOM経由で文字数を数えているので、概算です。
HTTPで流れてきたバイト数とは一致しません。
javascript:
## Show current page info:
## title, charset, Last-Modified, size(estimate), LINK, SCRIPT
function(d){
var m=d.lastModified,
l,i,lx="",jx="";
"?";// prevent \n to be /n
// collect <LINK>
l=d.getElementsByTagName("link");
for(i=0;i<l.length;i++){
lx+=l[i].outerHTML+"\n";
}
// collect <SCRIPT>
l=d.getElementsByTagName("script");
for(i=0;i<l.length;i++){
if(l[i].src)jx+="src="+l[i].src+"\n";
}
alert("
Title: "+d.title+"\n
Charset: "+d.charset+"\n
Last-Modified: "+((m=="January 1, 1970 GMT")?"none":m)+"\n
Size: "+d.documentElement.outerHTML.length+"\n
URL: "+d.location+
(lx?"\nLink: "+lx:"")+
(jx?"\nScript: "+jx:"")
)
}(document)
追加用補助リンク
Object名 (window.navigatorなど) を入力し、
中身をダンプします。
DOM探検や、javascriptプログラムの試験に使います。
一応、オフライン(インターネットにつないでいない状態)でも使えます。
javascript:
## Prompt an expression, and dump (enumerate) contents of that Object.
## Default expression will be the text of current selection.
## Expression evaluating to plain value will just be shown in alert().
##
## Interesting Objects:
## window
## window.navigator
## window.getSelection()
## document
## document.activeElement
## document.getElementsByTagName('SCRIPT')[0]
##
## What we want to do is
## 1. get current text selection, otherwise set default expression
## 2. prompt() for expression
## 3. eval() in *global context* (not in function)
## 4. enumerate and dump the object
## but the code is not in this order.
(
## This temp var will taint the global scope (window.*), so be obscure
## The global window._o3E will have {DontDelete} attribute,
## so it is not "delete _o3E"-able.
_o3E=function(s){
// selection sometimes include \v for newline. strip it
//s.replace(RegExp(String.fromCharCode(11),'g'),' ');
## 2. prompt() for expression
## prompt() silently truncates return value length to 49.
## Warn if likely; otherwise, prompt()
## (Note: editing the string in prompt() will change
## document.activeElement to <BODY>)
if(s.length<50||
!confirm('Too long. Eval directly?:'+s)){
// Selection was length<50, or user cancelled
// to edit the selection anyway.
// Truncate to 49 before prompt() does it,
// to show user the real thing
s=prompt('Object expression:',s.slice(0,49));
// [Cancel] will return undefined
}
return s;
}(
## 1. get current text selection, otherwise set default expression
getSelection()+''||
'document.activeElement' //Edit this default as needed
)
)&&
## if user cancelled, control NOTREACHED
function(s,o){
## 4. enumerate and dump the object
s=s.replace(/&/g,'&');
var t=typeof o,
r=Math.floor(Math.random()*1000),
h='<DIV id='+r+'>
<HR>
## removeNode() seems to be nonstandard (MS?), but works
<INPUT type=button value=dismiss onclick="function(n){n.removeNode(n)}(this.parentNode)"> '+
// title on right of [dismiss] button
s+'
<DL style="font-size:xx-small;white-space:pre-wrap;">
',
i,v;
if(t!='object'||o===null){ //typeof null is "object"!
////g(s,[o],0);
// If the result is "undefined", it's likely
// a statement or function with side effect.
// quit immediately.
//if(t=='undefined'){alert(o);return;}
// else it's a value. just alert() it and
// retain current window
//alert(o); return
// So, that's same thing to do
alert(o);return;
}
// enumerate attributes in the object
for(i in o){
// Generate a <DT><DD> for an attribute.
v=o[i],t=typeof v;
h+='<DT>'+(
// object.0 as in Array should be written as object[0]
/^[0-9]/.exec(i)?
// "object[0]"
s+'['+i+']'
:
// "object.attr"
s+'.'+i
)+(t=='function'?'()':'')+
'<DD style="margin-left:2em">'+t+' ';
// we can't use switch-case here, as it uses ===
if(i=='toString'||i=='valueOf'){
v=o[i]();t=typeof v; // resolve toString()
}
if(t=='string'){
h+='"'+v.slice(0,99).replace(/</g,'<')+'"';
if(v.length>99)h+='...'
}
if(t=='number'||t=='boolean'||v===null){
h+=v;
}
h+='\n'; //purely HTML level cosmetics
}//next i
h+='</DL></DIV>\n';
document.write(h);
document.getElementById(r).scrollIntoView();
}(
## 3. eval() in global context
_o3E,eval(_o3E)
)
追加用補助リンク
eval()するかどうか聞かれます。
(prompt()が50文字以上を扱えない対策)
ちょっとしたコードを実行したいとき、
いちいち「アドレス入力」からhttp://を消して
javascript:...を打ち直すのが
めんどくさい場合にも重宝します。
領域選択していない際のデフォルト値は埋め込みなので、 各自で適当に変更してください。 このブックマークレットも960文字くらいあるので、 大規模改造は難しいです。
よくあるjavascript電卓です。が、 数字入力用のボタンもないと タッチペンデバイスでは使いにくくてしょうがないので 追加してあります。 オフラインでも使えます。
javascript:
## Calculator.
##
function bt(v,s,i){
return '<INPUT type=button value="'+v+'" onclick="javascript:'+s.replace(/&"'/g,function(c){return '&#'+c.charCodeAt(0)+';'})+'"'+(i?' id="'+i+'"':'')+'>'
}
document.write('
<TITLE>Calculator</TITLE>
<STYLE>INPUT{font-size:11px;padding:1px 4px;margin:1px 0;}</STYLE>
<SCRIPT>
function $(i){return document.getElementById(i)}
var ud=[]; //undo buffer
</SCRIPT>
<INPUT type=text id=88 value="" align=right>'+
bt('=','$(88).value=function(x){with(Math){var n=eval(x);if(n!=x){ud.push(x);ud.push(n)}return n}}($(88).value)')+
bt('C','function(v){if(v.value){ud.push(v.value);v.value=\'\'}}($(88))')+
bt('undo','function(n){while(ud.length>0&&$(88).value==n){$(88).value=ud.pop()}}($(88).value)')+
'<br>\n'+
function(){
var r='',b='0123456789_.,/*-+',i;
for(;i=b.charAt(0),b.length;b=b.slice(1)){
if(i=='_'){r+='<br>\n';continue;}
r+=bt(i,'$(88).value+=\''+i+"'");
}
return r
}()+
bt('del','function(s){$(88).value=s.substr(0,s.length-1)}($(88).value)')+
'<br>\n'
);
数式はテキストボックス選択で直接編集も可能です。
Mathオブジェクト内で計算するので、
直接数式を打てば sin(PI*2) といった計算も可能です。
こういうガジェットは使うより自分で改造するほうが面白いもんです。 この電卓での凝った機能は[undo]ボタンだけにとどめてあります。
<CANVAS> を使ってマンデルブロー集合を描きます。 ブックマークレットなので、オフラインでも存分に楽しめます。
javascript:
## Draw Mandelbrot set using <canvas>
// w=h=100;p=1; MMX 166MHz: 9sec, DSi XL: 40sec
w=h=102;p=2; //canvas width,height, pixel size
//h/p should be odd, to have axis rendered at center
document.write('
<canvas id=8 width='+w+' height='+h+' style="background:#ddd">canvas</canvas>
<br>
<button onclick="a/=2.5;m.st()">zoom in</button>
<button onclick="a*=2.5;m.st()">zoom out</button>
<script>
## return "#rgb" from iteration count i
c=[]; //i->"#rgb" cache
function g(i){
return c[i]||(c[i]="#"+q(i/=7)+q(i+2)+q(i+4));
// above works. eval order of c[i]=..i/=7.. is
// implementation dependent in C, but
// left-to-right in ECMAScript
}
function q(t){
return "00123456789abcdeff".charAt(Math.cos(t)*8+9);
}
//aperture. smaller value will zoom
a=2.7; //in global to make it available from "onclick"
m=function(d){
//wrap in function to create activation object
var i,
pr=-.8,pi=0, //center coordinate
//a=3.0, //aperture
cv=d.getElementById(8),
c=cv.getContext("2d"),
w='+w+',h='+h+', //canvas size
p='+p+', //pixel size
cr,ci, // Complex c=(cr,ci) of rendering point
r,s, // Complex Z=(r,s)
t,u, // temp r*r, s*s
x,y, // drawing canvas coordinate
f, // #rgb temp
o={}; // object to return
o.st=function(){
c.clearRect(x=0,y=0,w,h);
setTimeout(o.xt);
};
o.xt=function(){
## async implementation of outer loop "for(y=0; y<h; y+=p)"
if(!(y<h)){ //end loop
d.close();
return
}
## -p/2 to calculate at the center of pixel
ci=(h/2-p/2-y)*a/h+pi;
## inner loop of x not async-ized here
for(x=0;x<w;x+=p){
cr=(x-w/2+p/2)*a/w+pr;
## iterate
for(i=99,r=s=0;i>0&&4>(t=r*r)+(u=s*s);i--){
## iterate z = z^2 + c
## until |z|>2, which is proved to diverge to infinite
t=t-u+cr;s=2*r*s+ci;r=t; //standard Mandelbrot set
//t=t-u+cr;s=-Math.abs(2*r*s+ci);r=t; //flaming bird
}
## draw pixel
c.fillStyle=(f=i?g(i):"#000");
//d.write("\\nx"+cr+","+ci+"i"+i+f);
c.fillRect(x,y,p,p);
}
y+=p;
//"this.xt" is invalid since "this" isn't available,
// so use "arguments.callee" to self-refer
//setTimeout(arguments.callee,0); //yield&repeat
setTimeout(o.xt); //yield&repeat
}; //.xt
//set addEventListener to pick up Event struct;
//"onclick=" will not have Event arg
cv.addEventListener("click",function(e){
pr+=(e.clientX-cv.offsetLeft-w/2)*a/w;
pi+=(h/2-e.clientY+cv.offsetTop)*a/h;
o.st();
},!1);
return o;
}(document); //m
m.st();
</script>'
);
追加用補助リンク
CPUの数値演算を酷使するベンチマークにもなります。 MMX 166MHz の Opera と比べると 1/4くらいのスピードなので、 JavaScriptのスピードだけ見ればDSiブラウザはPentium 50MHz程度の性能? 3GHz CPUでは1秒で終わる無駄に重いスクリプトは、 DSiでは1分かかることになる勘定です。 体感でもそんなものですね。
正直、1000文字以内のブックマークレットでここまでやる必要あんのか? という気はしますが。
Operaの癖で、<A href>中のURLの、
"?" 以前にある "\" は
勝手に "/" に置換されてしまう。
ブックマークレットを補助リンク経由で配布する際は、
コードに"\" が含まれないよう細工するか、
コードの冒頭のどこかで ? を使います。
三項演算子(a?b:c)や、'?';を
事前に入れておけば十分。
手打ちするぶんには問題ない。
ブックマークレット補助リンクの href 中が、
「# の後にマルチバイト文字がある」となっていると、
お気に入りに「ページを追加」した時に
# 以前の空白や < > がすべて
return%20c; などと escape() されてしまう。
javascriptとしては当然動かない。
スクリプトによっては引っかかる場合がある。
なので普通の補助リンクは <A href="#javascript:...."> などとしておくわけですが、 当ページでこの方法をとってないのは、クリック後のエラー画面で せめてスクリプトの断片を確認したいから。 エラー画面では # 以降は表示されないので、"#javascript:" とすると 主URLしか表示されず、本当に補助リンクを踏んだのか不安になる。
|が打てないスクリーンキーボードでは "|" (VERTICAL BAR, OR演算子) が 入力できません。 Shift+@ の位置に出ているのは全角の "|" です。 手書きでも出てきません。 半角の "|" をDSi単独で入力する方法は無いかも… バグだと思う。
補助リンクで配る分には問題なく投入できます。
お気に入りの「編集」の手打ちでどうしても使いたい場合は、
三項演算子で代用するか、
ド・モルガンの法則で論理を反転してやります。
例: if( a || b ) → if (a?1:b) if(!(!a && !b))
なお DSi上では | は broken bar に見えます。
DSiブラウザーのブックマークは1000文字くらいの制限があるので、 あまり巨大なブックマークレットは登録できません。 DSブラウザーはもっと大きなブックマークを作れたみたいですが…
正確にいうと、長いURL自体は お気に入り に追加できるが、 アドレスを「編集」するエディタが1000文字以上を扱えない。 補助リンク経由での配布ではどうしても「編集」が必要なので、 この制限はけっこう痛い。
prompt()の49文字制限DSiブラウザーのprompt()の返り値は49文字に制限されています。
表示や入力文字列の編集はもっと余裕がありますが、
返り値は49文字で強制的に切られてしまうので、
javascript:alert(eval(prompt('Expression:','')))
で長いコードを入れると途中で切られてエラーになる(何も起こらない)
ことがあります。
49文字って意外と短いですよ?プログラムコードだと2行くらい。
unescape(escape(...))が元に戻らないescape("\r\nほげ") は %0D%0A%u307B%u3052に変換されますが、
unescape()が%0D%0Aを戻せず止まる。
どうやったらそんなバグ作れるんだ。
.replace(/%0/g,'%u000')とかでむりやりUnicode化(%u000A%u000D)すると
戻せるようになる。
document.activeElementが親を拾う例えば <A href="content.html" target="body"> で別ページを表示すると、 DSiブラウザー内では FRAME か 別タブを開くようになっているのか、 新ページでフォーカスを移動させても document.activeElement では新ページではなく 親ページの <A href> のほうが拾われてしまいます。 別タブになっているかどうかは DSiブラウザー上では全くわかりません。
document.activeElement は元々は Internet Explorer 4の独自拡張ですが、 Mozilla系列にも似たようなバグがあった、らしい、ので、 修正がめんどくさい部類のバグのようです。
DSi側での対処法: 一旦、右下ボタン→「www アドレス入力」→[移動] (編集は不要)で、 FRAME状態を解除する。
onclickに何があるか探索するなど、 DOMノードを順次親に向かって探索しようと素直に
a=document.activeElement;
for(p=a; p; p=p.parentNode){
...
}
とすると、最上位ノード (p.nodeName=="#document")で p.parentNode を
拾う時に問答無用で停止します。ので
for(p=a; p && p.nodeName!='#document'; p=p.parentNode){
...
}
みたいな不細工な停止条件が必要です。
スクリーンショットを撮っているデジカメが 本体内部の赤外線を拾ってるっぽいです。 なので中央が白っぽく写るようです。 まぁデジカメもそんな高級品ではないですが。