You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

156 lines
4.3 KiB

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