error_report.js 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309
  1. /* vim: set expandtab sw=4 ts=4 sts=4: */
  2. /**
  3. * general function, usually for data manipulation pages
  4. *
  5. */
  6. var ErrorReport = {
  7. /**
  8. * @var object stores the last exception info
  9. */
  10. _last_exception: null,
  11. /**
  12. * handles thrown error exceptions based on user preferences
  13. *
  14. * @return void
  15. */
  16. error_handler: function (exception) {
  17. if (exception.name === null || typeof(exception.name) === 'undefined') {
  18. exception.name = ErrorReport._extractExceptionName(exception);
  19. }
  20. ErrorReport._last_exception = exception;
  21. $.post('error_report.php', {
  22. ajax_request: true,
  23. server: PMA_commonParams.get('server'),
  24. get_settings: true,
  25. exception_type: 'js'
  26. }, function (data) {
  27. if (data.success !== true) {
  28. PMA_ajaxShowMessage(data.error, false);
  29. return;
  30. }
  31. if (data.report_setting === 'ask') {
  32. ErrorReport._showErrorNotification();
  33. } else if (data.report_setting === 'always') {
  34. report_data = ErrorReport._get_report_data(exception);
  35. post_data = $.extend(report_data, {
  36. send_error_report: true,
  37. automatic: true
  38. });
  39. $.post('error_report.php', post_data, function (data) {
  40. if (data.success === false) {
  41. // in the case of an error, show the error message returned.
  42. PMA_ajaxShowMessage(data.error, false);
  43. } else {
  44. PMA_ajaxShowMessage(data.message, false);
  45. }
  46. });
  47. }
  48. });
  49. },
  50. /**
  51. * Shows the modal dialog previewing the report
  52. *
  53. * @param exception object error report info
  54. *
  55. * @return void
  56. */
  57. _showReportDialog: function (exception) {
  58. var report_data = ErrorReport._get_report_data(exception);
  59. /* Remove the hidden dialogs if there are*/
  60. if ($('#error_report_dialog').length !== 0) {
  61. $('#error_report_dialog').remove();
  62. }
  63. var $div = $('<div id="error_report_dialog"></div>');
  64. $div.css('z-index', '1000');
  65. var button_options = {};
  66. button_options[PMA_messages.strSendErrorReport] = function () {
  67. var $dialog = $(this);
  68. var post_data = $.extend(report_data, {
  69. send_error_report: true,
  70. description: $('#report_description').val(),
  71. always_send: $('#always_send_checkbox')[0].checked
  72. });
  73. $.post('error_report.php', post_data, function (data) {
  74. $dialog.dialog('close');
  75. if (data.success === false) {
  76. // in the case of an error, show the error message returned.
  77. PMA_ajaxShowMessage(data.error, false);
  78. } else {
  79. PMA_ajaxShowMessage(data.message, 3000);
  80. }
  81. });
  82. };
  83. button_options[PMA_messages.strCancel] = function () {
  84. $(this).dialog('close');
  85. };
  86. $.post('error_report.php', report_data, function (data) {
  87. if (data.success === false) {
  88. // in the case of an error, show the error message returned.
  89. PMA_ajaxShowMessage(data.error, false);
  90. } else {
  91. // Show dialog if the request was successful
  92. $div
  93. .append(data.message)
  94. .dialog({
  95. title: PMA_messages.strSubmitErrorReport,
  96. width: 650,
  97. modal: true,
  98. buttons: button_options,
  99. close: function () {
  100. $(this).remove();
  101. }
  102. });
  103. }
  104. });
  105. },
  106. /**
  107. * Shows the small notification that asks for user permission
  108. *
  109. * @return void
  110. */
  111. _showErrorNotification: function () {
  112. ErrorReport._removeErrorNotification();
  113. var $div = $(
  114. '<div style="position:fixed;bottom:0;left:0;right:0;margin:0;' +
  115. 'z-index:1000" class="error" id="error_notification"></div>'
  116. ).append(
  117. PMA_getImage('s_error') + PMA_messages.strErrorOccurred
  118. );
  119. var $buttons = $('<div class="floatright"></div>');
  120. var button_html = '<button id="show_error_report">';
  121. button_html += PMA_messages.strShowReportDetails;
  122. button_html += '</button>';
  123. button_html += '<a id="change_error_settings">';
  124. button_html += PMA_getImage('s_cog', PMA_messages.strChangeReportSettings);
  125. button_html += '</a>';
  126. button_html += '<a href="#" id="ignore_error">';
  127. button_html += PMA_getImage('b_close', PMA_messages.strIgnore);
  128. button_html += '</a>';
  129. $buttons.html(button_html);
  130. $div.append($buttons);
  131. $div.appendTo(document.body);
  132. $(document).on('click', '#change_error_settings', ErrorReport._redirect_to_settings);
  133. $(document).on('click', '#show_error_report', ErrorReport._createReportDialog);
  134. $(document).on('click', '#ignore_error', ErrorReport._removeErrorNotification);
  135. },
  136. /**
  137. * Removes the notification if it was displayed before
  138. *
  139. * @return void
  140. */
  141. _removeErrorNotification: function (e) {
  142. if (e) {
  143. // don't remove the hash fragment by navigating to #
  144. e.preventDefault();
  145. }
  146. $('#error_notification').fadeOut(function () {
  147. $(this).remove();
  148. });
  149. },
  150. /**
  151. * Extracts Exception name from message if it exists
  152. *
  153. * @return String
  154. */
  155. _extractExceptionName: function (exception) {
  156. if (exception.message === null || typeof(exception.message) === 'undefined') {
  157. return '';
  158. }
  159. var reg = /([a-zA-Z]+):/;
  160. var regex_result = reg.exec(exception.message);
  161. if (regex_result && regex_result.length === 2) {
  162. return regex_result[1];
  163. }
  164. return '';
  165. },
  166. /**
  167. * Shows the modal dialog previewing the report
  168. *
  169. * @return void
  170. */
  171. _createReportDialog: function () {
  172. ErrorReport._removeErrorNotification();
  173. ErrorReport._showReportDialog(ErrorReport._last_exception);
  174. },
  175. /**
  176. * Redirects to the settings page containing error report
  177. * preferences
  178. *
  179. * @return void
  180. */
  181. _redirect_to_settings: function () {
  182. window.location.href = 'prefs_forms.php';
  183. },
  184. /**
  185. * Returns the report data to send to the server
  186. *
  187. * @param exception object exception info
  188. *
  189. * @return object
  190. */
  191. _get_report_data: function (exception) {
  192. var report_data = {
  193. 'ajax_request': true,
  194. 'exception': exception,
  195. 'current_url': window.location.href,
  196. 'exception_type': 'js'
  197. };
  198. if (AJAX.scriptHandler._scripts.length > 0) {
  199. report_data.scripts = AJAX.scriptHandler._scripts.map(
  200. function (script) {
  201. return script.name;
  202. }
  203. );
  204. }
  205. return report_data;
  206. },
  207. /**
  208. * Wraps all global functions that start with PMA_
  209. *
  210. * @return void
  211. */
  212. wrap_global_functions: function () {
  213. for (var key in window) {
  214. if (key.indexOf('PMA_') === 0) {
  215. var global = window[key];
  216. if (typeof(global) === 'function') {
  217. window[key] = ErrorReport.wrap_function(global);
  218. }
  219. }
  220. }
  221. },
  222. /**
  223. * Wraps given function in error reporting code and returns wrapped function
  224. *
  225. * @param func function to be wrapped
  226. *
  227. * @return function
  228. */
  229. wrap_function: function (func) {
  230. if (!func.wrapped) {
  231. var new_func = function () {
  232. try {
  233. return func.apply(this, arguments);
  234. } catch (x) {
  235. TraceKit.report(x);
  236. }
  237. };
  238. new_func.wrapped = true;
  239. // Set guid of wrapped function same as original function, so it can be removed
  240. // See bug#4146 (problem with jquery draggable and sortable)
  241. new_func.guid = func.guid = func.guid || new_func.guid || jQuery.guid++;
  242. return new_func;
  243. } else {
  244. return func;
  245. }
  246. },
  247. /**
  248. * Automatically wraps the callback in AJAX.registerOnload
  249. *
  250. * @return void
  251. */
  252. _wrap_ajax_onload_callback: function () {
  253. var oldOnload = AJAX.registerOnload;
  254. AJAX.registerOnload = function (file, func) {
  255. func = ErrorReport.wrap_function(func);
  256. oldOnload.call(this, file, func);
  257. };
  258. },
  259. /**
  260. * Automatically wraps the callback in $.fn.on
  261. *
  262. * @return void
  263. */
  264. _wrap_$_on_callback: function () {
  265. var oldOn = $.fn.on;
  266. $.fn.on = function () {
  267. for (var i = 1; i <= 3; i++) {
  268. if (typeof(arguments[i]) === 'function') {
  269. arguments[i] = ErrorReport.wrap_function(arguments[i]);
  270. break;
  271. }
  272. }
  273. return oldOn.apply(this, arguments);
  274. };
  275. },
  276. /**
  277. * Wraps all global functions that start with PMA_
  278. * also automatically wraps the callback in AJAX.registerOnload
  279. *
  280. * @return void
  281. */
  282. set_up_error_reporting: function () {
  283. ErrorReport.wrap_global_functions();
  284. ErrorReport._wrap_ajax_onload_callback();
  285. ErrorReport._wrap_$_on_callback();
  286. }
  287. };
  288. AJAX.registerOnload('error_report.js', function () {
  289. TraceKit.report.subscribe(ErrorReport.error_handler);
  290. ErrorReport.set_up_error_reporting();
  291. ErrorReport.wrap_global_functions();
  292. });