OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 /** | 5 /** |
6 * @fileoverview | 6 * @fileoverview |
7 * A module that contains basic utility components and methods for the | 7 * A module that contains basic utility components and methods for the |
8 * chromoting project | 8 * chromoting project |
9 * | 9 * |
10 */ | 10 */ |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
55 return callstack.join('\n'); | 55 return callstack.join('\n'); |
56 }; | 56 }; |
57 | 57 |
58 /** | 58 /** |
59 * @interface | 59 * @interface |
60 */ | 60 */ |
61 base.Disposable = function() {}; | 61 base.Disposable = function() {}; |
62 base.Disposable.prototype.dispose = function() {}; | 62 base.Disposable.prototype.dispose = function() {}; |
63 | 63 |
64 /** | 64 /** |
| 65 * @constructor |
| 66 * @param {...base.Disposable} var_args |
| 67 * @implements {base.Disposable} |
| 68 */ |
| 69 base.Disposables = function(var_args) { |
| 70 /** |
| 71 * @type {Array.<base.Disposable>} |
| 72 * @private |
| 73 */ |
| 74 this.disposables_ = Array.prototype.slice.call(arguments, 0); |
| 75 }; |
| 76 |
| 77 base.Disposables.prototype.dispose = function() { |
| 78 for (var i = 0; i < this.disposables_.length; i++) { |
| 79 this.disposables_[i].dispose(); |
| 80 } |
| 81 }; |
| 82 |
| 83 /** |
65 * A utility function to invoke |obj|.dispose without a null check on |obj|. | 84 * A utility function to invoke |obj|.dispose without a null check on |obj|. |
66 * @param {base.Disposable} obj | 85 * @param {base.Disposable} obj |
67 */ | 86 */ |
68 base.dispose = function(obj) { | 87 base.dispose = function(obj) { |
69 if (obj) { | 88 if (obj) { |
70 base.debug.assert(typeof obj.dispose == 'function'); | 89 base.debug.assert(typeof obj.dispose == 'function'); |
71 obj.dispose(); | 90 obj.dispose(); |
72 } | 91 } |
73 }; | 92 }; |
74 | 93 |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
109 function(key) { | 128 function(key) { |
110 return dict[key]; | 129 return dict[key]; |
111 }); | 130 }); |
112 }; | 131 }; |
113 | 132 |
114 /** | 133 /** |
115 * @param {*} value | 134 * @param {*} value |
116 * @return {*} a recursive copy of |value| or null if |value| is not copyable | 135 * @return {*} a recursive copy of |value| or null if |value| is not copyable |
117 * (e.g. undefined, NaN). | 136 * (e.g. undefined, NaN). |
118 */ | 137 */ |
119 base.deepCopy = function (value) { | 138 base.deepCopy = function(value) { |
120 try { | 139 try { |
121 return JSON.parse(JSON.stringify(value)); | 140 return JSON.parse(JSON.stringify(value)); |
122 } catch (e) {} | 141 } catch (e) {} |
123 return null; | 142 return null; |
124 }; | 143 }; |
125 | 144 |
126 /** | 145 /** |
127 * @type {boolean|undefined} | 146 * @type {boolean|undefined} |
128 * @private | 147 * @private |
129 */ | 148 */ |
(...skipping 295 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
425 listeners.forEach( | 444 listeners.forEach( |
426 /** @param {function(*=):void} listener */ | 445 /** @param {function(*=):void} listener */ |
427 function(listener){ | 446 function(listener){ |
428 if (listener) { | 447 if (listener) { |
429 listener(opt_details); | 448 listener(opt_details); |
430 } | 449 } |
431 }); | 450 }); |
432 } | 451 } |
433 }; | 452 }; |
434 | 453 |
| 454 |
| 455 /** |
| 456 * A lightweight object that helps manage the lifetime of an event listener. |
| 457 * |
| 458 * For example, do the following if you want to automatically unhook events |
| 459 * when your object is disposed: |
| 460 * |
| 461 * var MyConstructor = function(domElement) { |
| 462 * this.eventHooks_ = new base.Disposables( |
| 463 * new base.EventHook(domElement, 'click', this.onClick_.bind(this)), |
| 464 * new base.EventHook(domElement, 'keydown', this.onClick_.bind(this)), |
| 465 * new base.ChromeEventHook(chrome.runtime.onMessage, |
| 466 * this.onMessage_.bind(this)) |
| 467 * ); |
| 468 * } |
| 469 * |
| 470 * MyConstructor.prototype.dispose = function() { |
| 471 * this.eventHooks_.dispose(); |
| 472 * this.eventHooks_ = null; |
| 473 * } |
| 474 * |
| 475 * @param {base.EventSource} src |
| 476 * @param {string} eventName |
| 477 * @param {function(...?)} listener |
| 478 * |
| 479 * @constructor |
| 480 * @implements {base.Disposable} |
| 481 */ |
| 482 base.EventHook = function(src, eventName, listener) { |
| 483 this.src_ = src; |
| 484 this.eventName_ = eventName; |
| 485 this.listener_ = listener; |
| 486 src.addEventListener(eventName, listener); |
| 487 }; |
| 488 |
| 489 base.EventHook.prototype.dispose = function() { |
| 490 this.src_.removeEventListener(this.eventName_, this.listener_); |
| 491 }; |
| 492 |
| 493 /** |
| 494 * An event hook implementation for DOM Events. |
| 495 * |
| 496 * @param {HTMLElement} src |
| 497 * @param {string} eventName |
| 498 * @param {function(...?)} listener |
| 499 * @param {boolean} capture |
| 500 * |
| 501 * @constructor |
| 502 * @implements {base.Disposable} |
| 503 */ |
| 504 base.DomEventHook = function(src, eventName, listener, capture) { |
| 505 this.src_ = src; |
| 506 this.eventName_ = eventName; |
| 507 this.listener_ = listener; |
| 508 this.capture_ = capture; |
| 509 src.addEventListener(eventName, listener, capture); |
| 510 }; |
| 511 |
| 512 base.DomEventHook.prototype.dispose = function() { |
| 513 this.src_.removeEventListener(this.eventName_, this.listener_, this.capture_); |
| 514 }; |
| 515 |
| 516 |
| 517 /** |
| 518 * An event hook implementation for Chrome Events. |
| 519 * |
| 520 * @param {chrome.Event} src |
| 521 * @param {function(...?)} listener |
| 522 * |
| 523 * @constructor |
| 524 * @implements {base.Disposable} |
| 525 */ |
| 526 base.ChromeEventHook = function(src, listener) { |
| 527 this.src_ = src; |
| 528 this.listener_ = listener; |
| 529 src.addListener(listener); |
| 530 }; |
| 531 |
| 532 base.ChromeEventHook.prototype.dispose = function() { |
| 533 this.src_.removeListener(this.listener_); |
| 534 }; |
| 535 |
| 536 |
435 /** | 537 /** |
436 * Converts UTF-8 string to ArrayBuffer. | 538 * Converts UTF-8 string to ArrayBuffer. |
437 * | 539 * |
438 * @param {string} string | 540 * @param {string} string |
439 * @return {ArrayBuffer} | 541 * @return {ArrayBuffer} |
440 */ | 542 */ |
441 base.encodeUtf8 = function(string) { | 543 base.encodeUtf8 = function(string) { |
442 var utf8String = unescape(encodeURIComponent(string)); | 544 var utf8String = unescape(encodeURIComponent(string)); |
443 var result = new Uint8Array(utf8String.length); | 545 var result = new Uint8Array(utf8String.length); |
444 for (var i = 0; i < utf8String.length; i++) | 546 for (var i = 0; i < utf8String.length; i++) |
445 result[i] = utf8String.charCodeAt(i); | 547 result[i] = utf8String.charCodeAt(i); |
446 return result.buffer; | 548 return result.buffer; |
447 } | 549 }; |
448 | 550 |
449 /** | 551 /** |
450 * Decodes UTF-8 string from ArrayBuffer. | 552 * Decodes UTF-8 string from ArrayBuffer. |
451 * | 553 * |
452 * @param {ArrayBuffer} buffer | 554 * @param {ArrayBuffer} buffer |
453 * @return {string} | 555 * @return {string} |
454 */ | 556 */ |
455 base.decodeUtf8 = function(buffer) { | 557 base.decodeUtf8 = function(buffer) { |
456 return decodeURIComponent( | 558 return decodeURIComponent( |
457 escape(String.fromCharCode.apply(null, new Uint8Array(buffer)))); | 559 escape(String.fromCharCode.apply(null, new Uint8Array(buffer)))); |
458 } | 560 }; |
459 | 561 |
460 /** | 562 /** |
461 * Generate a nonce, to be used as an xsrf protection token. | 563 * Generate a nonce, to be used as an xsrf protection token. |
462 * | 564 * |
463 * @return {string} A URL-Safe Base64-encoded 128-bit random value. */ | 565 * @return {string} A URL-Safe Base64-encoded 128-bit random value. */ |
464 base.generateXsrfToken = function() { | 566 base.generateXsrfToken = function() { |
465 var random = new Uint8Array(16); | 567 var random = new Uint8Array(16); |
466 window.crypto.getRandomValues(random); | 568 window.crypto.getRandomValues(random); |
467 var base64Token = window.btoa(String.fromCharCode.apply(null, random)); | 569 var base64Token = window.btoa(String.fromCharCode.apply(null, random)); |
468 return base64Token.replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, ''); | 570 return base64Token.replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, ''); |
469 }; | 571 }; |
470 | 572 |
471 /** | 573 /** |
472 * @param {string} jsonString A JSON-encoded string. | 574 * @param {string} jsonString A JSON-encoded string. |
473 * @return {Object|undefined} The decoded object, or undefined if the string | 575 * @return {Object|undefined} The decoded object, or undefined if the string |
474 * cannot be parsed. | 576 * cannot be parsed. |
475 */ | 577 */ |
476 base.jsonParseSafe = function(jsonString) { | 578 base.jsonParseSafe = function(jsonString) { |
477 try { | 579 try { |
478 return /** @type {Object} */ (JSON.parse(jsonString)); | 580 return /** @type {Object} */ (JSON.parse(jsonString)); |
479 } catch (err) { | 581 } catch (err) { |
480 return undefined; | 582 return undefined; |
481 } | 583 } |
482 } | 584 }; |
OLD | NEW |