balloon.js 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  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. // Kill codes:
  17. 2 = Timeout
  18. 3 = Clicked
  19. 4 = Closed or faded out
  20. */
  21. var path = require('path'),
  22. notifier = path.resolve(__dirname, '../vendor/notifu/notifu'),
  23. utils = require('../lib/utils'),
  24. checkGrowl = require('../lib/checkGrowl'),
  25. Toaster = require('./toaster'),
  26. Growl = require('./growl'),
  27. os = require('os'),
  28. cloneDeep = require('lodash.clonedeep');
  29. var EventEmitter = require('events').EventEmitter;
  30. var util = require('util');
  31. var hasGrowl = void 0;
  32. module.exports = WindowsBalloon;
  33. function WindowsBalloon (options) {
  34. options = cloneDeep(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. WindowsBalloon.prototype.notify = function (options, callback) {
  43. var fallback, notifierOptions = this.options;
  44. options = cloneDeep(options || {});
  45. callback = callback || function () {};
  46. if (typeof options === 'string') options = {
  47. title: 'node-notifier',
  48. message: options
  49. };
  50. var actionJackedCallback = utils.actionJackerDecorator(this, options, callback, function (data) {
  51. if (data === 'activate') {
  52. return 'click';
  53. }
  54. if (data === 'timeout') {
  55. return 'timeout';
  56. }
  57. return false;
  58. });
  59. if (!!this.options.withFallback && utils.isWin8()) {
  60. fallback = fallback || new Toaster(notifierOptions);
  61. return fallback.notify(options, callback);
  62. }
  63. if (!!this.options.withFallback && (!utils.isLessThanWin8() || hasGrowl === true)) {
  64. fallback = fallback || new Growl(notifierOptions);
  65. return fallback.notify(options, callback);
  66. }
  67. if (!this.options.withFallback || hasGrowl === false) {
  68. doNotification(options, notifierOptions, actionJackedCallback);
  69. return this;
  70. }
  71. checkGrowl(notifierOptions, function (hasGrowlResult) {
  72. hasGrowl = hasGrowlResult;
  73. if (hasGrowl) {
  74. fallback = fallback || new Growl(notifierOptions);
  75. return fallback.notify(options, callback);
  76. }
  77. doNotification(options, notifierOptions, actionJackedCallback);
  78. });
  79. return this;
  80. };
  81. var allowedArguments = ["t", "d", "p", "m", "i", "e", "q", "w", "xp"];
  82. function doNotification (options, notifierOptions, callback) {
  83. var is64Bit = os.arch() === 'x64';
  84. options = options || {};
  85. options = utils.mapToNotifu(options);
  86. options.p = options.p || 'Node Notification:';
  87. var fullNotifierPath = notifier + (is64Bit ? '64' : '') + '.exe';
  88. var localNotifier = notifierOptions.customPath || fullNotifierPath;
  89. if (!options.m) {
  90. callback(new Error('Message is required.'));
  91. return this;
  92. }
  93. var argsList = utils.constructArgumentList(options, {
  94. wrapper: '',
  95. noEscape: true,
  96. explicitTrue: true,
  97. allowedArguments: allowedArguments
  98. });
  99. if (!!options.wait) {
  100. return utils.fileCommand(localNotifier, argsList, function (error, data) {
  101. var action = fromErrorCodeToAction(error.code);
  102. if (action === 'error') return callback(error, data);
  103. return callback(null, action);
  104. });
  105. }
  106. utils.immediateFileCommand(localNotifier, argsList, callback);
  107. }
  108. function fromErrorCodeToAction (errorCode) {
  109. switch (errorCode) {
  110. case 2:
  111. return 'timeout';
  112. case 3:
  113. case 6:
  114. case 7:
  115. return 'activate';
  116. case 4:
  117. return 'close';
  118. default:
  119. return 'error';
  120. }
  121. }