balloon.js 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. /**
  2. * Wrapper for the notifu 1.6 (http://www.paralint.com/projects/notifu/)
  3. Usage
  4. /t <value> The type of message to display values are:
  5. info The message is an informational message
  6. warn The message is an warning message
  7. error The message is an error message
  8. /d <value> The number of milliseconds to display (omit or 0 for infinit)
  9. /p <value> The title (or prompt) of the ballon
  10. /m <value> The message text
  11. /i <value> Specify an icon to use ("parent" uses the icon of the parent process)
  12. /e Enable ballon tips in the registry (for this user only)
  13. /q Do not play a sound when the tooltip is displayed
  14. /w Show the tooltip even if the user is in the quiet period that follows his very first login (Windows 7 and up)
  15. /xp Use IUserNotification interface event when IUserNotification2 is available
  16. /l Display license for notifu
  17. // Kill codes:
  18. 2 = Timeout
  19. 3 = Clicked
  20. 4 = Closed or faded out
  21. */
  22. var path = require('path');
  23. var notifier = path.resolve(__dirname, '../vendor/notifu/notifu');
  24. var checkGrowl = require('../lib/checkGrowl');
  25. var utils = require('../lib/utils');
  26. var Toaster = require('./toaster');
  27. var Growl = require('./growl');
  28. var os = require('os');
  29. var EventEmitter = require('events').EventEmitter;
  30. var util = require('util');
  31. var hasGrowl;
  32. module.exports = WindowsBalloon;
  33. function WindowsBalloon(options) {
  34. options = utils.clone(options || {});
  35. if (!(this instanceof WindowsBalloon)) {
  36. return new WindowsBalloon(options);
  37. }
  38. this.options = options;
  39. EventEmitter.call(this);
  40. }
  41. util.inherits(WindowsBalloon, EventEmitter);
  42. function noop() {}
  43. function notifyRaw(options, callback) {
  44. var fallback;
  45. var notifierOptions = this.options;
  46. options = utils.clone(options || {});
  47. callback = callback || noop;
  48. if (typeof options === 'string') {
  49. options = { title: 'node-notifier', message: options };
  50. }
  51. var actionJackedCallback = utils.actionJackerDecorator(
  52. this,
  53. options,
  54. callback,
  55. function(data) {
  56. if (data === 'activate') {
  57. return 'click';
  58. }
  59. if (data === 'timeout') {
  60. return 'timeout';
  61. }
  62. return false;
  63. }
  64. );
  65. if (!!this.options.withFallback && utils.isWin8()) {
  66. fallback = fallback || new Toaster(notifierOptions);
  67. return fallback.notify(options, callback);
  68. }
  69. if (
  70. !!this.options.withFallback &&
  71. (!utils.isLessThanWin8() || hasGrowl === true)
  72. ) {
  73. fallback = fallback || new Growl(notifierOptions);
  74. return fallback.notify(options, callback);
  75. }
  76. if (!this.options.withFallback || hasGrowl === false) {
  77. doNotification(options, notifierOptions, actionJackedCallback);
  78. return this;
  79. }
  80. checkGrowl(notifierOptions, function(_, hasGrowlResult) {
  81. hasGrowl = hasGrowlResult;
  82. if (hasGrowl) {
  83. fallback = fallback || new Growl(notifierOptions);
  84. return fallback.notify(options, callback);
  85. }
  86. doNotification(options, notifierOptions, actionJackedCallback);
  87. });
  88. return this;
  89. }
  90. Object.defineProperty(WindowsBalloon.prototype, 'notify', {
  91. get: function() {
  92. if (!this._notify) this._notify = notifyRaw.bind(this);
  93. return this._notify;
  94. }
  95. });
  96. var allowedArguments = ['t', 'd', 'p', 'm', 'i', 'e', 'q', 'w', 'xp'];
  97. function doNotification(options, notifierOptions, callback) {
  98. var is64Bit = os.arch() === 'x64';
  99. options = options || {};
  100. options = utils.mapToNotifu(options);
  101. options.p = options.p || 'Node Notification:';
  102. var fullNotifierPath = notifier + (is64Bit ? '64' : '') + '.exe';
  103. var localNotifier = notifierOptions.customPath || fullNotifierPath;
  104. if (!options.m) {
  105. callback(new Error('Message is required.'));
  106. return this;
  107. }
  108. var argsList = utils.constructArgumentList(options, {
  109. wrapper: '',
  110. noEscape: true,
  111. explicitTrue: true,
  112. allowedArguments: allowedArguments
  113. });
  114. if (options.wait) {
  115. return utils.fileCommand(localNotifier, argsList, function(error, data) {
  116. var action = fromErrorCodeToAction(error.code);
  117. if (action === 'error') return callback(error, data);
  118. return callback(null, action);
  119. });
  120. }
  121. utils.immediateFileCommand(localNotifier, argsList, callback);
  122. }
  123. function fromErrorCodeToAction(errorCode) {
  124. switch (errorCode) {
  125. case 2:
  126. return 'timeout';
  127. case 3:
  128. case 6:
  129. case 7:
  130. return 'activate';
  131. case 4:
  132. return 'close';
  133. default:
  134. return 'error';
  135. }
  136. }