diff options
-rw-r--r-- | _libly.js | 10 | ||||
-rw-r--r-- | notifier.js | 185 | ||||
-rw-r--r-- | notifier/observer_growl.js | 60 | ||||
-rw-r--r-- | notifier/subject_hatelabo_bottle.js | 89 |
4 files changed, 245 insertions, 99 deletions
@@ -5,7 +5,7 @@ var PLUGIN_INFO = <description>vimperator plugins library?</description> <description lang="ja">適当なライブラリっぽいものたち。</description> <author mail="suvene@zeromemory.info" homepage="http://zeromemory.sblo.jp/">suVene</author> - <version>0.1.1</version> + <version>0.1.2</version> <minVersion>1.2</minVersion> <maxVersion>2.0pre</maxVersion> <detail><![CDATA[ @@ -150,6 +150,14 @@ lib.$U = {//{{{ } } }, + xmlSerialize: function(xml) { + try { + return (new XMLSerializer()).serializeToString(xml) + .replace(/<[^>]+>/g, function(all) all.toLowerCase()) + .replace(/<!--(?:[^-]|-(?!->))*-->/g, ''); // actually + //.replace(/<!--(?:[^-]|-(?!-))*-->/g, ''); // strictly + } catch (e) { return '' } + } }; //}}} diff --git a/notifier.js b/notifier.js index 126c523..5dcdfe5 100644 --- a/notifier.js +++ b/notifier.js @@ -1,22 +1,112 @@ -/** - * ==VimperatorPlugin== - * @name notifier.js - * @description notice of change framework. - * @description-ja 変更通知フレームワーク。 - * @author suVene suvene@zeromemory.info - * @version 0.1.0 - * @minVersion 2.0pre - * @maxVersion 2.0pre - * Last Change: 07-Dec-2008. - * ==/VimperatorPlugin== - * - * HEAD COMMENT {{{ - * }}} - */ +// PLUGIN_INFO//{{{ +var PLUGIN_INFO = +<VimperatorPlugin> + <name>{name}</name> + <description>notice of change framework.</description> + <description lang="ja">変更通知フレームワーク。</description> + <author mail="suvene@zeromemory.info" homepage="http://zeromemory.sblo.jp/">suVene</author> + <version>0.1.0</version> + <minVersion>2.0pre</minVersion> + <maxVersion>2.0pre</maxVersion> + <detail><![CDATA[ +== Command == +:notifierstart: + 変更通知をスタートします。 +:notifierrestart: + 変更通知をリスタートします。 +:notifierstop: + 変更通知をストップします。 + +== Observer == +* 通知された変更を扱うオブジェクトを定義します。 +Subject からの Message オブジェクトを解析し、何らかの動作を行います。 +Observer ⇒ Subject への依存は高くて OK です。 + +* 命名規約 +prefix に 'observer_' を付け、'rumtimepath/notifier' の下にインストールして下さい。 +ex.)'${rumtimepath}/notifier/observer_XXX.js' + +* 登録方法 +liberator.plugins.notifier.observer.register(baseClass, extendsMethods) +baseClass: + 基底クラスとなります。現在以下の基底クラスが存在します。 + - liberator.plugins.notifier.Observer +extendsMethosd: + 基底クラスの拡張となるメソッドをハッシュ形式で渡します。 + 実装するメソッドは基底クラスのルールに従って下さい。 + +* 基底クラスの説明 +** librator.plugins.notifier.Observer +Observerの基本クラスです。 +initialize(): + 必要の無い場合、実装しなくても OK です。 + インスタンス生成時に1度だけフレームワークによって呼び出されます。 + 初期化処理など必要な処理を実装して下さい。 +update(liberator.plugins.notifier.Message): + 必ず実装して下さい。 + Subject からの変更通知がなされた場合、引数 Message と共にフレームワークより呼び出されます。 + +== Subject == +* 変更を検知し Observer に通知します。 +原則、observer との依存を少なくして下さい。 +(Message の解析の役割は Observer にある) + +* 命名規約 +prefix に 'subject_' を付け、'rumtimepath/notifier' の下にインストールして下さい。 +ex.)'${rumtimepath}/notifier/subject_XXX.js' + +* 登録方法 +liberator.plugins.notifier.subject.register(baseClass, extendsMethods) +baseClass: + 基底クラスとなります。現在以下の基底クラスが存在します。 + - liberator.plugins.notifier.Subject + - liberator.plugins.notifier.SubjectHttp +extendsMethosd: + 基底クラスへの拡張をハッシュ形式で渡します。 + +* 基底クラスの説明 +** librator.plugins.notifier.Subject +Subject の基本クラスです。 +interval: + 秒で変更チェックするインターバルを指定します。デフォルトは 60 です。 +initialize(): + 必要の無い場合、実装しなくても OK です。 + インスタンス生成時に1度だけフレームワークによって呼び出されます。 + 初期化処理など必要な処理を実装して下さい。 +check(): + 必ず実装して下さい。 + 指定したインターバルごとにフレームワークによって呼び出されます。 + 変更を検知した場合、liberator.plugins.notifier.Message のインスタンスを引数に + this.notify(message) を呼び出してください。 + +** librator.plugins.notifier.SubjectHttp +Httpを利用した変更検知の基底クラスです。 +リクエスト内容をキャッシュします。 +options{}: + url: + URL を指定します。 + headers{}: + リクエストに header が必要な場合ハッシュで指定します。 + extra{}: + リクエストのオプションです。ハッシュで指定します。 + 以下の key が有効です。 + asynchronose (false), encoding(default utf-8) +parse(liberator.pluginsnotifier.Request): + 必ず実装して下さい。 + リクエストを解析した結果を返却して下さい。 +diff(cache, parsed): + 必ず実装して下さい。 + this.parse() による解析結果と、そのキャッシュとの差分を抽出して返却して下さい。 +buildMessages(diff): + 必ず実装して下さい。 + this.diff() により抽出されたオブジェクトを元に、liberator.plugins.notifier.Message のインスタンス、 + または、その配列を返却して下さい。 + ]]></detail> +</VimperatorPlugin>; +//}}} (function() { -io.sourceFromRuntimePath(['libly.js']); if (!liberator.plugins.libly) { - liberator.log('notifier: needs libly.js'); + liberator.log('notifier: needs _libly.js'); return; } @@ -37,11 +127,10 @@ function bootstrap() { this.initialize.apply(this, arguments); }; Loader.prototype = { - initialize: function(name, registerHook) { + initialize: function(name) { liberator.plugins.notifier[name] = this; this.name = name; this.plugins = []; - this.registerHook = registerHook; this.load(name); }, load: function(name) { @@ -56,8 +145,8 @@ function bootstrap() { }); }); }, - register: function(plugin) { - this.plugins.push(this.registerHook(plugin)); + register: function(baseClass, pluginExtends) { + this.plugins.push(new baseClass(pluginExtends)); }, unregister: function(plugin) { var ret = []; @@ -105,8 +194,7 @@ function bootstrap() { __initialize__: function(args) { this.isActive = false; this.observers = []; - this.interval = 0; - //if (this.interval < 60) this.interval = 60; + this.interval = 60; this.__nextTime = new Date(); $U.extend(this, args); if (typeof this.initialize == 'function') this.initialize(); @@ -128,6 +216,50 @@ function bootstrap() { check: function() { throw 'needs override.' } };//}}} + var SubjectHttp = Subject;//{{{ + $U.extend(SubjectHttp.prototype, { + initialize: function() { + this.initialized = false; + this.count = 0; + this.cache; + + var req = new libly.Request( + this.options.url, + this.options.headers, + this.options.extra + ); + req.addEventListener('onSuccess', $U.bind(this, function(res) { + if (typeof this.parse == 'function') this.cache = this.parse(res); + if (this.cache) + this.initialized = true; + })); + req.get(); + }, + check: function() { + if (!this.initialized) return; + + this.count++; + var req = new libly.Request( + this.options.url, + this.options.headers, + this.options.extra + ); + req.addEventListener('onSuccess', $U.bind(this, function(res) { + var parsed, diff; + if (typeof this.parse == 'function') parsed = this.parse(res); + if (parsed && typeof this.diff == 'function') diff = this.diff(this.cache, parsed); + if (diff && (typeof diff.length != 'undefined' && diff.length > 0)) { + if (typeof this.buildMessages == 'function') { + let messages = this.buildMessages([].concat(diff)); + [].concat(messages).forEach($U.bind(this, function(m) this.notify(m))); + } + this.cache = parsed; + } + })); + req.get(); + } + });//}}} + var Notifier = function() {//{{{ this.initialize.apply(this, arguments); }; @@ -143,7 +275,7 @@ function bootstrap() { setup: function() {//{{{ if (this.isBusy) { - logger.log('bussy.' + this.id); + logger.log('busy.' + this.id); return; } @@ -161,6 +293,9 @@ function bootstrap() { ); liberator.plugins.notifier.libly = libly; + liberator.plugins.notifier.Observer = Observer; + liberator.plugins.notifier.Subject = Subject; + liberator.plugins.notifier.SubjectHttp = SubjectHttp; liberator.plugins.notifier.Message = Message; this.observers = new Loader('observer', function(args) new Observer(args)); @@ -204,7 +339,7 @@ function bootstrap() { s.isActive = false; s.__nextTime = new Date(s.__nextTime.getTime() + s.interval * 1000); if (s.__nextTime < now) s.__nextTime = now; - }, 10); + }, 1000); } }); liberator.sleep(3 * 1000); diff --git a/notifier/observer_growl.js b/notifier/observer_growl.js index e8d61e5..0a3d1d3 100644 --- a/notifier/observer_growl.js +++ b/notifier/observer_growl.js @@ -1,17 +1,17 @@ -/** - * notifier.js plugin observer - * @name observer_growl.js - * @description growl when notified. - * @description-ja Growl風通知。 - * @author suVene suvene@zeromemory.info - * @version 0.1.0 - * Last Change: 07-Dec-2008. - * - * use jQuery - * http://jquery.com/ - * use JGrowl - * http://stanlemon.net/projects/jgrowl.html - */ +// PLUGIN_INFO//{{{ +var PLUGIN_INFO = +<VimperatorPlugin> + <name>{name}</name> + <description>notification from the subjects is notified to you by the Growl style.</description> + <description lang="ja">Growl風通知。</description> + <author mail="suvene@zeromemory.info" homepage="http://zeromemory.sblo.jp/">suVene</author> + <version>0.1.0</version> + <minVersion>2.0pre</minVersion> + <maxVersion>2.0pre</maxVersion> + <detail><![CDATA[ + ]]></detail> +</VimperatorPlugin>; +//}}} (function() { var notifier = liberator.plugins.notifier; @@ -28,22 +28,23 @@ Growl.prototype = { defaults: { life: 5000 }, - initialize: function(dom, container) { + initialize: function(dom, container, options) { this.dom = dom; this.container = container; this.created = new Date(); - this.life = this.defaults.life; + this.options = $U.extend(this.defaults, (options || {})); + this.life = this.options.life; dom.childNodes[0].addEventListener("click", $U.bind(this, this.remove), false); }, remove: function() { + // TODO: animation!!!! this.container.removeChild(this.dom); }, }//}}} -notifier.observer.register({ +notifier.observer.register(notifier.Observer, { initialize: function () { - logger.log('initialize'); this.count = 1; io.getRuntimeDirectories('').forEach(function(dir) { @@ -59,7 +60,6 @@ notifier.observer.register({ }); }, update: function(message) { - logger.log('update:' + this.count); var doc = window.content.document; var container = doc.getElementById("observer_growl"); @@ -68,8 +68,9 @@ notifier.observer.register({ container = doc.getElementById("observer_growl"); } - this.createPopup(doc, message, container); - container.appendChild(this.createPopup(doc, message, container)); + var notification = this.createPopup(message, doc, container); + // TODO: animation!!! + container.appendChild(notification); if (container.childNodes.length == 1) { let interval = setInterval($U.bind(this, this.checkStatus), 1000); @@ -78,17 +79,16 @@ notifier.observer.register({ this.count++; }, - createPopup: function(doc, message, nodes) { + createPopup: function(message, doc, nodes) { var dom; var html = - <div class="observer_growl_notification" style="display: block;"> - <div class="close">×</div> - <div class="header">{util.escapeHTML(this.count + ': ' + message.title)}</div> - <div class="message">{util.escapeHTML(message.message)}</div> - </div>; + <div class="observer_growl_notification" style="display: block;"> + <div class="close">×</div> + <div class="header">{new XMLList(this.count + ': ' + message.title)}</div> + <div class="message">{new XMLList(message.message || '')}</div> + </div>; dom = util.xmlToDom(html, doc, nodes); - dom.__data__ = new Growl(dom, nodes); - + dom.__data__ = new Growl(dom, nodes, message.options.growl); return dom; }, checkStatus: function() { @@ -106,7 +106,7 @@ notifier.observer.register({ removeNodes.push(item); } } - removeNodes.forEach(function(n) container.removeChild(n)); + removeNodes.forEach(function(element) element.__data__.remove()); if (container.childNodes.length == 0) clearInterval(container.__interval__); diff --git a/notifier/subject_hatelabo_bottle.js b/notifier/subject_hatelabo_bottle.js index 9c4914d..6c4a330 100644 --- a/notifier/subject_hatelabo_bottle.js +++ b/notifier/subject_hatelabo_bottle.js @@ -1,12 +1,17 @@ -/** - * notifier.js plugin subject - * @name subject_hatena_bottle.js - * @description notify if hatena bottle changed. - * @description-ja はてなボトルの変更通知。 - * @author suVene suvene@zeromemory.info - * @version 0.1.0 - * Last Change: 08-Dec-2008. - */ +// PLUGIN_INFO//{{{ +var PLUGIN_INFO = +<VimperatorPlugin> + <name>{name}</name> + <description>notifies if hatena bottle was changed.</description> + <description lang="ja">はてなボトルの変更通知。</description> + <author mail="suvene@zeromemory.info" homepage="http://zeromemory.sblo.jp/">suVene</author> + <version>0.1.0</version> + <minVersion>2.0pre</minVersion> + <maxVersion>2.0pre</maxVersion> + <detail><![CDATA[ + ]]></detail> +</VimperatorPlugin>; +//}}} (function() { var notifier = liberator.plugins.notifier; @@ -17,22 +22,14 @@ var $U = libly.$U; var logger = $U.getLogger('subject_hatelabo_bottle'); var URL = 'http://bottle.hatelabo.jp'; +//var URL = 'http://localhost/index.html?a'; -notifier.subject.register({ - interval: 30, - initialize: function() { - this.count = 0; - this.initialized = false; - this.cache; - - var req = new libly.Request(URL); - req.addEventListener('onSuccess', $U.bind(this, function(res) { - logger.log('initialized'); - this.cache = this.parse(res); - if (this.cache) - this.initialized = true; - })); - req.get(); +notifier.subject.register(notifier.SubjectHttp, { + interval: 40, + options: { + url: URL, + headers: null, + extra: null }, parse: function(res) { @@ -44,31 +41,37 @@ notifier.subject.register({ if (!dom) return ret; ret = []; - for (let i = 0, len < dom.childNodes.length; i < len; i++) { + for (let i = 0, len = dom.childNodes.length; i < len; i++) { ret.push(dom.childNodes[i]); } return ret; }, - check: function() { - - if (!this.initialized) return; - - this.count++; - logger.log('check'); - var req = new libly.Request(URL); - req.addEventListener('onSuccess', $U.bind(this, function(res) { - var text = res.responseText; - logger.log('success!! '); - var message = new notifier.Message('TEST', text); - this.notify(message); + diff: function(cache, parsed) { + var ret = []; + parsed.forEach(function(element) { + if (!cache.some(function(c) { if (c.toString() == element.toString()) return true })) + ret.push(element); + }); - if (this.count == 5) { - notifier.subject.unregister(this); - this.count = 0; - } - })); - req.get(); + return ret; + var text = (new XMLSerializer()).serializeToString(parsed[0]) + .replace(/<[^>]+>/g, function(all) all.toLowerCase()) + .replace(/<!--(?:[^-]|-(?!->))*-->/g, ''); // actually + return text; + }, + buildMessages: function(diff) { + var ret = []; + diff.forEach(function(d) { + ret.push( + new notifier.Message('Hatelab bottle', $U.xmlSerialize(d), { + growl: { + life: 7000 + } + }) + ); + }); + return ret; } }); |