PageRenderTime 76ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 1ms

/src/lib/50-HatenaStar.js

https://github.com/Cside/hatena-bookmark-googlechrome-extension
JavaScript | 3752 lines | 3696 code | 40 blank | 16 comment | 112 complexity | 9131b78df36628980be37af16fa1f1eb MD5 | raw file
  1. /* Ten */
  2. if (typeof(Ten) == 'undefined') {
  3. Ten = {};
  4. Ten.NAME = 'Ten';
  5. Ten.VERSION = 0.28;
  6. /* Ten.Class */
  7. Ten.Class = function(klass, prototype) {
  8. if (klass && klass.initialize) {
  9. var c = klass.initialize;
  10. } else if(klass && klass.base) {
  11. var c = function() { return klass.base[0].apply(this, arguments) };
  12. } else {
  13. var c = function() {};
  14. }
  15. c.prototype = prototype || {};
  16. c.prototype.constructor = c;
  17. Ten.Class.inherit(c, klass);
  18. if (klass && klass.base) {
  19. for (var i = 0; i < klass.base.length; i++) {
  20. var parent = klass.base[i];
  21. if (i == 0) {
  22. c.SUPER = parent;
  23. c.prototype.SUPER = parent.prototype;
  24. }
  25. Ten.Class.inherit(c, parent);
  26. Ten.Class.inherit(c.prototype, parent.prototype);
  27. }
  28. }
  29. return c;
  30. }
  31. Ten.Class.inherit = function(child,parent) {
  32. for (var prop in parent) {
  33. if (typeof(child[prop]) != 'undefined' || prop == 'initialize') continue;
  34. child[prop] = parent[prop];
  35. }
  36. }
  37. /*
  38. // Basic Ten Classes
  39. */
  40. /* Ten.Function */
  41. Ten.Function = {
  42. bind: function(f,o) {
  43. return function() {
  44. return f.apply(o, arguments);
  45. }
  46. },
  47. method: function(obj, method) {
  48. return Ten.Function.bind(obj[method], obj);
  49. }
  50. };
  51. /* Ten.Array */
  52. Ten.Array = {
  53. flatten: function(arr) {
  54. var ret = [];
  55. (function(arr) {
  56. for (var i = 0; i < arr.length; i++) {
  57. var o = arr[i];
  58. if (Ten.Array.isArray(o)) {
  59. arguments.callee(o);
  60. } else {
  61. ret.push(o);
  62. }
  63. }
  64. })(arr);
  65. return ret;
  66. },
  67. dup: function(arr) {
  68. var res = [];
  69. for (var i = 0; i < arr.length; i++) {
  70. res[i] = arr[i];
  71. }
  72. return res;
  73. },
  74. indexOf: function(arr,e) {
  75. for (var i = 0; i < arr.length; i++) {
  76. if (arr[i] == e) return i;
  77. }
  78. return -1;
  79. },
  80. isArray: function(o) {
  81. return (o instanceof Array ||
  82. (o && typeof(o.length) === 'number' && typeof(o) != 'string' && !o.nodeType));
  83. }
  84. };
  85. /* Ten.JSONP */
  86. Ten.JSONP = new Ten.Class({
  87. initialize: function(uri,obj,method) {
  88. if (Ten.JSONP.Callbacks.length) {
  89. setTimeout(function() {new Ten.JSONP(uri,obj,method)}, 500);
  90. return;
  91. }
  92. var del = uri.match(/\?/) ? '&' : '?';
  93. uri += del + 'callback=Ten.JSONP.callback';
  94. if (!uri.match(/timestamp=/)) {
  95. uri += '&' + encodeURI(new Date());
  96. }
  97. if (typeof(obj) == 'function' && typeof(method) == 'undefined') {
  98. obj = {callback: obj};
  99. method = 'callback';
  100. }
  101. if (obj && method) Ten.JSONP.addCallback(obj,method);
  102. this.script = document.createElement('script');
  103. this.script.src = uri;
  104. this.script.type = 'text/javascript';
  105. document.getElementsByTagName('head')[0].appendChild(this.script);
  106. },
  107. addCallback: function(obj,method) {
  108. Ten.JSONP.Callbacks.push({object: obj, method: method});
  109. },
  110. callback: function(args) {
  111. // alert('callback called');
  112. var cbs = Ten.JSONP.Callbacks;
  113. for (var i = 0; i < cbs.length; i++) {
  114. var cb = cbs[i];
  115. cb.object[cb.method].call(cb.object, args);
  116. }
  117. Ten.JSONP.Callbacks = [];
  118. },
  119. MaxBytes: 1800,
  120. Callbacks: []
  121. });
  122. /* Ten.XHR */
  123. Ten.XHR = new Ten.Class({
  124. initialize: function(uri,opts,obj,callPropertyName) {
  125. Ten.EventDispatcher.implementEventDispatcher(this);
  126. this.method = 'GET';
  127. if (!uri) return;
  128. if (!opts) opts = {};
  129. if (opts.method)
  130. this.method = opts.method;
  131. var self = this;
  132. this.addEventListener('complete', function() {
  133. if (!obj) return;
  134. if (typeof(obj) == 'function' && typeof(callPropertyName) == 'undefined') {
  135. obj.call(obj, self.request);
  136. } else {
  137. obj[callPropertyName].call(obj, self.request);
  138. }
  139. });
  140. this.load(uri, opts.data);
  141. },
  142. getXMLHttpRequest: function() {
  143. var xhr;
  144. var tryThese = [
  145. function () { return new XMLHttpRequest(); },
  146. function () { return new ActiveXObject('Msxml2.XMLHTTP'); },
  147. function () { return new ActiveXObject('Microsoft.XMLHTTP'); },
  148. function () { return new ActiveXObject('Msxml2.XMLHTTP.4.0'); },
  149. ];
  150. for (var i = 0; i < tryThese.length; i++) {
  151. var func = tryThese[i];
  152. try {
  153. xhr = func;
  154. return func();
  155. } catch (e) {
  156. //alert(e);
  157. }
  158. }
  159. return xhr;
  160. },
  161. makePostData: function(data) {
  162. var pairs = [];
  163. var regexp = /%20/g;
  164. for (var k in data) {
  165. if (!data[k]) continue;
  166. var v = data[k].toString();
  167. var pair = encodeURIComponent(k).replace(regexp,'+') + '=' +
  168. encodeURIComponent(v).replace(regexp,'+');
  169. pairs.push(pair);
  170. }
  171. return pairs.join('&');
  172. }
  173. },{
  174. load: function(url, params) {
  175. var req = Ten.XHR.getXMLHttpRequest();
  176. this.request = req;
  177. var self = this;
  178. req.onreadystatechange = function() {
  179. self.stateChangeHandler.call(self, req);
  180. };
  181. params = params ? Ten.XHR.makePostData(params) : null;
  182. req.open(this.method, url, true);
  183. if (this.method == 'POST')
  184. req.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
  185. req.send(params);
  186. },
  187. stateChangeHandler: function(req) {
  188. this.dispatchEvent('state_change');
  189. if (req.readyState == 4) {
  190. this.dispatchEvent('ready', req.status.toString());
  191. if (req.status >= 200 && req.status < 300) {
  192. this.dispatchEvent('complete', req);
  193. } else {
  194. this.dispatchEvent('error', req);
  195. }
  196. }
  197. }
  198. });
  199. /* Ten.Observer */
  200. Ten.Observer = new Ten.Class({
  201. initialize: function(element,event,obj,method) {
  202. var func = obj;
  203. if (typeof(method) == 'string') {
  204. func = obj[method];
  205. }
  206. this.element = element;
  207. this.event = event;
  208. this.listener = function(event) {
  209. return func.call(obj, new Ten.Event(event || window.event));
  210. }
  211. this.start();
  212. }
  213. },{
  214. stop: function() {
  215. if (this.element.removeEventListener) {
  216. this.element.removeEventListener(this.event,this.listener,false);
  217. } else if (this.element.detachEvent) {
  218. this.element.detachEvent(this.event,this.listener);
  219. }
  220. },
  221. start: function() {
  222. if (this.element.addEventListener) {
  223. if (this.event.indexOf('on') == 0) {
  224. this.event = this.event.substr(2);
  225. }
  226. this.element.addEventListener(this.event, this.listener, false);
  227. } else if (this.element.attachEvent) {
  228. this.element.attachEvent(this.event, this.listener);
  229. }
  230. }
  231. });
  232. /* Ten.Event */
  233. Ten.Event = new Ten.Class({
  234. initialize: function(e) {
  235. this.event = e;
  236. if (e) {
  237. this.target = e.target || e.srcElement;
  238. this.shiftKey = e.shiftKey;
  239. this.ctrlKey = e.ctrlKey;
  240. this.altKey = e.altKey;
  241. }
  242. },
  243. KeyMap: {
  244. 8:"backspace", 9:"tab", 13:"enter", 19:"pause", 27:"escape", 32:"space",
  245. 33:"pageup", 34:"pagedown", 35:"end", 36:"home", 37:"left", 38:"up",
  246. 39:"right", 40:"down", 44:"printscreen", 45:"insert", 46:"delete",
  247. 112:"f1", 113:"f2", 114:"f3", 115:"f4", 116:"f5", 117:"f6", 118:"f7",
  248. 119:"f8", 120:"f9", 121:"f10", 122:"f11", 123:"f12",
  249. 144:"numlock", 145:"scrolllock"
  250. }
  251. },{
  252. mousePosition: function() {
  253. if (!this.event.clientX) return null;
  254. return Ten.Geometry.getMousePosition(this.event);
  255. },
  256. isKey: function(name) {
  257. var ecode = this.event.keyCode;
  258. if (!ecode) return false;
  259. var ename = Ten.Event.KeyMap[ecode];
  260. if (!ename) return false;
  261. return (ename == name);
  262. },
  263. targetIsFormElements: function() {
  264. if (!this.target) return false;
  265. var T = (this.target.tagName || '').toUpperCase();
  266. return (T == 'INPUT' || T == 'SELECT' || T == 'OPTION' ||
  267. T == 'BUTTON' || T == 'TEXTAREA');
  268. },
  269. stop: function() {
  270. var e = this.event;
  271. if (e.stopPropagation) {
  272. e.stopPropagation();
  273. e.preventDefault();
  274. } else {
  275. e.cancelBubble = true;
  276. e.returnValue = false;
  277. }
  278. }
  279. });
  280. /* Ten.EventDispatcher */
  281. Ten.EventDispatcher = new Ten.Class({
  282. initialize: function() {
  283. this._eventListeners = {};
  284. },
  285. implementEventDispatcher: function(obj) {
  286. Ten.Class.inherit(obj, Ten.EventDispatcher.prototype);
  287. obj._eventListeners = {};
  288. }
  289. }, {
  290. hasEventListener: function(type) {
  291. return (this._eventListeners[type] instanceof Array && this._eventListeners[type].length > 0);
  292. },
  293. addEventListener: function(type, listener) {
  294. if (!this.hasEventListener(type)) {
  295. this._eventListeners[type] = [];
  296. }
  297. var listeners = this._eventListeners[type];
  298. for (var i = 0; i < listeners.length; i++) {
  299. if (listeners[i] == listener) {
  300. return;
  301. }
  302. }
  303. listeners.push(listener);
  304. },
  305. removeEventListener: function(type, listener) {
  306. if (this.hasEventListener(type)) {
  307. var listeners = this._eventListeners[type];
  308. for (var i = 0; i < listeners.length; i++) {
  309. if (listeners[i] == listener) {
  310. listeners.splice(i, 1);
  311. return;
  312. }
  313. }
  314. }
  315. },
  316. dispatchEvent: function(type, opt) {
  317. if (!this.hasEventListener(type)) return false;
  318. var listeners = this._eventListeners[type];
  319. for (var i = 0; i < listeners.length; i++) {
  320. listeners[i].call(this, opt);
  321. }
  322. return true; // preventDefault is not implemented
  323. }
  324. });
  325. /* Ten.DOM */
  326. Ten.DOM = new Ten.Class({
  327. createElementFromString : function (str, opts) {
  328. if (!opts) opts = { data: {} };
  329. if (!opts.data) opts.data = { };
  330. var t, cur = opts.parent || document.createDocumentFragment(), root, stack = [cur];
  331. while (str.length) {
  332. if (str.indexOf("<") == 0) {
  333. if ((t = str.match(/^\s*<(\/?[^\s>\/]+)([^>]+?)?(\/)?>/))) {
  334. var tag = t[1], attrs = t[2], isempty = !!t[3];
  335. if (tag.indexOf("/") == -1) {
  336. child = document.createElement(tag);
  337. if (attrs) attrs.replace(/([a-z]+)=(?:'([^']+)'|"([^"]+)")/gi,
  338. function (m, name, v1, v2) {
  339. var v = text(v1 || v2);
  340. if (name == "class") root && (root[v] = child), child.className = v;
  341. child.setAttribute(name, v);
  342. }
  343. );
  344. cur.appendChild(root ? child : (root = child));
  345. if (!isempty) {
  346. stack.push(cur);
  347. cur = child;
  348. }
  349. } else cur = stack.pop();
  350. } else throw("Parse Error: " + str);
  351. } else {
  352. if ((t = str.match(/^([^<]+)/))) cur.appendChild(document.createTextNode(text(t[0])));
  353. }
  354. str = str.substring(t[0].length);
  355. }
  356. function text (str) {
  357. return str
  358. .replace(/&(#(x)?)?([^;]+);/g, function (_, isNumRef, isHex, ref) {
  359. return isNumRef ? String.fromCharCode(parseInt(ref, isHex ? 16 : 10)):
  360. {"lt":"<","gt":"<","amp":"&"}[ref];
  361. })
  362. .replace(/#\{([^}]+)\}/g, function (_, name) {
  363. return (typeof(opts.data[name]) == "undefined") ? _ : opts.data[name];
  364. });
  365. }
  366. return root;
  367. },
  368. getElementsByTagAndClassName: function(tagName, className, parent) {
  369. if (typeof(parent) == 'undefined') parent = document;
  370. if (!tagName) return Ten.DOM.getElementsByClassName(className, parent);
  371. var children = parent.getElementsByTagName(tagName);
  372. if (className) {
  373. var elements = [];
  374. for (var i = 0; i < children.length; i++) {
  375. var child = children[i];
  376. if (Ten.DOM.hasClassName(child, className)) {
  377. elements.push(child);
  378. }
  379. }
  380. return elements;
  381. } else {
  382. return children;
  383. }
  384. },
  385. getElementsByClassName: function(className, parent) {
  386. if (typeof(parent) == 'undefined') parent = document;
  387. var ret = [];
  388. if (parent.getElementsByClassName) {
  389. var nodes = parent.getElementsByClassName(className);
  390. for (var i = 0 , len = nodes.length ; i < len ; i++ ) ret.push(nodes.item(i));
  391. return ret;
  392. } else {
  393. if (!className) return ret;
  394. (function(parent) {
  395. var elems = parent.childNodes;
  396. for (var i = 0; i < elems.length; i++) {
  397. var e = elems[i];
  398. if (Ten.DOM.hasClassName(e, className)) {
  399. ret.push(e);
  400. }
  401. arguments.callee(e);
  402. }
  403. })(parent);
  404. ret = Ten.Array.flatten(ret);
  405. return ret;
  406. }
  407. },
  408. hasClassName: function(element, className) {
  409. if (!element || !className) return false;
  410. var cname = element.className;
  411. if (!cname) return false;
  412. cname = ' ' + cname.toLowerCase() + ' ';
  413. className = ' ' + className.toLowerCase() + ' ';
  414. return (cname.indexOf(className) != -1);
  415. },
  416. addClassName: function(element, className) {
  417. if (Ten.DOM.hasClassName(element, className)) return;
  418. var c = element.className || '';
  419. c = c.length ? c + " " + className : className;
  420. element.className = c;
  421. },
  422. removeClassName: function(element, className) {
  423. if (!Ten.DOM.hasClassName(element, className)) return;
  424. var c = element.className;
  425. var classes = c.split(/\s+/);
  426. for (var i = 0; i < classes.length; i++) {
  427. if (classes[i] == className) {
  428. classes.splice(i,1);
  429. break;
  430. }
  431. }
  432. element.className = classes.join(' ');
  433. },
  434. removeEmptyTextNodes: function(element) {
  435. var nodes = element.childNodes;
  436. for (var i = 0; i < nodes.length; i++) {
  437. var node = nodes[i];
  438. if (node.nodeType == 3 && !/\S/.test(node.nodeValue)) {
  439. node.parentNode.removeChild(node);
  440. }
  441. }
  442. },
  443. nextElement: function(elem) {
  444. do {
  445. elem = elem.nextSibling;
  446. } while (elem && elem.nodeType != 1);
  447. return elem;
  448. },
  449. prevElement: function(elem) {
  450. do {
  451. elem = elem.previousSibling;
  452. } while (elem && elem.nodeType != 1);
  453. return elem;
  454. },
  455. nextSiblingInSource: function(elem) {
  456. if (elem.childNodes && elem.childNodes.length) {
  457. return elem.childNodes[0];
  458. } else if (elem.nextSibling) {
  459. return elem.nextSibling;
  460. } else if (elem.parentNode && elem.parentNode.nextSibling) {
  461. return elem.parentNode.nextSibling;
  462. }
  463. return null;
  464. },
  465. insertBefore: function(node, ref) {
  466. ref.parentNode.insertBefore(node, ref);
  467. },
  468. insertAfter: function(node, ref) {
  469. if (ref.nextSibling) {
  470. ref.parentNode.insertBefore(node, ref.nextSibling);
  471. } else {
  472. ref.parentNode.appendChild(node);
  473. }
  474. },
  475. unshiftChild: function(elem, child) {
  476. if (elem.firstChild) {
  477. elem.insertBefore(child, elem.firstChild);
  478. } else {
  479. elem.appendChild(child);
  480. }
  481. },
  482. replaceNode: function(newNode, oldNode) {
  483. var parent = oldNode.parentNode;
  484. if (newNode && parent && parent.nodeType == 1) {
  485. parent.insertBefore(newNode, oldNode);
  486. parent.removeChild(oldNode);
  487. }
  488. },
  489. removeElement: function(elem) {
  490. if (!elem.parentNode) return;
  491. elem.parentNode.removeChild(elem);
  492. },
  493. removeAllChildren: function(node) {
  494. while (node.firstChild)
  495. node.removeChild(node.firstChild);
  496. },
  497. scrapeText: function(node) {
  498. if (typeof node.textContent == 'string') return node.textContent;
  499. if (typeof node.innerText == 'string') return node.innerText;
  500. var rval = [];
  501. (function (node) {
  502. var cn = node.childNodes;
  503. if (cn) {
  504. for (var i = 0; i < cn.length; i++) {
  505. arguments.callee.call(this, cn[i]);
  506. }
  507. }
  508. var nodeValue = node.nodeValue;
  509. if (typeof(nodeValue) == 'string') {
  510. rval.push(nodeValue);
  511. }
  512. })(node);
  513. return rval.join('');
  514. },
  515. getSelectedText: function() {
  516. if (window.getSelection)
  517. return '' + (window.getSelection() || '');
  518. else if (document.getSelection)
  519. return document.getSelection();
  520. else if (document.selection)
  521. return document.selection.createRange().text;
  522. else
  523. return '';
  524. },
  525. show: function(elem) {
  526. elem.style.display = 'block';
  527. },
  528. hide: function(elem) {
  529. elem.style.display = 'none';
  530. },
  531. addObserver: function() {
  532. var c = Ten.DOM;
  533. if (c.observer || c.loaded) return;
  534. c.observer = new Ten.Observer(window,'onload',c,'finishLoad');
  535. var ua = navigator.userAgent.toUpperCase();
  536. if (window.opera || ua.indexOf('FIREFOX') >= 0) {
  537. new Ten.Observer(window,'DOMContentLoaded',c,'finishLoad');
  538. } else if ((ua.indexOf('MSIE') >= 0 || ua.toLowerCase().indexOf('webkit') >= 0) && window == top) {
  539. var i = 0;
  540. (function() {
  541. if (i++ > 10000) return null;
  542. try {
  543. if (document.readyState != 'loaded' &&
  544. document.readyState != 'complete') {
  545. document.documentElement.doScroll('left');
  546. }
  547. } catch(error) {
  548. return setTimeout(arguments.callee, 13);
  549. }
  550. return c.finishLoad();
  551. })();
  552. }
  553. },
  554. finishLoad: function() {
  555. var c = Ten.DOM;
  556. if (!c.loaded) {
  557. c.dispatchEvent('DOMContentLoaded');
  558. c.dispatchEvent('onload'); // for backward compatibility
  559. c.loaded = true;
  560. c.observer.stop();
  561. c.observer = null;
  562. }
  563. },
  564. observer: null,
  565. loaded: false
  566. });
  567. Ten.EventDispatcher.implementEventDispatcher(Ten.DOM);
  568. Ten.DOM.addObserver();
  569. /* Ten.Element */
  570. Ten.Element = new Ten.Class({
  571. initialize: function(tagName, attributes) {
  572. var elem = document.createElement(tagName);
  573. for (var a in attributes) {
  574. if (a == 'style') {
  575. Ten.Style.applyStyle(elem, attributes[a])
  576. } else if (a == 'value' && tagName.toLowerCase() == 'input') {
  577. elem.setAttribute('value', attributes[a]);
  578. } else if (a.indexOf('on') == 0) {
  579. new Ten.Observer(elem, a, attributes[a]);
  580. } else {
  581. elem[a] = attributes[a];
  582. }
  583. }
  584. var children = Array.prototype.slice.call(arguments, 2);
  585. for (var i = 0; i < children.length; i++) {
  586. var child = children[i];
  587. if (typeof child == 'string')
  588. child = document.createTextNode(child);
  589. if (!child)
  590. continue;
  591. elem.appendChild(child);
  592. }
  593. Ten.Element.dispatchEvent('create',elem);
  594. return elem;
  595. }
  596. });
  597. Ten.EventDispatcher.implementEventDispatcher(Ten.Element);
  598. /* Ten.Cookie */
  599. Ten.Cookie = new Ten.Class({
  600. initialize: function(string) {
  601. this.cookies = this.constructor.parse(string);
  602. },
  603. parse: function(string) {
  604. var cookies = { };
  605. var segments = (string || document.cookie).split(/;\s*/);
  606. while (segments.length) {
  607. try {
  608. var segment = segments.shift().replace(/^\s*|\s*$/g, '');
  609. if (!segment.match(/^([^=]*)=(.*)$/))
  610. continue;
  611. var key = RegExp.$1, value = RegExp.$2;
  612. if (value.indexOf('&') != -1) {
  613. value = value.split(/&/);
  614. for (var i = 0; i < value.length; i++)
  615. value[i] = decodeURIComponent(value[i]);
  616. } else {
  617. value = decodeURIComponent(value);
  618. }
  619. key = decodeURIComponent(key);
  620. cookies[key] = value;
  621. } catch (e) {
  622. }
  623. }
  624. return cookies;
  625. }
  626. }, {
  627. set: function(key, value, option) {
  628. this.cookies[key] = value;
  629. if (value instanceof Array) {
  630. for (var i = 0; i < value.length; i++)
  631. value[i] = encodeURIComponent(value[i]);
  632. value = value.join('&');
  633. } else {
  634. value = encodeURIComponent(value);
  635. }
  636. var cookie = encodeURIComponent(key) + '=' + value;
  637. option = option || { };
  638. if (typeof option == 'string' || option instanceof Date) {
  639. // deprecated
  640. option = {
  641. expires: option
  642. };
  643. }
  644. if (!option.expires) {
  645. option.expires = this.defaultExpires;
  646. }
  647. if (/^\+?(\d+)([ymdh])$/.exec(option.expires)) {
  648. var count = parseInt(RegExp.$1);
  649. var field = ({ y: 'FullYear', m: 'Month', d: 'Date', h: 'Hours' })[RegExp.$2];
  650. var date = new Date;
  651. date['set' + field](date['get' + field]() + count);
  652. option.expires = date;
  653. }
  654. if (option.expires) {
  655. if (option.expires.toUTCString)
  656. option.expires = option.expires.toUTCString();
  657. cookie += '; expires=' + option.expires;
  658. }
  659. if (option.domain) {
  660. cookie += '; domain=' + option.domain;
  661. }
  662. if (option.path) {
  663. cookie += '; path=' + option.path;
  664. } else {
  665. cookie += '; path=/';
  666. }
  667. return document.cookie = cookie;
  668. },
  669. get: function(key) {
  670. return this.cookies[key];
  671. },
  672. has: function(key) {
  673. return (key in this.cookies) && !(key in Object.prototype);
  674. },
  675. clear: function(key) {
  676. this.set(key, '', new Date(0));
  677. delete this.cookies[key];
  678. }
  679. });
  680. /* Ten.Selector */
  681. Ten.Selector = new Ten.Class({
  682. initialize: function(selector) {
  683. this.selectorText = selector;
  684. var sels = selector.split(/\s+/);
  685. var child = null;
  686. var separator = null;
  687. for (var i = sels.length - 1; i >= 0; i--) {
  688. if (sels[i] == '>') {
  689. continue;
  690. } else if ((i > 0) && sels[i-1] == '>') {
  691. separator = sels[i-1];
  692. }
  693. var opt = separator ? {separator: separator} : null;
  694. separator = null;
  695. var node = new Ten.SelectorNode(sels[i],child,opt);
  696. child = node;
  697. }
  698. this.childNode = child;
  699. },
  700. getElementsBySelector: function(selector, parent) {
  701. sels = selector.split(/\s*,\s*/);
  702. var ret = [];
  703. for (var i = 0; i < sels.length; i++) {
  704. var sel = new Ten.Selector(sels[i]);
  705. ret = ret.concat(sel.getElements(parent));
  706. }
  707. ret = Ten.Array.flatten(ret);
  708. return ret;
  709. }
  710. },{
  711. getElements: function(parent) {
  712. if (typeof(parent) == 'undefined') {
  713. parent = document;
  714. }
  715. return this.childNode.getElements(parent);
  716. }
  717. });
  718. /* Ten.SelectorNode */
  719. Ten.SelectorNode = new Ten.Class({
  720. initialize: function(selector, child, opt) {
  721. if (selector) {
  722. selector = selector.replace(/\s/g,'');
  723. }
  724. this.option = opt;
  725. this.selectorText = selector;
  726. this.childNode = child;
  727. this.parseSelector();
  728. }
  729. },{
  730. getElementsBySelector: null, // will be overridden by parser
  731. parseSelector: function() {
  732. var f = 'getElementsBySelector';
  733. var t = this.selectorText;
  734. var match;
  735. if ((match = t.match(/^(.+)\:([\w-+()]+)$/))) {
  736. t = match[1];
  737. this.pseudoClass = match[2];
  738. }
  739. if (t.match(/^[\w-]+$/)) {
  740. this[f] = function(parent) {
  741. return parent.getElementsByTagName(t);
  742. };
  743. } else if ((match = t.match(/^([\w-]+)?#([\w-]+)$/))) {
  744. var tname = match[1];
  745. var idname = match[2];
  746. this[f] = function(parent) {
  747. var e = document.getElementById(idname);
  748. if (!tname ||
  749. e.tagName.toLowerCase() == tname.toLowerCase()) {
  750. return [e];
  751. } else {
  752. return [];
  753. }
  754. };
  755. } else if ((match = t.match(/^([\w-]+)?\.([\w-]+)/))) {
  756. var tname = match[1];
  757. var cname = match[2];
  758. this[f] = function(parent) {
  759. return Ten.DOM.getElementsByTagAndClassName(tname,cname,parent);
  760. };
  761. }
  762. if (this.option && this.option.separator) this.parseSeparator();
  763. if (this.pseudoClass) this.parsePseudoClass();
  764. },
  765. parsePseudoClass: function() {
  766. if (!this.pseudoClass) return;
  767. var pseudo = this.pseudoClass;
  768. var f = 'getElementsBySelector';
  769. var func = this[f];
  770. var match;
  771. if ((match = pseudo.match(/^(.+)-child(\((\d+)\))?$/))) {
  772. var type = match[1];
  773. var n = match[3];
  774. var index;
  775. if (type == 'first') {
  776. index = 0;
  777. } else if (type == 'last') {
  778. index = -1;
  779. } else if (type == 'nth' && n) {
  780. index = n - 1;
  781. }
  782. if (typeof index == 'number') {
  783. this[f] = function(parent) {
  784. var elems = func(parent);
  785. if (index < 0) index = elems.length + index;
  786. if (elems[index]) {
  787. return [elems[index]];
  788. } else {
  789. return [];
  790. }
  791. }
  792. }
  793. } else if ((match = pseudo.match(/^nth-child\((\d+)n\+(\d+)\)$/))) {
  794. var a = new Number(match[1]);
  795. var b = new Number(match[2]);
  796. this[f] = function(parent) {
  797. var elems = func(parent);
  798. var ret = [];
  799. for (var n = 0; n < 1000; n++) {
  800. var i = a * n + b - 1;
  801. if (i < 0) continue;
  802. if (typeof elems[i] == 'undefined') break;
  803. ret.push(elems[i]);
  804. }
  805. return ret;
  806. };
  807. }
  808. },
  809. parseSeparator: function() {
  810. if (!this.option) return;
  811. var sep = this.option.separator;
  812. if (!sep) return;
  813. var f = 'getElementsBySelector';
  814. var func = this[f];
  815. if (sep == '>') {
  816. this[f] = function(parent) {
  817. var elems = func(parent);
  818. var ret = [];
  819. for (var i = 0; i < elems.length; i++) {
  820. if (elems[i].parentNode == parent) ret.push(elems[i]);
  821. }
  822. return ret;
  823. }
  824. }
  825. },
  826. getElements: function(parent) {
  827. if (typeof this.getElementsBySelector != 'function') return null;
  828. var ret = [];
  829. var elems = this.getElementsBySelector(parent);
  830. if (elems && this.childNode) {
  831. for (var i = 0; i < elems.length; i++) {
  832. ret.push(this.childNode.getElements(elems[i]));
  833. }
  834. return ret;
  835. } else {
  836. return elems;
  837. }
  838. }
  839. });
  840. /* Ten._Selector */
  841. Ten._Selector = new Ten.Class({
  842. base : [Ten.Selector],
  843. initialize: function(selector) {
  844. this.selectorText = selector;
  845. var sels = selector.split(/\s+/);
  846. var child = null;
  847. var separator = null;
  848. for (var i = sels.length - 1; i >= 0; i--) {
  849. if (sels[i] == '>') {
  850. continue;
  851. } else if ((i > 0) && sels[i-1] == '>') {
  852. separator = sels[i-1];
  853. }
  854. var opt = separator ? {separator: separator} : null;
  855. separator = null;
  856. var node = new Ten._SelectorNode(sels[i],child,opt);
  857. child = node;
  858. }
  859. this.childNode = child;
  860. },
  861. getElementsBySelector: function(selector, parent) {
  862. sels = selector.split(/\s*,\s*/);
  863. var ret = [];
  864. for (var i = 0; i < sels.length; i++) {
  865. var sel = new Ten._Selector(sels[i]);
  866. ret = ret.concat(sel.getElements(parent));
  867. }
  868. ret = Ten._Selector._elementArrayFlatten(ret);
  869. if (selector.indexOf(',') >= 0) ret.sort(Ten._Selector._sortByElementOrder);
  870. return ret;
  871. },
  872. _sortByElementOrder: function(a, b) {
  873. var depthA = Ten._Selector._getNodeDepth(a);
  874. var depthB = Ten._Selector._getNodeDepth(b);
  875. if (depthA > depthB) for (var i = 0; i < (depthA - depthB) ; i++ ) a = a.parentNode;
  876. else if (depthA < depthB) for (var i = 0; i < (depthB - depthA) ; i++ ) b = b.parentNode;
  877. return Ten._Selector._getSiblingDepth(b) - Ten._Selector._getSiblingDepth(a);
  878. },
  879. _getNodeDepth: function(elem) {
  880. var i = 0;
  881. for (var n = elem ; n ; n = n.parentNode, i++){}
  882. return i;
  883. },
  884. _getSiblingDepth: function(elem) {
  885. var i = 0;
  886. for (var n = elem; n ; n = n.nextSibling, i++){}
  887. return i;
  888. },
  889. _elementArrayFlatten : function(arr) {
  890. var ret = [];
  891. (function(arr) {
  892. for (var i = 0; i < arr.length; i++) {
  893. var o = arr[i];
  894. if (o instanceof Array ||
  895. (o && typeof(o.length) === 'number'
  896. && typeof(o) != 'string'
  897. && !o.tagName)){
  898. arguments.callee(o);
  899. } else {
  900. ret.push(o);
  901. }
  902. }
  903. })(arr);
  904. return ret;
  905. }
  906. },{
  907. });
  908. /* Ten._SelectorNode */
  909. Ten._SelectorNode = new Ten.Class({
  910. base : [Ten.SelectorNode]
  911. },{
  912. parsePseudoClass: function() {
  913. if (!this.pseudoClass) return;
  914. var pseudo = this.pseudoClass;
  915. var f = 'getElementsBySelector';
  916. var func = this[f];
  917. var match;
  918. if ((match = pseudo.match(/^(.+)-child(\((\d+)\))?$/))) {
  919. var type = match[1];
  920. var n = match[3];
  921. var index;
  922. if (type == 'first') {
  923. index = 0;
  924. } else if (type == 'last') {
  925. index = -1;
  926. } else if (type == 'nth' && n) {
  927. index = n - 1;
  928. }
  929. if (typeof index == 'number') {
  930. this[f] = function(parent) {
  931. var elems = func(parent);
  932. var ret = [];
  933. for (var i = 0, len = elems.length ; i < len ; i++ ) {
  934. var children = elems[i].parentNode.childNodes;
  935. if((index >= 0 && children[index] == elems[i])
  936. || (index < 0 && children[children.length - 1] == elems[i]))
  937. ret.push(elems[i]);
  938. }
  939. return ret;
  940. }
  941. }
  942. } else if ((match = pseudo.match(/^nth-child\((\d+)n\+(\d+)\)$/))) {
  943. var a = new Number(match[1]);
  944. var b = new Number(match[2]);
  945. this[f] = function(parent) {
  946. var elems = func(parent);
  947. var tagName = elems[0].tagName;
  948. var parents = [];
  949. var checkArray = function (array , e) {
  950. for (var i = 0 , len = array.length; i < len ; i++) {
  951. if (array[i] == e) return;
  952. }
  953. array.push(e);
  954. }
  955. for (var i = 0, len = elems.length ; i < len ; i++ ){
  956. checkArray(parents, elems[i].parentNode);
  957. }
  958. var ret = [];
  959. for (var j = 0, len = parents.length ; j < len ; j++) {
  960. var children = parents[j].childNodes;
  961. for (var n = 0; n < children.length; n++) {
  962. var i = a * n + b - 1;
  963. if (i < 0) continue;
  964. if (children[i] && children[i].tagName == tagName) ret.push(children[i]);
  965. }
  966. }
  967. return ret;
  968. };
  969. }
  970. }
  971. });
  972. /* Ten.querySelector */
  973. Ten.querySelector;
  974. if (document.querySelector) {
  975. Ten.querySelector = function (selector, elem) {
  976. if (elem) return (elem.querySelector) ? elem.querySelector(selector) : null;
  977. return document.querySelector(selector);
  978. }
  979. } else {
  980. Ten.querySelector = function (selector, elem) {
  981. return Ten._Selector.getElementsBySelector(selector, elem)[0] || null;
  982. }
  983. }
  984. Ten.querySelectorAll;
  985. if (document.querySelectorAll) {
  986. Ten.querySelectorAll = function (selector, elem) {
  987. var elems ;
  988. try {
  989. if (elem) elems = (elem.querySelectorAll) ? elem.querySelectorAll(selector) : [];
  990. else elems = document.querySelectorAll(selector);
  991. } catch (e) {
  992. return (elem) ? Ten._Selector.getElementsBySelector(selector, elem) : Ten._Selector.getElementsBySelector(selector);
  993. }
  994. // return Array.prototype.slice.apply(elems);
  995. var ret = [];
  996. for (var i = 0 , len = elems.length ; i < len ; i++ ) ret.push(elems[i]);
  997. return ret;
  998. }
  999. Ten.DOM.orig_getElementsByTagAndClassName = Ten.DOM.getElementsByTagAndClassName;
  1000. Ten.DOM.getElementsByTagAndClassName = function(tag,klass,parent) {
  1001. var selector = tag || '';
  1002. if (klass) selector += '.' + klass;
  1003. if (!tag && !klass) return [];
  1004. try {
  1005. return Ten.querySelectorAll(selector, parent);
  1006. } catch(e) {
  1007. return Ten.DOM.orig_getElementsByTagAndClassName(tag, klass, parent);
  1008. }
  1009. }
  1010. } else {
  1011. Ten.querySelectorAll = Ten._Selector.getElementsBySelector;
  1012. }
  1013. /* Ten.Color */
  1014. Ten.Color = new Ten.Class({
  1015. initialize: function(r,g,b,a) {
  1016. if (typeof(a) == 'undefined' || a === null) a = 1;
  1017. this.r = r;
  1018. this.g = g;
  1019. this.b = b;
  1020. this.a = a;
  1021. },
  1022. parseFromString: function(str) {
  1023. var match;
  1024. if ((match = str.match(/^#([0-9a-f]{6}|[0-9a-f]{3})$/i))) {
  1025. var hexstr = match[1];
  1026. var w = hexstr.length / 3;
  1027. var rgb = [];
  1028. for (var i = 0; i < 3; i++) {
  1029. var hex = hexstr.substr(w * i, w);
  1030. if (hex.length == 1) hex += hex;
  1031. rgb.push(parseInt(hex,16));
  1032. }
  1033. return new Ten.Color(rgb[0],rgb[1],rgb[2]);
  1034. } else if ((match = str.match(/^rgb\(([\d.,\s]+)\)/))) {
  1035. var rdba = match[1].split(/[\s,]+/);
  1036. return new Ten.Color(rdba[0],rdba[1],rdba[2],rdba[3]);
  1037. }
  1038. return null;
  1039. },
  1040. parseFromElementColor: function(elem,prop) {
  1041. var ret;
  1042. for (var color; elem; elem = elem.parentNode) {
  1043. color = Ten.Style.getElementStyle(elem, prop);
  1044. if (typeof(color) != 'undefined' && color != 'transparent') {
  1045. ret = color;
  1046. break;
  1047. }
  1048. }
  1049. return ret ? Ten.Color.parseFromString(ret) : null;
  1050. }
  1051. },{
  1052. asRGBString: function() {
  1053. if (this.a < 1) {
  1054. return 'rgba(' + this.r + ',' + this.g + ',' + this.b +
  1055. ',' + this.a + ')';
  1056. } else {
  1057. return 'rgb(' + this.r + ',' + this.g + ',' + this.b + ')';
  1058. }
  1059. },
  1060. asHexString: function() {
  1061. var str = '#';
  1062. var cls = ['r','g','b'];
  1063. for (var i = 0; i < 3; i ++) {
  1064. var c = Math.round(this[cls[i]]);
  1065. var s = c.toString(16);
  1066. if (c < 16) s = '0' + s;
  1067. str += s;
  1068. }
  1069. return str;
  1070. },
  1071. overlay: function(color) {
  1072. if (color.a == 1) return color;
  1073. r = Math.round(color.r * color.a + this.r * this.a * (1 - color.a));
  1074. g = Math.round(color.g * color.a + this.g * this.a * (1 - color.a));
  1075. b = Math.round(color.b * color.a + this.b * this.a * (1 - color.a));
  1076. return new Ten.Color(r,g,b);
  1077. }
  1078. });
  1079. /* Ten.Style */
  1080. Ten.Style = new Ten.Class({
  1081. applyStyle: function(elem, style) {
  1082. var cssText = elem.style.cssText;
  1083. var estyle = elem.style;
  1084. for (var prop in style) {
  1085. estyle[prop] = style[prop];
  1086. }
  1087. return function() {
  1088. elem.style.cssText = cssText;
  1089. };
  1090. },
  1091. getGlobalRule: function(selector) {
  1092. selector = selector.toLowerCase();
  1093. if (Ten.Style._cache[selector]) {
  1094. return Ten.Style._cache[selector];
  1095. } else if (Ten.Style._cache[selector] === null) {
  1096. return null;
  1097. } else {
  1098. for (var i = document.styleSheets.length - 1; i >= 0; i--) {
  1099. var ss = document.styleSheets[i];
  1100. try {
  1101. var cssRules = ss.cssRules || ss.rules;
  1102. } catch(e) {
  1103. continue;
  1104. }
  1105. for (var j = cssRules.length - 1; j >= 0; j--) {
  1106. var rule = cssRules[j];
  1107. if (rule.selectorText &&
  1108. rule.selectorText.toLowerCase() == selector) {
  1109. Ten.Style._cache[selector] = rule;
  1110. return rule;
  1111. }
  1112. }
  1113. }
  1114. }
  1115. Ten.Style._cache[selector] = null;
  1116. return null;
  1117. },
  1118. getGlobalStyle: function(selector, prop) {
  1119. var rule = Ten.Style.getGlobalRule(selector);
  1120. if (rule && rule.style[prop]) {
  1121. return rule.style[prop];
  1122. } else {
  1123. return null;
  1124. }
  1125. },
  1126. getElementStyle: function(elem, prop) {
  1127. var style = elem.style ? elem.style[prop] : null;
  1128. if (!style) {
  1129. var dv = document.defaultView;
  1130. if (dv && dv.getComputedStyle) {
  1131. try {
  1132. var styles = dv.getComputedStyle(elem, null);
  1133. } catch(e) {
  1134. return null;
  1135. }
  1136. prop = prop.replace(/([A-Z])/g, '-$1').toLowerCase();
  1137. style = styles ? styles.getPropertyValue(prop) : null;
  1138. } else if (elem.currentStyle) {
  1139. style = elem.currentStyle[prop];
  1140. }
  1141. }
  1142. return style;
  1143. },
  1144. scrapeURL: function(url) {
  1145. if (url.match(/url\((.+)\)/)) {
  1146. url = RegExp.$1;
  1147. url = url.replace(/[\'\"<>]/g, '');
  1148. return url;
  1149. }
  1150. return null;
  1151. },
  1152. _cache: {}
  1153. });
  1154. /* Ten.Geometry */
  1155. Ten.Geometry = new Ten.Class({
  1156. initialize: function() {
  1157. if (Ten.Geometry._initialized) return;
  1158. var func = Ten.Geometry._functions;
  1159. var de = document.documentElement;
  1160. if (window.innerWidth) {
  1161. func.getWindowWidth = function() { return window.innerWidth; }
  1162. func.getWindowHeight = function() { return window.innerHeight; }
  1163. func.getXScroll = function() { return window.pageXOffset; }
  1164. func.getYScroll = function() { return window.pageYOffset; }
  1165. } else if (de && de.clientWidth) {
  1166. func.getWindowWidth = function() { return de.clientWidth; }
  1167. func.getWindowHeight = function() { return de.clientHeight; }
  1168. func.getXScroll = function() { return de.scrollLeft; }
  1169. func.getYScroll = function() { return de.scrollTop; }
  1170. } else if (document.body.clientWidth) {
  1171. func.getWindowWidth = function() { return document.body.clientWidth; }
  1172. func.getWindowHeight = function() { return document.body.clientHeight; }
  1173. func.getXScroll = function() { return document.body.scrollLeft; }
  1174. func.getYScroll = function() { return document.body.scrollTop; }
  1175. }
  1176. if (window.opera) {
  1177. func.getDocumentHeight = function(w) { return parseInt(Ten.Style.getElementStyle(w.document.body, 'height')); }
  1178. func.getDocumentWidth = function(w) { return parseInt(Ten.Style.getElementStyle(w.document.body, 'width')); }
  1179. } else if (document.all) {
  1180. func.getDocumentHeight = function(w) { return w.document.body.scrollHeight; }
  1181. func.getDocumentWidth = function(w) { return w.document.body.scrollWidth; }
  1182. } else {
  1183. func.getDocumentHeight = function(w) { return w.document.body.offsetHeight || w.document.documentElement.scrollHeight; }
  1184. func.getDocumentWidth = function(w) { return w.document.body.offsetWidth || w.document.documentElement.scrollWidth; }
  1185. }
  1186. Ten.Geometry._initialized = true;
  1187. },
  1188. _initialized: false,
  1189. _functions: {},
  1190. getScroll: function() {
  1191. if (!Ten.Geometry._initialized) new Ten.Geometry;
  1192. return {
  1193. x: Ten.Geometry._functions.getXScroll(),
  1194. y: Ten.Geometry._functions.getYScroll()
  1195. };
  1196. },
  1197. getMousePosition: function(pos) {
  1198. // pos should have clientX, clientY same as mouse event
  1199. if (!Ten.Browser.isChrome && (navigator.userAgent.indexOf('Safari') > -1) &&
  1200. (navigator.userAgent.indexOf('Version/') < 0)) {
  1201. return {
  1202. x: pos.clientX,
  1203. y: pos.clientY
  1204. };
  1205. } else {
  1206. var scroll = Ten.Geometry.getScroll();
  1207. return {
  1208. x: pos.clientX + scroll.x,
  1209. y: pos.clientY + scroll.y
  1210. };
  1211. }
  1212. },
  1213. getElementPosition: function(e) {
  1214. var pos = {x:0, y:0};
  1215. if (document.documentElement.getBoundingClientRect) { // IE
  1216. var box = e.getBoundingClientRect();
  1217. var owner = e.ownerDocument;
  1218. pos.x = box.left + Math.max(owner.documentElement.scrollLeft, owner.body.scrollLeft) - 2;
  1219. pos.y = box.top + Math.max(owner.documentElement.scrollTop, owner.body.scrollTop) - 2
  1220. } else if(document.getBoxObjectFor) { //Firefox
  1221. pos.x = document.getBoxObjectFor(e).x;
  1222. pos.y = document.getBoxObjectFor(e).y;
  1223. } else {
  1224. do {
  1225. pos.x += e.offsetLeft;
  1226. pos.y += e.offsetTop;
  1227. } while ((e = e.offsetParent));
  1228. }
  1229. return pos;
  1230. },
  1231. getWindowSize: function() {
  1232. if (!Ten.Geometry._initialized) new Ten.Geometry;
  1233. return {
  1234. w: Ten.Geometry._functions.getWindowWidth(),
  1235. h: Ten.Geometry._functions.getWindowHeight()
  1236. };
  1237. },
  1238. getDocumentSize: function(w) {
  1239. if (!Ten.Geometry._initialized) new Ten.Geometry;
  1240. w = w || window;
  1241. return {
  1242. w: Ten.Geometry._functions.getDocumentWidth(w),
  1243. h: Ten.Geometry._functions.getDocumentHeight(w)
  1244. };
  1245. }
  1246. });
  1247. /* Ten.Position */
  1248. Ten.Position = new Ten.Class({
  1249. initialize: function(x,y) {
  1250. this.x = x;
  1251. this.y = y;
  1252. },
  1253. add: function(a,b) {
  1254. return new Ten.Position(a.x + b.x, a.y + b.y);
  1255. },
  1256. subtract: function(a,b) {
  1257. return new Ten.Position(a.x - b.x, a.y - b.y);
  1258. }
  1259. });
  1260. /* Ten.Logger */
  1261. Ten.Logger = new Ten.Class({
  1262. initialize: function(level, fallbackElement) {
  1263. this.level = level || 'info';
  1264. this.fallbackElement = fallbackElement;
  1265. this.logFunction = this.constructor.logFunction;
  1266. this.logs = [];
  1267. },
  1268. LEVEL: {
  1269. error: 0,
  1270. warn: 1,
  1271. info: 2,
  1272. debug: 3
  1273. },
  1274. logFunction: function(level, args) {
  1275. if (typeof console == 'undefined') {
  1276. try {
  1277. if (window.opera) {
  1278. // Opera
  1279. opera.postError(args.join(', '));
  1280. } else {
  1281. // fub
  1282. external.consoleLog(args.join(', '));
  1283. }
  1284. } catch (e) {
  1285. if (this.fallbackElement && this.fallbackElement.appendChild) {
  1286. this.fallbackElement.appendChild(document.createTextNode(level + ': ' + args.join(', ')));
  1287. this.fallbackElement.appendChild(document.createElement('br'));
  1288. }
  1289. }
  1290. } else if (typeof console[level] == 'function') {
  1291. if (navigator.userAgent.indexOf('Safari') >= 0) {
  1292. // Safari
  1293. console[level](args.join(', '));
  1294. } else {
  1295. // Firefox (with Firebug)
  1296. console[level].apply(console, args);
  1297. }
  1298. } else if (typeof console.log == 'function') {
  1299. console.log(args.join(', '));
  1300. }
  1301. }
  1302. }, {
  1303. logs: null,
  1304. log: function(level) {
  1305. var LEVEL = this.constructor.LEVEL;
  1306. if (!(level in LEVEL) || LEVEL[level] > LEVEL[this.level])
  1307. return;
  1308. var args = [];
  1309. for (var i = 1; i < arguments.length; i++) {
  1310. args.push(arguments[i]);
  1311. }
  1312. this.logs.push([level, args]);
  1313. this.logFunction(level, args);
  1314. },
  1315. error: function() {
  1316. return this._log('error', arguments);
  1317. },
  1318. warn: function() {
  1319. return this._log('warn', arguments);
  1320. },
  1321. info: function() {
  1322. return this._log('info', arguments);
  1323. },
  1324. debug: function() {
  1325. return this._log('debug', arguments);
  1326. },
  1327. _log: function(level, _arguments) {
  1328. var args = [level];
  1329. for (var i = 0; i < _arguments.length; i++)
  1330. args.push(_arguments[i]);
  1331. return this.log.apply(this, args);
  1332. }
  1333. });
  1334. /* Ten.Browser */
  1335. Ten.Browser = {
  1336. isIE: navigator.userAgent.indexOf('MSIE') != -1,
  1337. isMozilla: navigator.userAgent.indexOf('Mozilla') != -1 && !/compatible|WebKit/.test(navigator.userAgent),
  1338. isOpera: !!window.opera,
  1339. isSafari: navigator.userAgent.indexOf('WebKit') != -1,
  1340. isChrome : navigator.userAgent.indexOf('Chrome/') != -1,
  1341. isFirefox : navigator.userAgent.indexOf('Firefox/') != -1,
  1342. isSupportsXPath : !!document.evaluate,
  1343. version: {
  1344. string: (/(?:Firefox\/|MSIE |Opera\/|Chrome\/|Version\/)([\d.]+)/.exec(navigator.userAgent) || []).pop(),
  1345. valueOf: function() { return parseFloat(this.string) },
  1346. toString: function() { return this.string }
  1347. }
  1348. };
  1349. Ten.Deferred = (function () {
  1350. function Deferred () { return (this instanceof Deferred) ? this.init() : new Deferred() }
  1351. Deferred.ok = function (x) { return x };
  1352. Deferred.ng = function (x) { throw x };
  1353. Deferred.prototype = {
  1354. init : function () {
  1355. this._next = null;
  1356. this.callback = {
  1357. ok: Deferred.ok,
  1358. ng: Deferred.ng
  1359. };
  1360. return this;
  1361. },
  1362. next : function (fun) { return this._post("ok", fun) },
  1363. error : function (fun) { return this._post("ng", fun) },
  1364. call : function (val) { return this._fire("ok", val) },
  1365. fail : function (err) { return this._fire("ng", err) },
  1366. cancel : function () {
  1367. (this.canceller || function () {})();
  1368. return this.init();
  1369. },
  1370. _post : function (okng, fun) {
  1371. this._next = new Deferred();
  1372. this._next.callback[okng] = fun;
  1373. return this._next;
  1374. },
  1375. _fire : function (okng, value) {
  1376. var next = "ok";
  1377. try {
  1378. value = this.callback[okng].call(this, value);
  1379. } catch (e) {
  1380. next = "ng";
  1381. value = e;
  1382. if (Deferred.onerror) Deferred.onerror(e);
  1383. }
  1384. if (value instanceof Deferred) {
  1385. value._next = this._next;
  1386. } else {
  1387. if (this._next) this._next._fire(next, value);
  1388. }
  1389. return this;
  1390. }
  1391. };
  1392. Deferred.next_default = function (fun) {
  1393. var d = new Deferred();
  1394. var id = setTimeout(function () { d.call() }, 0);
  1395. d.canceller = function () { clearTimeout(id) };
  1396. if (fun) d.callback.ok = fun;
  1397. return d;
  1398. };
  1399. Deferred.next_faster_way_readystatechange = ((location.protocol == "http:") && !window.opera && /\bMSIE\b/.test(navigator.userAgent)) && function (fun) {
  1400. var d = new Deferred();
  1401. var t = new Date().getTime();
  1402. if (t - arguments.callee._prev_timeout_called < 150) {
  1403. var cancel = false;
  1404. var script = document.createElement("script");
  1405. script.type = "text/javascript";
  1406. script.src = "javascript:";
  1407. script.onreadystatechange = function () {
  1408. if (!cancel) {
  1409. d.canceller();
  1410. d.call();
  1411. }
  1412. };
  1413. d.canceller = function () {
  1414. if (!cancel) {
  1415. cancel = true;
  1416. script.onreadystatechange = null;
  1417. document.body.removeChild(script);
  1418. }
  1419. };
  1420. document.body.appendChild(script);
  1421. } else {
  1422. arguments.callee._prev_timeout_called = t;
  1423. var id = setTimeout(function () { d.call() }, 0);
  1424. d.canceller = function () { clearTimeout(id) };
  1425. }
  1426. if (fun) d.callback.ok = fun;
  1427. return d;
  1428. };
  1429. Deferred.next_faster_way_Image = ((typeof(Image) != "undefined") && document.addEventListener) && function (fun) {
  1430. var d = new Deferred();
  1431. var img = new Image();
  1432. var handler = function () {
  1433. d.canceller();
  1434. d.call();
  1435. };
  1436. img.addEventListener("load", handler, false);
  1437. img.addEventListener("error", handler, false);
  1438. d.canceller = function () {
  1439. img.removeEventListener("load", handler, false);
  1440. img.removeEventListener("error", handler, false);
  1441. };
  1442. img.src = "data:,/ _ / X";
  1443. if (fun) d.callback.ok = fun;
  1444. return d;
  1445. };
  1446. Deferred.next = Deferred.next_faster_way_readystatechange ||
  1447. Deferred.next_faster_way_Image ||
  1448. Deferred.next_default;
  1449. Deferred.wait = function (n) {
  1450. var d = new Deferred(), t = new Date();
  1451. var id = setTimeout(function () {
  1452. d.call((new Date).getTime() - t.getTime());
  1453. }, n * 1000);
  1454. d.canceller = function () { clearTimeout(id) };
  1455. return d;
  1456. };
  1457. Deferred.call = function (f ) {
  1458. var args = Array.prototype.slice.call(arguments, 1);
  1459. return Deferred.next(function () {
  1460. return f.apply(this, args);
  1461. });
  1462. };
  1463. Deferred.parallel = function (dl) {
  1464. var ret = new Deferred(), values = {}, num = 0;
  1465. for (var i in dl) if (dl.hasOwnProperty(i)) (function (d, i) {
  1466. d.next(function (v) {
  1467. values[i] = v;
  1468. if (--num <= 0) {
  1469. if (dl instanceof Array) {
  1470. values.length = dl.length;
  1471. values = Array.prototype.slice.call(values, 0);
  1472. }
  1473. ret.call(values);
  1474. }
  1475. }).error(function (e) {
  1476. ret.fail(e);
  1477. });
  1478. num++;
  1479. })(dl[i], i);
  1480. if (!num) Deferred.next(function () { ret.call() });
  1481. ret.canceller = function () {
  1482. for (var i in dl) if (dl.hasOwnProperty(i)) {
  1483. dl[i].cancel();
  1484. }
  1485. };
  1486. return ret;
  1487. };
  1488. Deferred.earlier = function (dl) {
  1489. var ret = new Deferred(), values = {}, num = 0;
  1490. for (var i in dl) if (dl.hasOwnProperty(i)) (function (d, i) {
  1491. d.next(function (v) {
  1492. values[i] = v;
  1493. if (dl instanceof Array) {
  1494. values.length = dl.length;
  1495. values = Array.prototype.slice.call(values, 0);
  1496. }
  1497. ret.canceller();
  1498. ret.call(values);
  1499. }).error(function (e) {
  1500. ret.fail(e);
  1501. });
  1502. num++;
  1503. })(dl[i], i);
  1504. if (!num) Deferred.next(function () { ret.call() });
  1505. ret.canceller = function () {
  1506. for (var i in dl) if (dl.hasOwnProperty(i)) {
  1507. dl[i].cancel();
  1508. }
  1509. };
  1510. return ret;
  1511. };
  1512. Deferred.loop = function (n, fun) {
  1513. var o = {
  1514. begin : n.begin || 0,
  1515. end : (typeof n.end == "number") ? n.end : n - 1,
  1516. step : n.step || 1,
  1517. last : false,
  1518. prev : null
  1519. };
  1520. var ret, step = o.step;
  1521. return Deferred.next(function () {
  1522. function _loop (i) {
  1523. if (i <= o.end) {
  1524. if ((i + step) > o.end) {
  1525. o.last = true;
  1526. o.step = o.end - i + 1;
  1527. }
  1528. o.prev = ret;
  1529. ret = fun.call(this, i, o);
  1530. if (ret instanceof Deferred) {
  1531. return ret.next(function (r) {
  1532. ret = r;
  1533. return Deferred.call(_loop, i + step);
  1534. });
  1535. } else {
  1536. return Deferred.call(_loop, i + step);
  1537. }
  1538. } else {
  1539. return ret;
  1540. }
  1541. }
  1542. return (o.begin <= o.end) ? Deferred.call(_loop, o.begin) : null;
  1543. });
  1544. };
  1545. Deferred.repeat = function (n, f) {
  1546. var i = 0, end = {}, ret = null;
  1547. return Deferred.next(function () {
  1548. var t = (new Date()).getTime();
  1549. divide: {
  1550. do {
  1551. if (i >= n) break divide;
  1552. ret = f(i++);
  1553. } while ((new Date()).getTime() - t < 20);
  1554. return Deferred.call(arguments.callee);
  1555. }
  1556. });
  1557. };
  1558. Deferred.register = function (name, fun) {
  1559. this.prototype[name] = function () {
  1560. var a = arguments;
  1561. return this.next(function () {
  1562. return fun.apply(this, a);
  1563. });
  1564. };
  1565. };
  1566. Deferred.register("loop", Deferred.loop);
  1567. Deferred.register("wait", Deferred.wait);
  1568. Deferred.Arguments = function (args) { this.args = Array.prototype.slice.call(args, 0) }
  1569. Deferred.connect = function (func, obj) {
  1570. if (!obj) obj = {};
  1571. var callbackArgIndex = obj.ok;
  1572. var errorbackArgIndex = obj.ng;
  1573. var target = obj.target;
  1574. return function () {
  1575. var d = new Deferred();
  1576. d.next = function (fun) { return this._post("ok", function () {
  1577. fun.apply(this, (arguments[0] instanceof Deferred.Arguments) ? arguments[0].args : arguments);
  1578. }) };
  1579. var args = Array.prototype.slice.call(arguments, 0);
  1580. if (!(isFinite(callbackArgIndex) && callbackArgIndex !== null)) {
  1581. callbackArgIndex = args.length;
  1582. }
  1583. var callback = function () { d.call(new Deferred.Arguments(arguments)) };
  1584. args.splice(callbackArgIndex, 0, callback);
  1585. if (isFinite(errorbackArgIndex) && errorbackArgIndex !== null) {
  1586. var errorback = function () { d.fail(arguments) };
  1587. args.splice(errorbackArgIndex, 0, errorback);
  1588. }
  1589. Deferred.next(function () { func.apply(target, args) });
  1590. return d;
  1591. }
  1592. }
  1593. Deferred.retry = function (retryCount, funcDeffered, options) {
  1594. if (!options) options = {};
  1595. var wait = options.wait || 0;
  1596. var d = new Deferred();
  1597. var retry = function () {
  1598. var m = funcDeffered(retryCount);
  1599. m.
  1600. next(function (mes) {
  1601. d.call(mes);
  1602. }).
  1603. error(function (e) {
  1604. if (--retryCount <= 0) {
  1605. d.fail(['retry failed', e]);
  1606. } else {
  1607. setTimeout(retry, wait * 1000);
  1608. }
  1609. });
  1610. };
  1611. setTimeout(retry, 0);
  1612. return d;
  1613. }
  1614. Deferred.define = function (obj, list) {
  1615. if (!list) list = ["parallel", "wait", "next", "call", "loop", "repeat"];
  1616. if (!obj) obj = (function getGlobal () { return this })();
  1617. for (var i = 0; i < list.length; i++) {
  1618. var n = list[i];
  1619. obj[n] = Deferred[n];
  1620. }
  1621. return Deferred;
  1622. };
  1623. return Deferred;
  1624. })();
  1625. } // if (typeof(Ten) == undefined)
  1626. /*
  1627. // require Ten.js
  1628. */
  1629. /* Ten.SubWindow */
  1630. Ten.SubWindow = new Ten.Class({
  1631. initialize: function(args) {
  1632. var c = this.constructor;
  1633. if (c.singleton && c._cache) {
  1634. return c._cache;
  1635. }
  1636. if (args) {
  1637. for (var k in args) {
  1638. this[k] = args[k];
  1639. }
  1640. }
  1641. var div = document.createElement('div');
  1642. Ten.Style.applyStyle(div, Ten.SubWindow._baseStyle);
  1643. Ten.Style.applyStyle(div, c.style);
  1644. this.window = div;
  1645. this.addContainerAndCloseButton();
  1646. document.body.appendChild(div);
  1647. if (c.draggable) {
  1648. this._draggable = new Ten.Draggable(div, this.handle);
  1649. }
  1650. if (c.singleton) c._cache = this;
  1651. return this;
  1652. },
  1653. _baseStyle: {
  1654. color: '#000',
  1655. position: 'absolute',
  1656. display: 'none',
  1657. zIndex: 2,
  1658. left: 0,
  1659. top: 0,
  1660. backgroundColor: '#fff',
  1661. border: '1px solid #bbb'
  1662. },
  1663. style: {
  1664. padding: '2px',
  1665. textAlign: 'center',
  1666. borderRadius: '6px',
  1667. MozBorderRadius: '6px',
  1668. width: '100px',
  1669. height: '100px'
  1670. },
  1671. handleStyle: {
  1672. position: 'absolute',
  1673. top: '0px',
  1674. left: '0px',
  1675. backgroundColor: '#f3f3f3',
  1676. borderBottom: '1px solid #bbb',
  1677. width: '100%',
  1678. height: '30px'
  1679. },
  1680. containerStyle: {
  1681. margin: '32px 0 0 0',
  1682. padding: '0 10px'
  1683. },
  1684. // closeButton: 'close.gif',
  1685. closeButton: 'http://s.hatena.com/images/close.gif',
  1686. closeButtonStyle: {
  1687. position: 'absolute',
  1688. top: '8px',
  1689. right: '10px',
  1690. cursor: 'pointer'
  1691. },
  1692. _baseScreenStyle: {
  1693. position: 'absolute',
  1694. top: '0px',
  1695. left: '0px',
  1696. display: 'none',
  1697. zIndex: 1,
  1698. overflow: 'hidden',
  1699. width: '100%',
  1700. height: '100%'
  1701. },
  1702. screenStyle: {},
  1703. showScreen: true,
  1704. singleton: true,
  1705. draggable: true,
  1706. _cache: null
  1707. },{
  1708. screen: null,
  1709. windowObserver: null,
  1710. visible: false,
  1711. addContainerAndCloseButton: function() {
  1712. var win = this.window;
  1713. var c = this.constructor;
  1714. var div = document.createElement('div');
  1715. win.appendChild(div);
  1716. Ten.Style.applyStyle(div, c.containerStyle);
  1717. this.container = div;
  1718. if (c.handleStyle) {
  1719. var handle = document.createElement('div');
  1720. Ten.Style.applyStyle(handle, c.handleStyle);
  1721. win.appendChild(handle);
  1722. this.handle = handle;
  1723. }
  1724. if (c.closeButton) {
  1725. var btn = document.createElement('img');
  1726. btn.src = c.closeButton;
  1727. btn.alt = 'close';
  1728. Ten.Style.applyStyle(btn, c.closeButtonStyle);
  1729. win.appendChild(btn);
  1730. new Ten.Observer(btn, 'onclick', this, 'hide');
  1731. this.closeButton = btn;
  1732. }
  1733. if (c.showScreen) {
  1734. var screen = document.createElement('div');
  1735. Ten.Style.applyStyle(screen, Ten.SubWindow._baseScreenStyle);
  1736. Ten.Style.applyStyle(screen, c.screenStyle);
  1737. document.body.appendChild(screen);
  1738. this.screen = screen;
  1739. new Ten.Observer(screen, 'onclick', this, 'hide');
  1740. }
  1741. },
  1742. show: function(pos) {
  1743. pos = (pos.x && pos.y) ? pos : {x:0, y:0};
  1744. with (this.window.style) {
  1745. display = 'block';
  1746. left = pos.x + 'px';
  1747. top = pos.y + 'px';
  1748. }
  1749. if (this.screen) {
  1750. with (this.screen.style) {
  1751. display = 'block';
  1752. left = Ten.Geometry.getScroll().x + 'px';
  1753. top = Ten.Geometry.getScroll().y + 'px';
  1754. }
  1755. }
  1756. this.windowObserver = new Ten.Observer(document.body, 'onkeypress', this, 'handleEscape');
  1757. this.visible = true;
  1758. },
  1759. handleEscape: function(e) {
  1760. if (!e.isKey('escape')) return;
  1761. this.hide();
  1762. e.stop();
  1763. },
  1764. hide: function() {
  1765. if (this._draggable) this._draggable.endDrag();
  1766. this.window.style.display = 'none';
  1767. if (this.screen) this.screen.style.display = 'none';
  1768. if (this.windowObserver) this.windowObserver.stop();
  1769. this.visible = false;
  1770. this.window.blur();
  1771. }
  1772. });
  1773. /* Ten.Draggable */
  1774. Ten.Draggable = new Ten.Class({
  1775. initialize: function(element,handle) {
  1776. this.element = element;
  1777. this.handle = handle || element;
  1778. this.startObserver = new Ten.Observer(this.handle, 'onmousedown', this, 'startDrag');
  1779. this.handlers = [];
  1780. }
  1781. },{
  1782. startDrag: function(e) {
  1783. if (e.targetIsFormElements()) return;
  1784. this.delta = Ten.Position.subtract(
  1785. e.mousePosition(),
  1786. Ten.Geometry.getElementPosition(this.element)
  1787. );
  1788. this.handlers = [
  1789. new Ten.Observer(document, 'onmousemove', this, 'drag'),
  1790. new Ten.Observer(document, 'onmouseup', this, 'endDrag'),
  1791. new Ten.Observer(this.element, 'onlosecapture', this, 'endDrag')
  1792. ];
  1793. e.stop();
  1794. },
  1795. drag: function(e) {
  1796. var pos = Ten.Position.subtract(e.mousePosition(), this.delta);
  1797. Ten.Style.applyStyle(this.element, {
  1798. left: pos.x + 'px',
  1799. top: pos.y + 'px'
  1800. });
  1801. e.stop();
  1802. },
  1803. endDrag: function(e) {
  1804. for (var i = 0; i < this.handlers.length; i++) {
  1805. this.handlers[i].stop();
  1806. }
  1807. if(e) e.stop();
  1808. }
  1809. });
  1810. /*
  1811. // require Ten.js
  1812. */
  1813. /* Ten.Highlight */
  1814. Ten.Highlight = new Ten.Class({
  1815. initialize: function(quote) {
  1816. if (!quote) return;
  1817. this.quote = quote;
  1818. var c = this.constructor;
  1819. if (!c._cache) c._cache = {};
  1820. if (c._cache[quote]) return c._cache[quote];
  1821. c._cache[quote] = this;
  1822. c.makeTextNodes(c);
  1823. },
  1824. makeTextNodes: function(c) {
  1825. if (c.textNodes || c.textNodePositions || c.documentText) return;
  1826. if (Ten.Highlight.highlighted) Ten.Highlight.highlighted.hide();
  1827. c.textNodes = [];
  1828. c.textNodePositions = [];
  1829. var isIE = navigator.userAgent.indexOf('MSIE') != -1;
  1830. var texts = [];
  1831. var pos = 0;
  1832. (function(node, parent) {
  1833. if (isIE && parent && parent != node.parentNode) return;
  1834. if (node.nodeType == 3) {
  1835. c.textNodes.push(node);
  1836. texts.push(node.nodeValue);
  1837. c.textNodePositions.push(pos);
  1838. pos += node.nodeValue.length;
  1839. } else {
  1840. var childNodes = node.childNodes;
  1841. for (var i = 0; i < childNodes.length; i++) {
  1842. arguments.callee(childNodes[i], node);
  1843. }
  1844. }
  1845. })(document.body);
  1846. c.documentText = texts.join('');
  1847. c.loaded = true;
  1848. },
  1849. loaded: false,
  1850. bgColors: null,
  1851. textNodes: null,
  1852. textNodePositions: null,
  1853. documentText: null,
  1854. highlighted: null,
  1855. _cache: null,
  1856. _lock: {},
  1857. Color: new Ten.Color(255,255,0,0.4),
  1858. ClassName: null
  1859. },{
  1860. makeMatchedNodes: function() {
  1861. if (this.matchedNodes) return;
  1862. var matched = {};
  1863. var c = this.constructor;
  1864. var quote = this.quote;
  1865. var nodes = c.textNodes, positions = c.textNodePositions, text = c.documentText;
  1866. var i = 0;
  1867. for (var start = text.indexOf(quote); start != -1;
  1868. start = text.indexOf(quote, start + quote.length)) {
  1869. var end = start + quote.length - 1;
  1870. for (; i < positions.length; i++) {
  1871. if (end < positions[i]) {
  1872. break;
  1873. }
  1874. var last = positions[i+1] ? positions[i+1] - 1
  1875. : c.documentText.length;
  1876. if (last < start) {
  1877. continue;
  1878. } else if (start <= last) {
  1879. if (!matched[i]) matched[i] = {ranges: []};
  1880. var range = [];
  1881. range[0] = start - positions[i];
  1882. range[1] = end < last ? end - positions[i] + 1
  1883. : last - positions[i] + 1;
  1884. matched[i].ranges.push(range);
  1885. }
  1886. }
  1887. i--;
  1888. }
  1889. this.matchedNodes = matched;
  1890. },
  1891. show: function() {
  1892. var c = this.constructor;
  1893. if (!c.loaded) return;
  1894. this.makeMatchedNodes();
  1895. var matched = this.matchedNodes;
  1896. if (!matched) return;
  1897. if (Ten.Highlight.highlighted) Ten.Highlight.highlighted.hide();
  1898. var nodes = c.textNodes;
  1899. if (!this.containers) this.containers = {};
  1900. var containers = this.containers;
  1901. for (var i in matched) {
  1902. if (!i.match(/^\d+$/)) continue;
  1903. if (!this.containers[i]) {
  1904. var node = nodes[i];
  1905. if (!node) continue;
  1906. var text = nodes[i].nodeValue;
  1907. var container = document.createElement('span');
  1908. container.style.padding = '0';
  1909. container.style.margin = '0';
  1910. var pos = 0;
  1911. var ranges = matched[i].ranges;
  1912. for (var j = 0; j < ranges.length; j++) {
  1913. var range = ranges[j];
  1914. if (pos < range[0]) {
  1915. container.appendChild(document.createTextNode(text.substring(pos,range[0])));
  1916. }
  1917. var span = this.createSpan(i);
  1918. if (!span) continue;
  1919. span.appendChild(document.createTextNode(text.substring(range[0],range[1])));
  1920. container.appendChild(span);
  1921. pos = range[1];
  1922. }
  1923. if (pos < text.length) container.appendChild(document.createTextNode(text.substring(pos)));
  1924. this.containers[i] = container;
  1925. }
  1926. this.replaceNode(i,true);
  1927. }
  1928. Ten.Highlight.highlighted = this;
  1929. },
  1930. createSpan: function(i) {
  1931. var c = this.constructor;
  1932. if (!c.bgColors) c.bgColors = {};
  1933. if (!c.bgColors[i]) {
  1934. if (!c.textNodes[i]) return;
  1935. var node = c.textNodes[i].parentNode;
  1936. var back = Ten.Color.parseFromElementColor(node,'backgroundColor')
  1937. || new Ten.Color(255,255,255);
  1938. c.bgColors[i] = back.overlay(c.Color).asHexString();
  1939. }
  1940. var span = document.createElement('span');
  1941. span.style.backgroundColor = c.bgColors[i];
  1942. if (c.ClassName) span.className = c.ClassName;
  1943. return span;
  1944. },
  1945. hide: function() {
  1946. var matched = this.matchedNodes;
  1947. if (!matched) return;
  1948. Ten.Highlight.highlighted = null;
  1949. var c = this.constructor;
  1950. for (var i in matched) {
  1951. if (!i.match(/^\d+$/)) continue;
  1952. this.replaceNode(i,false);
  1953. }
  1954. },
  1955. replaceNode: function(i, show) {
  1956. var c = this.constructor;
  1957. if (c._lock[i]) return;
  1958. if (c.textNodes[i].parentNode && c.textNodes[i].parentNode.tagName.toLowerCase() == 'textarea') {
  1959. return;
  1960. }
  1961. c._lock[i] = true;
  1962. var newNode, oldNode;
  1963. if (show) {
  1964. newNode = this.containers[i], oldNode = c.textNodes[i];
  1965. } else {
  1966. newNode = c.textNodes[i], oldNode = this.containers[i];
  1967. }
  1968. if (newNode) Ten.DOM.replaceNode(newNode, oldNode);
  1969. c._lock[i] = false;
  1970. },
  1971. containers: null,
  1972. matchedNodes: null
  1973. });
  1974. /*
  1975. // require Ten.js
  1976. */
  1977. /* Hatena */
  1978. if (typeof(Hatena) == 'undefined') {
  1979. Hatena = {};
  1980. }
  1981. /* Hatena.User */
  1982. Hatena.User = new Ten.Class({
  1983. initialize: function(args) {
  1984. if (typeof(args) == 'string') {
  1985. this.name = args;
  1986. } else {
  1987. for (var key in args) {
  1988. this[key] = args[key];
  1989. }
  1990. }
  1991. },
  1992. getProfileIcon: function(name) {
  1993. if (!name) name = 'user';
  1994. var pre = name.match(/^[\w-]{2}/)[0];
  1995. var img = document.createElement('img');
  1996. img.src = 'http://www.hatena.ne.jp/users/' + pre + '/' + name + '/profile_s.gif';
  1997. img.setAttribute('alt', name);
  1998. img.setAttribute('title', name);
  1999. img.setAttribute('width','16px');
  2000. img.setAttribute('height','16px');
  2001. img.className = 'profile-icon';
  2002. with (img.style) {
  2003. margin = '0 3px';
  2004. border = 'none';
  2005. verticalAlign = 'middle';
  2006. }
  2007. return img;
  2008. }
  2009. }, {
  2010. profileIcon: function() {
  2011. return Hatena.User.getProfileIcon(this.name);
  2012. }
  2013. });
  2014. /*
  2015. // require Ten.js
  2016. // require Ten/SubWindow.js
  2017. // require Ten/Highlight.js
  2018. // require Hatena.js
  2019. */
  2020. /* Hatena.Star */
  2021. if (typeof(Hatena.Star) == 'undefined') {
  2022. Hatena.Star = {};
  2023. }
  2024. Hatena.Star.VERSION = 1.95;
  2025. /*
  2026. // Hatena.Star.* classes //
  2027. */
  2028. Hatena.Star.BaseURL = 'http://s.hatena.ne.jp/';
  2029. Hatena.Star.Token = null;
  2030. /* Hatena.Star.User */
  2031. Hatena.Star.User = new Ten.Class({
  2032. base: [Hatena.User],
  2033. initialize: function(name) {
  2034. if (Hatena.Star.User._cache[name]) {
  2035. return Hatena.Star.User._cache[name];
  2036. } else {
  2037. this.name = name;
  2038. Hatena.Star.User._cache[name] = this;
  2039. return this;
  2040. }
  2041. },
  2042. getProfileIcon: function(name,src) {
  2043. if (!name) name = 'user';
  2044. var img = document.createElement('img');
  2045. if (src) {
  2046. img.src = src;
  2047. } else {
  2048. var pre = name.match(/^[\w-]{2}/)[0];
  2049. img.src = 'http://www.st-hatena.com/users/' + pre + '/' + name + '/profile_s.gif';
  2050. }
  2051. img.setAttribute('alt', name);
  2052. img.setAttribute('title', name);
  2053. img.setAttribute('width','16px');
  2054. img.setAttribute('height','16px');
  2055. img.className = 'profile-icon';
  2056. with (img.style) {
  2057. margin = '0 3px';
  2058. border = 'none';
  2059. verticalAlign = 'middle';
  2060. width = '16px';
  2061. height = '16px';
  2062. }
  2063. return img;
  2064. },
  2065. _cache: {}
  2066. },{
  2067. userPage: function() {
  2068. return Hatena.Star.BaseURL + this.name + '/';
  2069. }
  2070. });
  2071. /* Hatena.Star.Entry */
  2072. Hatena.Star.Entry = new Ten.Class({
  2073. initialize: function(e) {
  2074. this.entry = e;
  2075. this.uri = e.uri;
  2076. this.title = e.title;
  2077. this.star_container = e.star_container;
  2078. this.comment_container = e.comment_container;
  2079. this.entryNode = e.entryNode;
  2080. this.stars = [];
  2081. this.colored_stars = [];
  2082. this.comments = [];
  2083. this.starEntry = null;
  2084. },
  2085. maxStarCount: 11
  2086. },{
  2087. flushStars: function() {
  2088. this.stars = [];
  2089. this.star_container.innerHTML = '';
  2090. },
  2091. bindStarEntry: function(se) {
  2092. this.starEntry = se;
  2093. if (se.colored_stars) {
  2094. var colored_star_hash = {};
  2095. for (var i = 0, len = se.colored_stars.length; i < len ; i++){
  2096. colored_star_hash[se.colored_stars[i].color] = se.colored_stars[i].stars;
  2097. }
  2098. var cs = "purple,blue,red,green".split(',');
  2099. for (var i = 0, len = cs.length; i < len ; i++){
  2100. var csh = colored_star_hash[cs[i]];
  2101. if (csh) this.pushStars(csh,cs[i]);
  2102. }
  2103. }
  2104. this.pushStars(se.stars);
  2105. if (se.comments && !this.comments.length) {
  2106. for (var i = 0; i < se.comments.length; i++) {
  2107. this.comments.push(new Hatena.Star.Comment(se.comments[i]));
  2108. }
  2109. }
  2110. this.can_comment = se.can_comment;
  2111. },
  2112. pushStars: function(s,c) {
  2113. for (var i = 0; i < s.length; i++) {
  2114. if (typeof(s[i]) == 'number') {
  2115. this.stars.push(new Hatena.Star.InnerCount(s[i],this,c));
  2116. } else if(s[i]) {
  2117. var args = s[i];
  2118. args.entry = this.entry;
  2119. args.container = this.star_container;
  2120. args.color = c;
  2121. this.stars.push(new Hatena.Star.Star(args));
  2122. }
  2123. }
  2124. },
  2125. setCanComment: function(v) {
  2126. this.can_comment = v;
  2127. },
  2128. showButtons: function() {
  2129. this.addAddButton();
  2130. this.addCommentButton();
  2131. },
  2132. addAddButton: function() {
  2133. var sc = this.star_container;
  2134. if (sc) {
  2135. this.addButton = new Hatena.Star.AddButton(this,sc);
  2136. sc.appendChild(this.addButton);
  2137. }
  2138. },
  2139. addCommentButton: function() {
  2140. var cc = this.comment_container;
  2141. if (cc) {
  2142. this.commentButton = new Hatena.Star.CommentButton(this,cc);
  2143. cc.appendChild(this.commentButton.img);
  2144. }
  2145. },
  2146. showStars: function() {
  2147. var sc = this.star_container;
  2148. for (var i = 0; i < this.stars.length; i++) {
  2149. sc.appendChild(this.stars[i].asElement());
  2150. }
  2151. },
  2152. showCommentButton: function() {
  2153. if (this.can_comment) {
  2154. this.commentButton.show();
  2155. if (this.comments.length) this.commentButton.activate();
  2156. } else {
  2157. // this.commentButton.hide();
  2158. }
  2159. },
  2160. addTemporaryStar: function(args) {
  2161. // if (this.temporaryStar) return;
  2162. if (this.temporaryStar) {
  2163. this.star_container.removeChild(this.temporaryStar);
  2164. }
  2165. var s = new Hatena.Star.Star({
  2166. color: 'temp',
  2167. name: '',
  2168. entry: this,
  2169. container: this.star_container
  2170. });
  2171. this.temporaryStar = s.asElement();
  2172. this.star_container.appendChild(this.temporaryStar);
  2173. },
  2174. removeTemporaryStar: function() {
  2175. if (!this.temporaryStar) return;
  2176. this.temporaryStar.style.display = 'none';
  2177. this.temporaryStar = null;
  2178. },
  2179. addStar: function(args) {
  2180. var star = new Hatena.Star.Star({
  2181. color: args.color,
  2182. name: args.name,
  2183. quote: args.quote,
  2184. entry: this,
  2185. container: this.star_container
  2186. });
  2187. this.stars.push(star);
  2188. this.star_container.appendChild(star.asElement());
  2189. this.constructor.dispatchEvent('starAdded', this);
  2190. },
  2191. addComment: function(com) {
  2192. if (!this.comments) this.comments = [];
  2193. if (this.comments.length == 0) {
  2194. this.commentButton.activate();
  2195. }
  2196. this.comments.push(com);
  2197. },
  2198. showCommentCount: function() {
  2199. this.comment_container.innerHTML += this.comments.length;
  2200. }
  2201. });
  2202. Ten.EventDispatcher.implementEventDispatcher(Hatena.Star.Entry);
  2203. /* Hatena.Star.Button */
  2204. Hatena.Star.Button = new Ten.Class({
  2205. createButton: function(args) {
  2206. var img = document.createElement('img');
  2207. for (var attr in args) {
  2208. img.setAttribute(attr, args[attr]);
  2209. }
  2210. with (img.style) {
  2211. cursor = 'pointer';
  2212. margin = '0 3px';
  2213. padding = '0';
  2214. border = 'none';
  2215. verticalAlign = 'middle';
  2216. }
  2217. return img;
  2218. },
  2219. getImgSrc: function(c,container) {
  2220. var sel = c.ImgSrcSelector;
  2221. if (container) {
  2222. var cname = sel.replace(/\./,'');
  2223. var span = new Ten.Element('span',{
  2224. className: cname
  2225. });
  2226. container.appendChild(span);
  2227. var bgimage = Ten.Style.getElementStyle(span,'backgroundImage');
  2228. container.removeChild(span);
  2229. if (bgimage) {
  2230. var url = Ten.Style.scrapeURL(bgimage);
  2231. if (url) return url;
  2232. }
  2233. }
  2234. if (sel) {
  2235. var prop = Ten.Style.getGlobalStyle(sel,'backgroundImage');
  2236. if (prop) {
  2237. var url = Ten.Style.scrapeURL(prop);
  2238. if (url) return url;
  2239. }
  2240. }
  2241. return c.ImgSrc;
  2242. }
  2243. });
  2244. /* Hatena.Star.AddButton */
  2245. Hatena.Star.AddButton = new Ten.Class({
  2246. base: [Hatena.Star.Button],
  2247. initialize: function(entry,container) {
  2248. this.entry = entry;
  2249. this.lastPosition = null;
  2250. this.selectedText = null;
  2251. this.showSelectedColorTimerId = null;
  2252. this.hideSelectedColorTimerId = null;
  2253. var src = Hatena.Star.Button.getImgSrc(this.constructor,container);
  2254. var img = Hatena.Star.Button.createButton({
  2255. src: src,
  2256. tabIndex: 0,
  2257. alt: 'Add Star',
  2258. title: 'Add Star'
  2259. });
  2260. img.className = 'hatena-star-add-button';
  2261. new Ten.Observer(img,'onclick',this,'addStar');
  2262. new Ten.Observer(img,'onclick',this,'hideColorPallet');
  2263. new Ten.Observer(img,'onkeyup',this,'handleKeyUp');
  2264. // new Ten.Observer(img,'onmouseover',this,'showSelectedColor');
  2265. new Ten.Observer(img,'onmouseover',this,'showColorPalletDelay');
  2266. new Ten.Observer(img,'onmouseover',this,'copySelectedText');
  2267. new Ten.Observer(img,'onmouseout',this,'clearSelectedColorTimer');
  2268. // new Ten.Observer(img,'onmouseout',this,'hideSelectedColor');
  2269. // new Ten.Observer(img,'onmouseout',this,'hideSelectedColor');
  2270. this.img = img;
  2271. return img;
  2272. },
  2273. ImgSrcSelector: '.hatena-star-add-button-image',
  2274. ImgSrc: Hatena.Star.BaseURL + 'images/add.gif'
  2275. },{
  2276. handleKeyUp: function(e) {
  2277. if (!e.isKey('enter')) return;
  2278. this.addStar(e);
  2279. },
  2280. clearSelectedColorTimer : function() {
  2281. try{ clearTimeout(this.showSelectedColorTimerId); }catch(e){};
  2282. try{ clearTimeout(this.hideSelectedColorTimerId); }catch(e){};
  2283. },
  2284. showSelectedColor : function(e) {
  2285. var self = this;
  2286. this.clearSelectedColorTimer();
  2287. this.showSelectedColorTimerId = setTimeout(function(){
  2288. //if (!self.pallet || (self.pallet && self.pallet.isColorPallet()) ) self._showSelectedColor();
  2289. self._showSelectedColor();
  2290. },300);
  2291. },
  2292. _showSelectedColor : function(e) {
  2293. if (this.pallet) {
  2294. } else {
  2295. this.pallet = new Hatena.Star.Pallet();
  2296. }
  2297. if (this.pallet.isNowLoading) return;
  2298. var pos = Ten.Geometry.getElementPosition(this.img);
  2299. if (Ten.Browser.isFirefox || Ten.Browser.isOpera) {
  2300. pos.y += 15;
  2301. pos.x += 2;
  2302. } else {
  2303. pos.y += 13;
  2304. }
  2305. this.pallet.showSelectedColor(pos, this);
  2306. },
  2307. hideColorPallet : function(e) {
  2308. try {
  2309. this.pallet.hide();
  2310. } catch(e) {}
  2311. },
  2312. hideSelectedColor : function(e) {
  2313. var self = this;
  2314. this.clearSelectedColorTimer();
  2315. this.hideSelectedColorTimerId = setTimeout(function(){
  2316. if (self.pallet.isSelectedColor) {
  2317. //if (!self.pallet || (self.pallet && self.pallet.isSelectedColor()) ) self._showSelectedColor();
  2318. self.pallet.hide();
  2319. }
  2320. },2000);
  2321. },
  2322. showColorPalletDelay : function(e) {
  2323. var self = this;
  2324. this.clearSelectedColorTimer();
  2325. this.showSelectedColorTimerId = setTimeout(function(){
  2326. //if (!self.pallet || (self.pallet && self.pallet.isColorPallet()) ) self._showSelectedColor();
  2327. self.showColorPallet();
  2328. },800);
  2329. },
  2330. showColorPallet : function(e) {
  2331. this.clearSelectedColorTimer();
  2332. if (!this.pallet) this.pallet = new Hatena.Star.Pallet();
  2333. var pos = Ten.Geometry.getElementPosition(this.img);
  2334. if (Ten.Browser.isFirefox || Ten.Browser.isOpera) {
  2335. pos.y += 15;
  2336. pos.x += 2;
  2337. } else {
  2338. pos.y += 13;
  2339. }
  2340. this.pallet.showPallet(pos, this);
  2341. },
  2342. copySelectedText: function(e) {
  2343. this.selectedText = Ten.DOM.getSelectedText().substr(0,200);
  2344. },
  2345. addStar: function(e) {
  2346. this.clearSelectedColorTimer();
  2347. this.color = (this.color) ? this.color : 'yellow';
  2348. this.entry.addTemporaryStar({color: this.color});
  2349. this.lastPosition = e.mousePosition();
  2350. var quote = this.selectedText;
  2351. var uri = Hatena.Star.BaseURL + 'star.add.json?uri=' + encodeURIComponent(this.entry.uri) +
  2352. '&title=' + encodeURIComponent(this.entry.title) +
  2353. '&quote=' + encodeURIComponent(quote) +
  2354. '&location=' + encodeURIComponent(document.location.href);
  2355. if (Hatena.Star.Token) {
  2356. uri += '&token=' + Hatena.Star.Token;
  2357. }
  2358. if (Hatena.Visitor) {
  2359. if (Hatena.Visitor.RKS) {
  2360. uri += '&rks=' + Hatena.Visitor.RKS;
  2361. }
  2362. if (Hatena.Visitor.sessionParams) {
  2363. var params = Hatena.Visitor.sessionParams;
  2364. for (var key in params) {
  2365. uri += '&' + key + '=' + encodeURIComponent(params[key]);
  2366. }
  2367. }
  2368. }
  2369. new Ten.JSONP(uri, this, 'receiveResult');
  2370. },
  2371. receiveResult: function(args) {
  2372. this.entry.removeTemporaryStar();
  2373. var name = args ? args.name : null;
  2374. var color = args ? args.color : '';
  2375. var pos = this.lastPosition;
  2376. pos = (pos) ? pos : Ten.Geometry.getElementPosition(this.img);
  2377. pos.x -= 10;
  2378. pos.y += 25;
  2379. if (name) {
  2380. this.entry.addStar({
  2381. color: color,
  2382. name: name,
  2383. quote: args.quote
  2384. });
  2385. //alert('Succeeded in Adding Star ' + args);
  2386. } else if (args.is_guest && args.html) {
  2387. var win = new Hatena.LoginWindow();
  2388. win.addLoginForm(args.html);
  2389. win.show(pos);
  2390. } else if (args.errors) {
  2391. var scroll = Ten.Geometry.getScroll();
  2392. var scr = new Hatena.Star.AlertScreen();
  2393. var alert = args.errors[0];
  2394. scr.showAlert(alert, pos);
  2395. }
  2396. }
  2397. });
  2398. /* Hatena.Star.Pallet */
  2399. Hatena.Star.Pallet = new Ten.Class({
  2400. base: [Ten.SubWindow],
  2401. style: {
  2402. padding: '0px',
  2403. textAlign: 'center',
  2404. border: '0px'
  2405. },
  2406. containerStyle: {
  2407. textAlign: 'left',
  2408. margin: 0,
  2409. padding: 0
  2410. },
  2411. handleStyle: null,
  2412. showScreen: false,
  2413. closeButton: null,
  2414. draggable: false,
  2415. SELECTED_COLOR_ELEMENT_ID: 'hatena-star-selected-color',
  2416. PALLET_ELEMENT_ID: 'hatena-star-color-pallet'
  2417. },{
  2418. isSelectedColor : function() {
  2419. return (this.container && this.container.getElementById && this.container.getElementById(Hatena.Star.Pallet.SELECTED_COLOR_ELEMENT_ID)) ? true : false;
  2420. },
  2421. isColorPallet : function() {
  2422. return (this.container && this.container.getElenentById && this.container.getElementById(Hatena.Star.Pallet.PALLET_ELEMENT_ID)) ? true : false;
  2423. },
  2424. showSelectedColor: function(pos, addButton) {
  2425. this.hide();
  2426. this.container.innerHTML = '';
  2427. if (addButton) this.addButton = addButton;
  2428. if (pos) this.selected_color_pos = pos;
  2429. var iframeStyle;
  2430. if (Ten.Browser.isIE) iframeStyle = "width:16px;height:5px;border:1px solid #bbbbbb;";
  2431. else iframeStyle = "width:14px;height:3px;border:1px solid #bbbbbb;";
  2432. this.container.innerHTML = '<iframe id="' + Hatena.Star.Pallet.SELECTED_COLOR_ELEMENT_ID + '" src="' +
  2433. Hatena.Star.BaseURL + 'colorpalette.selected_color?uri=' + encodeURIComponent(this.addButton.entry.uri) +
  2434. '" frameborder="0" border="0" scrolling="no" style="' + iframeStyle + 'position:absolute;margin:0;padding:0;overflow:hidden;"/>';
  2435. var clickhandlerStyle = {
  2436. position: "absolute",
  2437. top: "0px",
  2438. left: "0px",
  2439. width: "16px",
  2440. height: "5px",
  2441. margin: "0",
  2442. padding: "0",
  2443. display: "block",
  2444. cursor: "pointer"
  2445. };
  2446. var E = Ten.Element;
  2447. var div = E('div',{
  2448. title : 'select color',
  2449. alt : 'select color',
  2450. style : clickhandlerStyle
  2451. });
  2452. this.container.appendChild(div);
  2453. this.selectedColor =this.container.childNodes[0];
  2454. this.isNowLoading = true;
  2455. new Ten.Observer(this.selectedColor,'onload',this , 'showSelectedColorDelay');
  2456. new Ten.Observer(this.container.childNodes[1],'onclick',this.addButton,'showColorPallet');
  2457. //this.show(this.selected_color_pos);
  2458. },
  2459. showSelectedColorDelay: function() {
  2460. this.show(this.selected_color_pos);
  2461. this.isNowLoading = false;
  2462. this.screen.style.display = 'none';
  2463. },
  2464. showPallet: function(pos, addButton) {
  2465. this.hide();
  2466. this.container.innerHTML = '';
  2467. if (addButton) this.addButton = addButton;
  2468. if (pos) this.pallet_pos = pos;
  2469. this.addButton.clearSelectedColorTimer();
  2470. this.container.innerHTML = '<iframe id="' + Hatena.Star.Pallet.PALLET_ELEMENT_ID + '" src="' +
  2471. Hatena.Star.BaseURL + 'colorpalette?uri=' + encodeURIComponent(this.addButton.entry.uri) +
  2472. '" frameborder="0" border="0" scrolling="no" style="width:16px;height:51px;overflow:hidden;"/>';
  2473. this.pallet =this.container.childNodes[0];
  2474. this.isNowLoading = true;
  2475. this._pallet_onloaded = 0;
  2476. new Ten.Observer(this.pallet,'onload',this , 'observerSelectColor');
  2477. // new Ten.Observer(this.pallet,'onmouseout',this , 'hidePallet');
  2478. // this.show(this.pallet_pos);
  2479. },
  2480. hidePallet: function() {
  2481. var self = this;
  2482. setTimeout(function() {
  2483. if( self.isColorPallet) self.showSelectedColor();
  2484. },2000);
  2485. },
  2486. selectColor: function(e){
  2487. this.addButton.color = e.target.className.split('-')[2];
  2488. this.showSelectedColor();
  2489. // this.hide();
  2490. },
  2491. observerSelectedColor: function(){
  2492. this.show(this.pallet_pos);
  2493. },
  2494. observerSelectColor: function(e){
  2495. this._pallet_onloaded = (this._pallet_onloaded) ? this._pallet_onloaded : 0;
  2496. this._pallet_onloaded ++;
  2497. if (this._pallet_onloaded == 1){
  2498. this.show(this.pallet_pos);
  2499. this.isNowLoading = false;
  2500. } else if (this._pallet_onloaded > 1) {
  2501. this._pallet_onloaded = 0;
  2502. this.hide();
  2503. this.addButton.addStar(e);
  2504. this._pallet_onloaded = 0;
  2505. // this.hide();
  2506. // this.showSelectedColor();
  2507. // this.isNowLoading = true;
  2508. // this.addButton.hideSelectedColor();
  2509. }
  2510. }
  2511. });
  2512. /* Hatena.Star.CommentButton */
  2513. Hatena.Star.CommentButton = new Ten.Class({
  2514. base: [Hatena.Star.Button],
  2515. initialize: function(entry,container) {
  2516. this.entry = entry;
  2517. this.lastPosition = null;
  2518. this.container = container;
  2519. var src = Hatena.Star.Button.getImgSrc(this.constructor,container);
  2520. var img = Hatena.Star.Button.createButton({
  2521. src: src,
  2522. tabIndex: 0,
  2523. alt: 'Comments',
  2524. title: 'Comments'
  2525. });
  2526. img.className = 'hatena-star-comment-button';
  2527. new Ten.Observer(img,'onclick',this,'showComments');
  2528. new Ten.Observer(img,'onkeyup',this,'handleKeyUp');
  2529. this.img = img;
  2530. this.hide();
  2531. },
  2532. ImgSrcSelector: '.hatena-star-comment-button-image',
  2533. ImgSrc: Hatena.Star.BaseURL + 'images/comment.gif'
  2534. }, {
  2535. handleKeyUp: function(e) {
  2536. if (!e.isKey('enter')) return;
  2537. var pos = Ten.Geometry.getElementPosition(this.img);
  2538. e.mousePosition = function() {return pos};
  2539. this.showComments(e);
  2540. },
  2541. showComments: function(e) {
  2542. if (!this.screen) this.screen = new Hatena.Star.CommentScreen();
  2543. this.screen.bindEntry(this.entry);
  2544. var pos = e.mousePosition();
  2545. pos.y += 25;
  2546. this.screen.showComments(this.entry, pos);
  2547. },
  2548. hide: function() {
  2549. this.img.style.margin = '0';
  2550. this.img.style.display = 'none';
  2551. },
  2552. show: function() {
  2553. this.img.style.margin = '0 3px';
  2554. this.img.style.display = 'inline';
  2555. },
  2556. activate: function() {
  2557. this.show();
  2558. this.constructor = Hatena.Star.CommentButtonActive;
  2559. this.img.src = Hatena.Star.Button.getImgSrc(this.constructor,this.container);
  2560. }
  2561. });
  2562. /* Hatena.Star.CommentButtonActive */
  2563. Hatena.Star.CommentButtonActive = new Ten.Class({
  2564. base: [Hatena.Star.CommentButton],
  2565. ImgSrcSelector: '.hatena-star-comment-button-image-active',
  2566. ImgSrc: Hatena.Star.BaseURL + 'images/comment_active.gif'
  2567. });
  2568. /* Hatena.Star.Star */
  2569. Hatena.Star.Star = new Ten.Class({
  2570. initialize: function(args) {
  2571. if (args.img) {
  2572. this.img = args.img;
  2573. this.name = this.img.getAttribute('alt');
  2574. } else {
  2575. this.name = args.name;
  2576. this.screen_name = args.screen_name || args.name;
  2577. this.profile_icon = args.profile_icon;
  2578. this.container = args.container;
  2579. this.container._starColor = args.color;
  2580. this.color = args.color;
  2581. var img = Hatena.Star.Star.getImage(this.container);
  2582. img.alt = this.screen_name;
  2583. img.title = '';
  2584. if (this.color && this.color != 'yellow' && this.color != 'temp') {
  2585. img.alt = img.alt + ' (' + this.color + ')';
  2586. }
  2587. this.img = img;
  2588. }
  2589. this.quote = args.quote;
  2590. this.entry = args.entry;
  2591. new Ten.Observer(this.img,'onmouseover',this,'showName');
  2592. new Ten.Observer(this.img,'onmouseout',this,'hideName');
  2593. new Ten.Observer(this.img,'onmouseover',this,'setTimer');
  2594. new Ten.Observer(this.img,'onmouseout',this,'clearTimer');
  2595. this.user = new Hatena.Star.User(this.name);
  2596. this.anchor = document.createElement('a');
  2597. this.anchor.href = this.user.userPage();
  2598. this.anchor.appendChild(this.img);
  2599. this.count = args.count;
  2600. if (this.quote && this.quote.length >= 3) {
  2601. this.highlight = new Hatena.Star.Highlight(this.quote);
  2602. }
  2603. },
  2604. gotImage: {},
  2605. getImage: function(container) {
  2606. var color = this.ColorPallet[container._starColor];
  2607. color = (color) ? color : this.ColorPallet['yellow'];
  2608. if (!this.gotImage[color.ImgSrc]) {
  2609. var img = document.createElement('img');
  2610. img.src = Hatena.Star.Button.getImgSrc(color,container);
  2611. img.setAttribute('tabIndex', 0);
  2612. img.className = 'hatena-star-star';
  2613. with (img.style) {
  2614. padding = '0';
  2615. border = 'none';
  2616. }
  2617. this.gotImage[color.ImgSrc] = img;
  2618. }
  2619. return this.gotImage[color.ImgSrc].cloneNode(false);
  2620. },
  2621. // ImgSrcSelector: '.hatena-star-star-image',
  2622. // ImgSrc: Hatena.Star.BaseURL + 'images/star.gif',
  2623. ColorPallet : {
  2624. 'yellow' : {
  2625. ImgSrcSelector: '.hatena-star-star-image',
  2626. ImgSrc: Hatena.Star.BaseURL + 'images/star.gif'
  2627. },
  2628. 'green' : {
  2629. ImgSrcSelector: '.hatena-star-green-star-image',
  2630. ImgSrc: Hatena.Star.BaseURL + 'images/star-green.gif'
  2631. },
  2632. 'red' : {
  2633. ImgSrcSelector: '.hatena-star-red-star-image',
  2634. ImgSrc: Hatena.Star.BaseURL + 'images/star-red.gif'
  2635. },
  2636. 'blue' : {
  2637. ImgSrcSelector: '.hatena-star-blue-star-image',
  2638. ImgSrc: Hatena.Star.BaseURL + 'images/star-blue.gif'
  2639. },
  2640. 'purple' : {
  2641. ImgSrcSelector: '.hatena-star-purple-star-image',
  2642. ImgSrc: Hatena.Star.BaseURL + 'images/star-purple.gif'
  2643. },
  2644. 'temp' : {
  2645. ImgSrcSelector: '.hatena-star-temp-star-image',
  2646. ImgSrc: Hatena.Star.BaseURL + 'images/star-temp.gif'
  2647. }
  2648. }
  2649. },{
  2650. asElement: function() {
  2651. if (this.count && this.count > 1) {
  2652. var c = document.createElement('span');
  2653. c.className = 'hatena-star-inner-count';
  2654. var style = Hatena.Star.InnerCount.getStyle();
  2655. if (style) Ten.Style.applyStyle(c, style);
  2656. c.innerHTML = this.count;
  2657. var s = document.createElement('span');
  2658. s.appendChild(this.anchor);
  2659. s.appendChild(c);
  2660. return s;
  2661. } else {
  2662. return this.anchor;
  2663. }
  2664. },
  2665. setTimer: function(e) {
  2666. var self = this;
  2667. if (this.deleteTimer) return;
  2668. if (!this.name || !this.entry) return;
  2669. if (!Hatena.Visitor) return;
  2670. if (!Hatena.Visitor.RKS) return;
  2671. this.deleteTimer = setTimeout(function() {
  2672. self.deleteTimer = null;
  2673. return; // Chrome popup window crash..
  2674. var uri = Hatena.Star.BaseURL + 'star.deletable.json?name='
  2675. + self.name;
  2676. new Ten.JSONP(uri, self, 'confirmDeletable');
  2677. }, 4000);
  2678. },
  2679. clearTimer: function() {
  2680. if (this.deleteTimer) {
  2681. clearTimeout(this.deleteTimer);
  2682. this.deleteTimer = null;
  2683. }
  2684. },
  2685. confirmDeletable: function(res) {
  2686. if (res.result && res.message && confirm(res.message)) {
  2687. this.deleteStar();
  2688. }
  2689. },
  2690. deleteStar: function() {
  2691. var uri = Hatena.Star.BaseURL + 'star.delete.json?name='
  2692. + this.name + '&uri=' + encodeURIComponent(this.entry.uri)
  2693. + '&rks=' + Hatena.Visitor.RKS;
  2694. if (this.color) uri += '&color=' + this.color;
  2695. if (this.quote) {
  2696. uri += '&quote=' + encodeURIComponent(this.quote);
  2697. }
  2698. new Ten.JSONP(uri, this, 'receiveDeleteResult');
  2699. },
  2700. receiveDeleteResult: function(res) {
  2701. if (res && res.result) {
  2702. this.anchor.style.display = 'none';
  2703. }
  2704. },
  2705. showName: function(e) {
  2706. if (!this.screen) this.screen = new Hatena.Star.NameScreen();
  2707. var pos = e.mousePosition();
  2708. pos.x += 10;
  2709. pos.y += 25;
  2710. if (this.highlight) this.highlight.show();
  2711. this.screen.showName(this.screen_name, this.quote, pos, this.profile_icon);
  2712. },
  2713. hideName: function() {
  2714. if (!this.screen) return;
  2715. if (this.highlight) this.highlight.hide();
  2716. this.screen.hide();
  2717. }
  2718. });
  2719. /* Hatena.Star.Highlight */
  2720. Hatena.Star.Highlight = new Ten.Class({
  2721. base: [Ten.Highlight],
  2722. ClassName: 'hatena-star-highlight'
  2723. });
  2724. /* from Hatena::Bookmark */
  2725. /* thx id:amachang / id:Yuichirou / id:os0x */
  2726. Hatena.Star.Highlight._show = Hatena.Star.Highlight.show;
  2727. Hatena.Star.Highlight.show = function() {
  2728. setTimeout(function() {
  2729. if (Hatena.Star.Highlight.asyncMakeTextNode)
  2730. Hatena.Star.Highlight.asyncMakeTextNode();
  2731. Hatena.Star.Highlight._show();
  2732. }, 10);
  2733. };
  2734. Hatena.Star.Highlight._makeTextNodes = Hatena.Star.Highlight.makeTextNodes;
  2735. Hatena.Star.Highlight.makeTextNodes = function(c) {
  2736. if (c.asyncMakeTextNode || c.textNodes || c.textNodePositions || c.documentText) return;
  2737. if (Ten.Highlight.highlighted) Ten.Highlight.highlighted.hide();
  2738. if (!c.loaded && !c.prototype._show) {
  2739. c.prototype._show = c.prototype.show;
  2740. c.prototype.show = function() {
  2741. c.prototype.show = c.prototype._show;
  2742. var _self = this;
  2743. var exec = function() {
  2744. if (c.asyncMakeTextNode) {
  2745. c.asyncMakeTextNode();
  2746. }
  2747. _self.show();
  2748. };
  2749. exec();
  2750. }
  2751. }
  2752. c.asyncMakeTextNode = function() {
  2753. var textNodes = c.textNodes = [];
  2754. var textNodePositions = c.textNodePositions = [];
  2755. var pos = 0;
  2756. if (Ten.Browser.isSupportsXPath) {
  2757. var result = document.evaluate('descendant::text()', document.body, null, 7, null);
  2758. for (var i = 0, len = result.snapshotLength; i < len ; i ++) {
  2759. var node = result.snapshotItem(i);
  2760. textNodes.push(node);
  2761. textNodePositions.push(pos);
  2762. pos += node.length;
  2763. }
  2764. c.documentText = document.body.textContent || document.body.innerText;
  2765. } else {
  2766. var isIE = Ten.Browser.isIE;
  2767. var texts = [];
  2768. var fn = function(node, parent) {
  2769. if (isIE && parent && parent != node.parentNode) return;
  2770. if (node.nodeType == 3) {
  2771. textNodes.push(node);
  2772. texts.push(node.nodeValue);
  2773. textNodePositions.push(pos);
  2774. pos += node.nodeValue.length;
  2775. } else {
  2776. var childNodes = node.childNodes;
  2777. for (var i = 0, len = childNodes.length; i < len; ++i) {
  2778. fn(childNodes[i], node);
  2779. }
  2780. }
  2781. };
  2782. fn(document.body);
  2783. c.documentText = texts.join('');
  2784. }
  2785. c.loaded = true;
  2786. c.asyncMakeTextNode = null;
  2787. };
  2788. return;
  2789. }
  2790. /* Hatena.Star.InnerCount */
  2791. Hatena.Star.InnerCount = new Ten.Class({
  2792. initialize: function(count, e, color) {
  2793. this.count = count;
  2794. this.entry = e;
  2795. this.color = (color) ? color : '';
  2796. var c = document.createElement('span');
  2797. c.className = Hatena.Star.InnerCount.className(this.color);
  2798. c.setAttribute('tabIndex', 0);
  2799. var style = Hatena.Star.InnerCount.getStyle(color);
  2800. if (style) Ten.Style.applyStyle(c, style);
  2801. c.style.cursor = 'pointer';
  2802. c.innerHTML = count;
  2803. new Ten.Observer(c,'onclick',this,'showInnerStars');
  2804. new Ten.Observer(c,'onkeyup',this,'handleKeyUp');
  2805. this.container = c;
  2806. },
  2807. selectorName: function(color) {
  2808. color = (color) ? color : '';
  2809. var base = '.hatena-star-inner-count';
  2810. if (color) base += '-';
  2811. return base + color;
  2812. },
  2813. getStyle: function(color) {
  2814. color = (color) ? color : '';
  2815. var c = Hatena.Star.InnerCount;
  2816. if (Ten.Style.getGlobalRule(c.selectorName(color))) {
  2817. return null;
  2818. } else {
  2819. color = (color) ? color : 'yellow';
  2820. var fontColor = Hatena.Star.InnerCount.fontColor[color];
  2821. if (fontColor) c.style.color = fontColor;
  2822. return c.style;
  2823. }
  2824. },
  2825. className: function(color){
  2826. return Hatena.Star.InnerCount.selectorName(color).substr(1);
  2827. },
  2828. style: {
  2829. fontWeight: 'bold',
  2830. fontSize: '80%',
  2831. fontFamily: '"arial", sans-serif',
  2832. margin: '0 2px'
  2833. },
  2834. fontColor: {
  2835. yellow: '#f4b128',
  2836. green: '#8ed701',
  2837. red: '#ea475c',
  2838. purple: '#cd34e3',
  2839. blue: '#57b1ff'
  2840. }
  2841. },{
  2842. asElement: function() {
  2843. return this.container;
  2844. },
  2845. handleKeyUp: function(e) {
  2846. if (!e.isKey('enter')) return;
  2847. this.showInnerStars(e);
  2848. },
  2849. showInnerStars: function() {
  2850. var url = Hatena.Star.BaseURL + 'entry.json?uri=' +
  2851. encodeURIComponent(this.entry.uri);
  2852. new Ten.JSONP(url, this, 'receiveStarEntry');
  2853. },
  2854. receiveStarEntry: function(res) {
  2855. var se = res.entries[0];
  2856. var e = this.entry;
  2857. if (encodeURIComponent(se.uri) != encodeURIComponent(e.uri)) return;
  2858. e.flushStars();
  2859. e.bindStarEntry(se);
  2860. e.addAddButton();
  2861. e.showStars();
  2862. }
  2863. });
  2864. /* Hatena.Star.Comment */
  2865. Hatena.Star.Comment = new Ten.Class({
  2866. initialize: function(args) {
  2867. this.name = args.name;
  2868. this.body = args.body;
  2869. this.id = args.id;
  2870. }
  2871. },{
  2872. asElement: function() {
  2873. var div = new Ten.Element('div', {
  2874. style: {
  2875. margin: '0px 0',
  2876. padding: '5px 0 5px 22px',
  2877. lineHeight: '1.3',
  2878. borderBottom: '1px solid #ddd'
  2879. }
  2880. });
  2881. var ico = Hatena.Star.User.getProfileIcon(this.name);
  2882. ico.style.marginLeft = '-22px';
  2883. div.appendChild(ico);
  2884. var span = document.createElement('span');
  2885. with(span.style) {
  2886. fontSize = '90%';
  2887. }
  2888. span.innerHTML = this.body;
  2889. div.appendChild(span);
  2890. if (this.deletable()) {
  2891. new Hatena.Star.CommentDeleteButton(div, this);
  2892. }
  2893. return div;
  2894. },
  2895. deletable: function() {
  2896. if (typeof(Hatena.Visitor) != 'undefined' &&
  2897. typeof(Hatena.Visitor.name) != 'undefined' &&
  2898. Hatena.Visitor.name == this.name) {
  2899. return true;
  2900. }
  2901. return false;
  2902. },
  2903. deleteComment: function(callback) {
  2904. if (!this.deletable()) return;
  2905. if (!this.id) return;
  2906. if (!Hatena.Visitor.RKS) return;
  2907. var uri = Hatena.Star.BaseURL + 'comment.delete.json?comment_id=' + this.id
  2908. + '&rks=' + Hatena.Visitor.RKS;
  2909. new Ten.JSONP(uri, callback);
  2910. }
  2911. });
  2912. /* Hatena.Star.CommentDeleteButton */
  2913. Hatena.Star.CommentDeleteButton = new Ten.Class({
  2914. initialize: function(parent, comment) {
  2915. this.parent = parent;
  2916. this.comment = comment;
  2917. this.button = new Ten.Element('img', {
  2918. src: Hatena.Star.BaseURL + 'images/delete2.gif',
  2919. alt: 'Delete',
  2920. title: 'Delete',
  2921. style: {
  2922. margin: '0 3px',
  2923. verticalAlign: 'middle',
  2924. cursor: 'pointer',
  2925. display: 'none'
  2926. }
  2927. });
  2928. new Ten.Observer(this.parent, 'onmouseover', this, 'showButton');
  2929. new Ten.Observer(this.button, 'onclick', this, 'deleteComment');
  2930. this.parent.appendChild(this.button);
  2931. }
  2932. }, {
  2933. showButton: function() {
  2934. this.button.style.display = 'inline';
  2935. if (!this.hideObserver) {
  2936. this.hideObserver = new Ten.Observer(this.parent, 'onmouseout', this, 'hideButton');
  2937. }
  2938. },
  2939. hideButton: function() {
  2940. this.button.style.display = 'none';
  2941. },
  2942. deleteComment: function() {
  2943. var self = this;
  2944. this.comment.deleteComment(function(res) {
  2945. if (res.result) self.parent.style.display = 'none';
  2946. });
  2947. }
  2948. });
  2949. /* Hatena.Star.NameScreen */
  2950. Hatena.Star.NameScreen = new Ten.Class({
  2951. base: [Ten.SubWindow],
  2952. style: {
  2953. padding: '2px',
  2954. textAlign: 'center'
  2955. },
  2956. containerStyle: {
  2957. textAlign: 'left',
  2958. margin: 0,
  2959. padding: 0
  2960. },
  2961. quoteStyle: {
  2962. margin: '.3em .2em',
  2963. padding: '.5em 0 0 0',
  2964. fontSize: '80%',
  2965. borderTop: '1px solid #bbb',
  2966. color: '#777'
  2967. },
  2968. handleStyle: null,
  2969. showScreen: false,
  2970. closeButton: null,
  2971. draggable: false
  2972. },{
  2973. showName: function(name, quote, pos, src) {
  2974. this.container.innerHTML = '';
  2975. this.container.appendChild(Hatena.Star.User.getProfileIcon(name, src));
  2976. this.container.appendChild(document.createTextNode(name));
  2977. if (quote) {
  2978. var blockquote = document.createElement('blockquote');
  2979. Ten.Style.applyStyle(blockquote, this.constructor.quoteStyle);
  2980. blockquote.innerHTML = '&quot; ' + quote + ' &quot;';
  2981. this.container.appendChild(blockquote);
  2982. }
  2983. this.show(pos);
  2984. }
  2985. });
  2986. /* Hatena.LoginWindow */
  2987. Hatena.LoginWindow = new Ten.Class({
  2988. base: [Ten.SubWindow],
  2989. style: {
  2990. padding: '2px',
  2991. textAlign: 'left',
  2992. borderRadius: '6px',
  2993. MozBorderRadius: '6px'
  2994. },
  2995. handleStyle: {
  2996. position: 'absolute',
  2997. top: '0px',
  2998. left: '0px',
  2999. backgroundColor: '#f3f3f3',
  3000. borderBottom: '1px solid #bbb',
  3001. width: '100%',
  3002. height: '30px',
  3003. borderRadius: '6px 6px 0 0',
  3004. MozBorderRadius: '6px 6px 0 0'
  3005. }
  3006. },{
  3007. addLoginForm: function(html) {
  3008. this.container.innerHTML = html;
  3009. var form = this.container.getElementsByTagName('form')[0];
  3010. var input = new Ten.Element('input',{
  3011. type: 'hidden',
  3012. name: 'location',
  3013. value: document.location.href
  3014. });
  3015. form.appendChild(input);
  3016. }
  3017. });
  3018. /* Hatena.Star.AlertScreen */
  3019. Hatena.Star.AlertScreen = new Ten.Class({
  3020. base: [Ten.SubWindow],
  3021. style: {
  3022. padding: '2px',
  3023. textAlign: 'center',
  3024. borderRadius: '6px',
  3025. MozBorderRadius: '6px',
  3026. width: '240px',
  3027. height: '120px'
  3028. },
  3029. handleStyle: {
  3030. position: 'absolute',
  3031. top: '0px',
  3032. left: '0px',
  3033. backgroundColor: '#f3f3f3',
  3034. borderBottom: '1px solid #bbb',
  3035. width: '100%',
  3036. height: '30px',
  3037. borderRadius: '6px 6px 0 0',
  3038. MozBorderRadius: '6px 6px 0 0'
  3039. }
  3040. },{
  3041. showAlert: function(msg, pos) {
  3042. this.container.innerHTML = msg;
  3043. var win = Ten.Geometry.getWindowSize();
  3044. var scr = Ten.Geometry.getScroll();
  3045. var w = parseInt(this.constructor.style.width) + 20;
  3046. if (pos.x + w > scr.x + win.w) pos.x = win.w + scr.x - w;
  3047. this.show(pos);
  3048. }
  3049. });
  3050. /* Hatena.Star.CommentScreen */
  3051. Hatena.Star.CommentScreen = new Ten.Class({
  3052. base: [Ten.SubWindow],
  3053. initialize: function() {
  3054. var self = this.constructor.SUPER.call(this);
  3055. if (!self.commentsContainer) self.addCommentsContainer();
  3056. return self;
  3057. },
  3058. style: {
  3059. width: '280px',
  3060. height: '280px',
  3061. // overflow: 'auto',
  3062. // overflowX: 'hidden',
  3063. backgroundColor: '#f3f3f3',
  3064. padding: '0',
  3065. textAlign: 'center',
  3066. borderRadius: '6px',
  3067. MozBorderRadius: '6px'
  3068. },
  3069. handleStyle: {
  3070. position: 'absolute',
  3071. top: '0px',
  3072. left: '0px',
  3073. backgroundColor: '#f3f3f3',
  3074. borderBottom: '1px solid #bbb',
  3075. width: '100%',
  3076. height: '30px',
  3077. borderRadius: '6px 6px 0 0',
  3078. MozBorderRadius: '6px 6px 0 0'
  3079. },
  3080. containerStyle: {
  3081. backgroundColor: '#fff',
  3082. overflow: 'auto',
  3083. overflowX: 'hidden',
  3084. height: '248px',
  3085. margin: '32px 0 0 0',
  3086. textAlign: 'left',
  3087. padding: '0 10px'
  3088. },
  3089. getLoadImage: function() {
  3090. var img = document.createElement('img');
  3091. img.src = Hatena.Star.BaseURL + 'images/load.gif';
  3092. img.setAttribute('alt', 'Loading');
  3093. with (img.style) {
  3094. verticalAlign = 'middle';
  3095. margin = '0 2px';
  3096. }
  3097. return img;
  3098. }
  3099. },{
  3100. addCommentsContainer: function() {
  3101. var div = document.createElement('div');
  3102. Ten.Style.applyStyle(div, {
  3103. margin: '0'
  3104. });
  3105. this.container.appendChild(div);
  3106. this.commentsContainer = div;
  3107. },
  3108. showComments: function(e, pos) {
  3109. var comments = e.comments;
  3110. if (!comments) comments = [];
  3111. this.commentsContainer.innerHTML = '';
  3112. var cc = this.commentsContainer;
  3113. for (var i=0; i<comments.length; i++) {
  3114. cc.appendChild(comments[i].asElement());
  3115. }
  3116. if (e.starEntry && !e.can_comment) {
  3117. this.hideCommentForm();
  3118. } else {
  3119. this.addCommentForm();
  3120. }
  3121. var win = Ten.Geometry.getWindowSize();
  3122. var scr = Ten.Geometry.getScroll();
  3123. var w = parseInt(this.constructor.style.width) + 20;
  3124. var h = parseInt(this.constructor.style.height) + 20;
  3125. if (pos.x + w > scr.x + win.w) pos.x = win.w + scr.x - w;
  3126. if (pos.y + h > scr.y + win.h) pos.y = win.h + scr.y - h;
  3127. this.show(pos);
  3128. },
  3129. bindEntry: function(e) {
  3130. this.entry = e;
  3131. },
  3132. resizeCommentInput: function(e) {
  3133. var ci = this.commentInput;
  3134. if (ci.scrollHeight && (ci.clientHeight < ci.scrollHeight) && (ci.scrollHeight < 100)) {
  3135. var h = ci.scrollHeight + 10;
  3136. ci.style.height = h + 'px';
  3137. }
  3138. },
  3139. sendComment: function(e) {
  3140. var ci = this.commentInput;
  3141. var body = ci.value;
  3142. if (!body) return;
  3143. ci.disabled = 'true';
  3144. this.showLoadImage();
  3145. var url = Hatena.Star.BaseURL + 'comment.add.json?body=' + encodeURIComponent(body) +
  3146. '&uri=' + encodeURIComponent(this.entry.uri) +
  3147. '&title=' + encodeURIComponent(this.entry.title);
  3148. if (Hatena.Visitor && Hatena.Visitor.RKS) {
  3149. url += '&rks=' + Hatena.Visitor.RKS;
  3150. }
  3151. new Ten.JSONP(url, this, 'receiveResult');
  3152. },
  3153. handleKeyPress: function(e) {
  3154. if (e.isKey('enter') && e.ctrlKey) {
  3155. this.sendComment();
  3156. }
  3157. },
  3158. receiveResult: function(args) {
  3159. if (!args.name || !args.body) return;
  3160. this.commentInput.value = '';
  3161. this.commentInput.disabled = '';
  3162. this.commentInput.style.height = '3em';
  3163. this.commentInput.focus();
  3164. this.hideLoadImage();
  3165. var com = new Hatena.Star.Comment(args);
  3166. this.entry.addComment(com);
  3167. this.commentsContainer.appendChild(com.asElement());
  3168. },
  3169. showLoadImage: function() {
  3170. if (!this.loadImage) return;
  3171. this.loadImage.style.display = 'inline';
  3172. },
  3173. hideLoadImage: function() {
  3174. if (!this.loadImage) return;
  3175. this.loadImage.style.display = 'none';
  3176. },
  3177. hideCommentForm: function() {
  3178. if (!this.commentForm) return;
  3179. this.commentForm.style.display = 'none';
  3180. },
  3181. addCommentForm: function() {
  3182. if (this.commentForm) {
  3183. this.commentForm.style.display = 'block';
  3184. return;
  3185. }
  3186. var form = new Ten.Element('div', {
  3187. style : {
  3188. margin: '0px 0',
  3189. padding: '5px 0'
  3190. }
  3191. });
  3192. this.container.appendChild(form);
  3193. this.commentForm = form;
  3194. var input = new Ten.Element('textarea', {
  3195. style: {
  3196. width: '220px',
  3197. height: '3em',
  3198. border: '1px solid #bbb',
  3199. padding: '3px',
  3200. overflow: 'auto'
  3201. }
  3202. });
  3203. form.appendChild(input);
  3204. this.commentInput = input;
  3205. this.commentInputHeight = input.scrollHeight;
  3206. form.appendChild(new Ten.Element('br'));
  3207. var submit = new Ten.Element('input', {
  3208. type: 'button',
  3209. value: 'send'
  3210. });
  3211. form.appendChild(submit);
  3212. this.submit = submit;
  3213. var img = this.constructor.getLoadImage();
  3214. this.loadImage = img;
  3215. this.hideLoadImage();
  3216. form.appendChild(img);
  3217. new Ten.Observer(submit,'onclick',this,'sendComment');
  3218. new Ten.Observer(input,'onkeypress',this,'handleKeyPress');
  3219. new Ten.Observer(input,'onkeyup',this,'resizeCommentInput');
  3220. }
  3221. });
  3222. /* Hatena.Star.EntryLoader */
  3223. Hatena.Star.EntryLoader = new Ten.Class({
  3224. initialize: function() {
  3225. var c = Hatena.Star.EntryLoader;
  3226. c.loadNewEntries();
  3227. c.finishLoad();
  3228. },
  3229. loadNewEntries: function(node) {
  3230. var c = Hatena.Star.EntryLoader;
  3231. if (!node) node = document.body;
  3232. var entries_org = c.entries;
  3233. c.entries = null;
  3234. var entries;
  3235. if (c.headerTagAndClassName) {
  3236. entries = c.loadEntriesByHeader(node);
  3237. } else if (c.loadEntries) {
  3238. entries = c.loadEntries(node);
  3239. } else {
  3240. entries = c.loadEntriesByConfig(node);
  3241. }
  3242. c.entries = [];
  3243. if (entries && typeof(entries.length) == 'number') {
  3244. for (var i = 0; i < entries.length; i++) {
  3245. var e = new Hatena.Star.Entry(entries[i]);
  3246. e.showButtons();
  3247. c.entries.push(e);
  3248. }
  3249. }
  3250. c.getStarEntries();
  3251. if (entries_org) {
  3252. c.entries.push(entries_org);
  3253. c.entries = Ten.Array.flatten(c.entries);
  3254. }
  3255. },
  3256. createStarContainer: function() {
  3257. var sc = document.createElement('span');
  3258. sc.className = 'hatena-star-star-container';
  3259. return sc;
  3260. },
  3261. createCommentContainer: function() {
  3262. var cc = document.createElement('span');
  3263. cc.className = 'hatena-star-comment-container';
  3264. return cc;
  3265. },
  3266. scrapeTitle: function(node) {
  3267. var rval = [];
  3268. (function (node) {
  3269. if (node.className == 'sanchor' || node.className == 'timestamp' ||
  3270. node.className == 'edit') {
  3271. return;
  3272. } else if (node.nodeType == 3 && !/\S/.test(node.nodeValue)) {
  3273. return;
  3274. }
  3275. var cn = node.childNodes;
  3276. if (cn) {
  3277. for (var i = 0; i < cn.length; i++) {
  3278. arguments.callee.call(this, cn[i]);
  3279. }
  3280. }
  3281. var nodeValue = node.nodeValue;
  3282. if (typeof(nodeValue) == 'string') {
  3283. rval.push(nodeValue);
  3284. }
  3285. })(node);
  3286. var title = rval.join('');
  3287. title = title.replace(/^[\s\n\r]+/, '');
  3288. title = title.replace(/[\s\n\r]+$/, '');
  3289. title = title.replace(/[\n\r]/g, '');
  3290. return title;
  3291. },
  3292. getHeaders: function(node) {
  3293. var t = Hatena.Star.EntryLoader.headerTagAndClassName;
  3294. if (typeof(t[0]) == 'string') {
  3295. return Ten.DOM.getElementsByTagAndClassName(t[0],t[1],node || document);
  3296. } else {
  3297. var elements = [];
  3298. for (var i = 0; i < t.length; i++) {
  3299. var elems = Ten.DOM.getElementsByTagAndClassName(t[i][0],t[i][1],node || document);
  3300. for (var j = 0; j < elems.length; j++) {
  3301. elements.push(elems[j]);
  3302. }
  3303. }
  3304. return elements;
  3305. }
  3306. },
  3307. loadEntriesByHeader: function(node) {
  3308. var c = Hatena.Star.EntryLoader;
  3309. if (c.entries) return c.entries;
  3310. var entries = [];
  3311. var headers = c.getHeaders(node);
  3312. for (var i = 0; i < headers.length; i++) {
  3313. var header = headers[i];
  3314. var a = header.getElementsByTagName('a')[0];
  3315. if (!a) continue;
  3316. var uri = a.href;
  3317. var title = '';
  3318. // Ten.DOM.removeEmptyTextNodes(header);
  3319. var cns = header.childNodes;
  3320. title = c.scrapeTitle(header);
  3321. var cc = c.createCommentContainer();
  3322. header.appendChild(cc);
  3323. var sc = c.createStarContainer();
  3324. header.appendChild(sc);
  3325. entries.push({
  3326. uri: uri,
  3327. title: title,
  3328. star_container: sc,
  3329. comment_container: cc
  3330. });
  3331. }
  3332. c.entries = entries;
  3333. return entries;
  3334. },
  3335. loadEntriesByConfig: function(node) {
  3336. var c = Hatena.Star.EntryLoader;
  3337. if (c.entries) return c.entries;
  3338. var entries = [];
  3339. if (!Hatena.Star.SiteConfig) return null;
  3340. var conf = Hatena.Star.SiteConfig.entryNodes;
  3341. if (!conf) return null;
  3342. for (var eselector in conf) {
  3343. var enodes = Ten.Selector.getElementsBySelector(eselector,node);
  3344. if (!enodes) continue;
  3345. var sels = conf[eselector];
  3346. if (!Ten.Array.isArray(sels)) sels = [sels];
  3347. for (var i = 0; i < sels.length; i++) {
  3348. var selectors = sels[i];
  3349. for (var j = 0; j < enodes.length; j++) {
  3350. var enode = enodes[j];
  3351. var e = c.getEntryByENodeAndSelectors(enode, selectors);
  3352. if (e) entries.push(e);
  3353. }
  3354. }
  3355. }
  3356. c.entries = entries;
  3357. return entries;
  3358. },
  3359. getEntryByENodeAndSelectors: function(enode,selectors) {
  3360. var c = Hatena.Star.EntryLoader;
  3361. var e = {entryNode: enode};
  3362. var a = c.getElementByConfigSelector(selectors.uri, enode);
  3363. if (!a) return null;
  3364. e.uri = a.href;
  3365. if (!e.uri) return null;
  3366. var title = c.getElementByConfigSelector(selectors.title, enode);
  3367. if (typeof(title) == 'string') {
  3368. e.title = title;
  3369. } else {
  3370. e.title = c.scrapeTitle(title) || title.title || title.alt || '';
  3371. }
  3372. var cont = c.getElementByConfigSelector(selectors.container, enode);
  3373. if (!cont) return null;
  3374. e.comment_container = c.createCommentContainer();
  3375. cont.appendChild(e.comment_container);
  3376. e.star_container = c.createStarContainer();
  3377. cont.appendChild(e.star_container);
  3378. return e;
  3379. },
  3380. getElementByConfigSelector: function(selector,parent) {
  3381. if (selector.match(/^document\.(location|title)$/)) {
  3382. return document[RegExp.$1];
  3383. } else if (selector == 'window.location') {
  3384. return window.location;
  3385. } else if (selector == 'parent') {
  3386. return parent;
  3387. } else {
  3388. return Ten.Selector.getElementsBySelector(selector,parent)[0];
  3389. }
  3390. },
  3391. finishLoad: function() {
  3392. var c = Hatena.Star.EntryLoader;
  3393. c.dispatchEvent('load');
  3394. c.loaded = true;
  3395. },
  3396. getStarEntries: function() {
  3397. var c = Hatena.Star.EntryLoader;
  3398. var entries = c.entries;
  3399. if (!entries.length) return;
  3400. var url = Hatena.Star.BaseURL + 'entries.json?';
  3401. for (var i = 0; i < entries.length; i++) {
  3402. if (url.length > Ten.JSONP.MaxBytes) {
  3403. new Ten.JSONP(url, c, 'receiveStarEntries');
  3404. url = Hatena.Star.BaseURL + 'entries.json?';
  3405. }
  3406. url += 'uri=' + encodeURIComponent(entries[i].uri) + '&';
  3407. }
  3408. if (!Hatena.Visitor) url += 'timestamp=1';
  3409. new Ten.JSONP(url, c, 'receiveStarEntries');
  3410. },
  3411. receiveStarEntries: function(res) {
  3412. var c = Hatena.Star.EntryLoader;
  3413. var entries = res.entries;
  3414. if (!entries) entries = [];
  3415. for (var i = 0, cLen = c.entries.length ; i < cLen ; i++) {
  3416. var e = c.entries[i];
  3417. if (e.starEntry) continue;
  3418. if (!e.eURI) e.eURI = encodeURIComponent(e.uri);
  3419. for (var j = 0, eLen = entries.length ; j < eLen ; j++) {
  3420. var se = entries[j];
  3421. if (!se.uri) continue;
  3422. if ((se.eURI || (se.eURI = encodeURIComponent(se.uri))) == e.eURI) {
  3423. e.bindStarEntry(se);
  3424. entries.splice(j,1);
  3425. break;
  3426. }
  3427. }
  3428. if (typeof(e.can_comment) == 'undefined') {
  3429. e.setCanComment(res.can_comment);
  3430. }
  3431. e.showStars();
  3432. e.showCommentButton();
  3433. }
  3434. if (res.rks) {
  3435. if (!Hatena.Visitor || typeof(Hatena.Visitor) == 'undefined') {
  3436. Hatena.Visitor = {};
  3437. }
  3438. if (!Hatena.Visitor.RKS) Hatena.Visitor.RKS = res.rks;
  3439. }
  3440. },
  3441. loaded: false,
  3442. entries: null
  3443. });
  3444. Ten.EventDispatcher.implementEventDispatcher(Hatena.Star.EntryLoader);
  3445. /* Hatena.Star.ConfigLoader */
  3446. Hatena.Star.ConfigLoader = new Ten.Class({
  3447. initialize: function() {
  3448. var c = Hatena.Star.ConfigLoader;
  3449. if (c.loaded) return true;
  3450. if (Hatena.Star.SiteConfig ||
  3451. Hatena.Star.EntryLoader.headerTagAndClassName ||
  3452. Hatena.Star.EntryLoader.loadEntries) {
  3453. c.finishLoad();
  3454. return true;
  3455. } else {
  3456. c.loadConfig();
  3457. return null;
  3458. }
  3459. },
  3460. loadConfig: function() {
  3461. var uri = Hatena.Star.BaseURL + 'siteconfig.json?host=' + location.hostname;
  3462. new Ten.JSONP(uri, Hatena.Star.ConfigLoader, 'setConfig');
  3463. },
  3464. setConfig: function(data) {
  3465. var host = location.hostname;
  3466. var conf = data[host];
  3467. if (!conf && host.match(/^[\w-]+(\..+)$/)) {
  3468. var host = '*' + RegExp.$1;
  3469. conf = data[host] || [];
  3470. }
  3471. var path = location.pathname;
  3472. for (var i = 0; i < conf.length; i++) {
  3473. var c = conf[i];
  3474. if (path.match(new RegExp(c.path))) {
  3475. Hatena.Star.SiteConfig = c;
  3476. Hatena.Star.ConfigLoader.finishLoad();
  3477. return true;
  3478. }
  3479. }
  3480. Hatena.Star.ConfigLoader.finishLoad();
  3481. return null;
  3482. },
  3483. finishLoad: function() {
  3484. var c = Hatena.Star.ConfigLoader;
  3485. c.dispatchEvent('load');
  3486. c.loaded = true;
  3487. },
  3488. loaded: false
  3489. });
  3490. Ten.EventDispatcher.implementEventDispatcher(Hatena.Star.ConfigLoader);
  3491. /* Hatena.Star.WindowObserver */
  3492. Hatena.Star.WindowObserver = new Ten.Class({
  3493. initialize: function() {
  3494. var c = Hatena.Star.WindowObserver;
  3495. if (c.observer) return;
  3496. Hatena.Star.loaded = true;
  3497. if (Hatena.Star.onLoadFunctions) {
  3498. for (var i = 0; i < Hatena.Star.onLoadFunctions.length; i++) {
  3499. Hatena.Star.onLoadFunctions[i]();
  3500. }
  3501. Hatena.Star.onLoadFunctions = [];
  3502. }
  3503. c.observer = Ten.DOM.addEventListener('onload', function() {
  3504. c.finishLoad();
  3505. if (!Ten.Browser.isFirefox || parseInt(Ten.Browser.version) > 2) {
  3506. new Ten.Observer(document.body, 'onclick', function(event){
  3507. try{
  3508. var pallet = new Hatena.Star.Pallet();
  3509. pallet.hide();
  3510. } catch(e) {}
  3511. });
  3512. }
  3513. Hatena.Star.ConfigLoader.addEventListener('load', function() {
  3514. new Hatena.Star.EntryLoader();
  3515. });
  3516. new Hatena.Star.ConfigLoader();
  3517. });
  3518. },
  3519. finishLoad: function() {
  3520. var c = Hatena.Star.WindowObserver;
  3521. c.dispatchEvent('load');
  3522. c.loaded = true;
  3523. },
  3524. observer: null
  3525. });
  3526. Ten.EventDispatcher.implementEventDispatcher(Hatena.Star.WindowObserver);
  3527. /* start */
  3528. new Hatena.Star.WindowObserver();
  3529. /* Hatena.Star.SiteConfig */
  3530. /* sample configuration for Hatena Diary */
  3531. /*
  3532. // Hatena.Star.SiteConfig = {
  3533. // entryNodes: {
  3534. // 'div.section': {
  3535. // uri: 'h3 a',
  3536. // title: 'h3',
  3537. // container: 'h3'
  3538. // }
  3539. // }
  3540. // };
  3541. */
  3542. /*
  3543. =head1 NAME
  3544. HatenaStar.js - Make your blog more fun!
  3545. =head1 SYNOPSIS
  3546. In your blog header or body,
  3547. <script type="text/javascript" src="http://s.hatena.com/js/HatenaStar.js"></script>
  3548. You may have to configure these settings for your blog if you don't use
  3549. major blog hosting service.
  3550. <script type="text/javascript" src="http://s.hatena.com/js/HatenaStar.js"></script>
  3551. <script type="text/javascript>
  3552. Hatena.Star.SiteConfig = {
  3553. entryNodes: {
  3554. 'div.entry': {
  3555. uri: 'a.permalink',
  3556. title: 'h3.title',
  3557. container: 'h3.title'
  3558. }
  3559. }
  3560. };
  3561. </script>
  3562. You can also register your Hatena ID by adding your blog's url at
  3563. http://s.hatena.com/ (English)
  3564. http://s.hatena.ne.jp/ (Japanese)
  3565. You can receive comments from your favorite users if you register your ID.
  3566. =head1 SITE CONFIGURATION
  3567. Site configuration style changed in Sep. 2007. To configure Hatena Star
  3568. for your site, please specify your html element structure as below.
  3569. <script type="text/javascript>
  3570. Hatena.Star.SiteConfig = {
  3571. entryNodes: {
  3572. 'div.entry': {
  3573. uri: 'a.permalink',
  3574. title: 'h3.title',
  3575. container: 'h3.title'
  3576. }
  3577. }
  3578. };
  3579. </script>
  3580. (to be continued..)
  3581. =head1 CUTOMIZE IMAGES
  3582. You can customize the default image settings for your page if you want.
  3583. // change the images of stars, buttons by editing your style sheets
  3584. .hatena-star-add-button-image {
  3585. background-image: url(http://exapmle.com/add.gif);
  3586. }
  3587. .hatena-star-comment-button-image {
  3588. background-image: url(http://exapmle.com/comment.gif);
  3589. }
  3590. .hatena-star-star-image {
  3591. background-image: url(http://exapmle.com/star.gif);
  3592. }
  3593. =head1 CHANGES
  3594. Please see E<lt>http://s.hatena.com/js/Hatena/Star/HatenaStar.ChangesE<gt>.
  3595. =head1 AUTHOR
  3596. Junya Kondo, E<lt>http://d.hatena.ne.jp/jkondo/E<gt>
  3597. Yuichi Tateno, motemen, nagayama
  3598. =head1 COPYRIGHT AND LICENSE
  3599. Copyright (C) Hatena Inc. All Rights Reserved.
  3600. This library is free software; you may redistribute it and/or modify
  3601. it under the same terms as the Perl programming language.
  3602. =cut
  3603. */
  3604. Hatena.Star.BaseURL = 'http://s.hatena.ne.jp/';