error_report.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  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. $.get("error_report.php", {
  22. ajax_request: true,
  23. server: PMA_commonParams.get('server'),
  24. token: PMA_commonParams.get('token'),
  25. get_settings: true
  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 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. var button_options = {};
  65. button_options[PMA_messages.strSendErrorReport] = function () {
  66. $dialog = $(this);
  67. post_data = $.extend(report_data, {
  68. send_error_report: true,
  69. description: $("#report_description").val(),
  70. always_send: $("#always_send_checkbox")[0].checked
  71. });
  72. $.post("error_report.php", post_data, function (data) {
  73. $dialog.dialog('close');
  74. if (data.success === false) {
  75. //in the case of an error, show the error message returned.
  76. PMA_ajaxShowMessage(data.error, false);
  77. } else {
  78. PMA_ajaxShowMessage(data.message, 3000);
  79. }
  80. });
  81. };
  82. button_options[PMA_messages.strCancel] = function () {
  83. $(this).dialog('close');
  84. };
  85. $.post("error_report.php", report_data, function (data) {
  86. if (data.success === false) {
  87. //in the case of an error, show the error message returned.
  88. PMA_ajaxShowMessage(data.error, false);
  89. } else {
  90. // Show dialog if the request was successful
  91. $div
  92. .append(data.message)
  93. .dialog({
  94. title: PMA_messages.strSubmitErrorReport,
  95. width: 650,
  96. modal: true,
  97. buttons: button_options,
  98. close: function () {
  99. $(this).remove();
  100. }
  101. });
  102. }
  103. }); // end $.get()
  104. },
  105. /**
  106. * Shows the small notification that asks for user permission
  107. *
  108. * @return void
  109. */
  110. _showErrorNotification: function () {
  111. ErrorReport._removeErrorNotification();
  112. $div = $(
  113. '<div style="position:fixed;bottom:0;left:0;right:0;margin:0;' +
  114. 'z-index:1000" class="error" id="error_notification"></div>'
  115. ).append(
  116. PMA_getImage("s_error.png") + PMA_messages.strErrorOccurred
  117. );
  118. $buttons = $('<div style="float:right"></div>');
  119. button_html = '<button id="show_error_report">';
  120. button_html += PMA_messages.strShowReportDetails;
  121. button_html += '</button>';
  122. button_html += '<a id="change_error_settings">';
  123. button_html += PMA_getImage('s_cog.png', PMA_messages.strChangeReportSettings);
  124. button_html += '</a>';
  125. button_html += '<a href="#" id="ignore_error">';
  126. button_html += PMA_getImage('b_close.png', PMA_messages.strIgnore);
  127. button_html += '</a>';
  128. $buttons.html(button_html);
  129. $div.append($buttons);
  130. $div.appendTo(document.body);
  131. $("#change_error_settings").on("click", ErrorReport._redirect_to_settings);
  132. $("#show_error_report").on("click", ErrorReport._createReportDialog);
  133. $("#ignore_error").on("click", ErrorReport._removeErrorNotification);
  134. },
  135. /**
  136. * Removes the notification if it was displayed before
  137. *
  138. * @return void
  139. */
  140. _removeErrorNotification: function () {
  141. $("#error_notification").fadeOut(function () {
  142. $(this).remove();
  143. });
  144. },
  145. /**
  146. * Extracts Exception name from message if it exists
  147. *
  148. * @return String
  149. */
  150. _extractExceptionName: function (exception) {
  151. if (exception.message === null || typeof(exception.message) == "undefined"){
  152. return "";
  153. } else {
  154. return (/([a-zA-Z]+):/).exec(exception.message)[1];
  155. }
  156. },
  157. /**
  158. * Shows the modal dialog previewing the report
  159. *
  160. * @return void
  161. */
  162. _createReportDialog: function () {
  163. ErrorReport._removeErrorNotification();
  164. ErrorReport._showReportDialog(ErrorReport._last_exception);
  165. },
  166. /**
  167. * Returns the needed info about stored microhistory
  168. *
  169. * @return object
  170. */
  171. _get_microhistory: function () {
  172. cached_pages = AJAX.cache.pages.slice(-7);
  173. remove = ["common_query", "table", "db", "token", "pma_absolute_uri"];
  174. return {
  175. pages: cached_pages.map(function (page) {
  176. simplepage = {
  177. hash: page.hash
  178. };
  179. if (page.params) {
  180. simplepage.params = $.extend({}, page.params);
  181. $.each(simplepage.params, function (param) {
  182. if ($.inArray(param, remove) != -1) {
  183. delete simplepage.params[param];
  184. }
  185. });
  186. }
  187. return simplepage;
  188. }),
  189. current_index: AJAX.cache.current -
  190. (AJAX.cache.pages.length - cached_pages.length)
  191. };
  192. },
  193. /**
  194. * Redirects to the settings page containing error report
  195. * preferences
  196. *
  197. * @return void
  198. */
  199. _redirect_to_settings: function () {
  200. window.location.href = "prefs_forms.php?token=" + PMA_commonParams.get('token');
  201. },
  202. /**
  203. * Returns the report data to send to the server
  204. *
  205. * @param object exception info
  206. *
  207. * @return object
  208. */
  209. _get_report_data: function (exception) {
  210. var report_data = {
  211. "ajax_request": true,
  212. "token": PMA_commonParams.get('token'),
  213. "exception": exception,
  214. "current_url": window.location.href,
  215. "microhistory": ErrorReport._get_microhistory()
  216. };
  217. if (typeof AJAX.cache.pages[AJAX.cache.current - 1] !== 'undefined') {
  218. report_data.scripts = AJAX.cache.pages[AJAX.cache.current - 1].scripts.map(
  219. function (script) {
  220. return script.name;
  221. }
  222. );
  223. }
  224. return report_data;
  225. },
  226. /**
  227. * Wraps all global functions that start with PMA_
  228. *
  229. * @return void
  230. */
  231. wrap_global_functions: function () {
  232. for (var key in window) {
  233. var global = window[key];
  234. if (typeof(global) === "function" && key.indexOf("PMA_") === 0) {
  235. window[key] = ErrorReport.wrap_function(global);
  236. }
  237. }
  238. },
  239. /**
  240. * Wraps given function in error reporting code and returns wrapped function
  241. *
  242. * @param function function to be wrapped
  243. *
  244. * @return function
  245. */
  246. wrap_function: function (func) {
  247. if (!func.wrapped) {
  248. var new_func = function () {
  249. try {
  250. return func.apply(this, arguments);
  251. } catch (x) {
  252. TraceKit.report(x);
  253. }
  254. };
  255. new_func.wrapped = true;
  256. //Set guid of wrapped function same as original function, so it can be removed
  257. //See bug#4146 (problem with jquery draggable and sortable)
  258. new_func.guid = func.guid = func.guid || new_func.guid || jQuery.guid++;
  259. return new_func;
  260. } else {
  261. return func;
  262. }
  263. },
  264. /**
  265. * Automatically wraps the callback in AJAX.registerOnload
  266. *
  267. * @return void
  268. */
  269. _wrap_ajax_onload_callback: function () {
  270. var oldOnload = AJAX.registerOnload;
  271. AJAX.registerOnload = function (file, func) {
  272. func = ErrorReport.wrap_function(func);
  273. oldOnload.call(this, file, func);
  274. };
  275. },
  276. /**
  277. * Automatically wraps the callback in $.fn.on
  278. *
  279. * @return void
  280. */
  281. _wrap_$_on_callback: function () {
  282. var oldOn = $.fn.on;
  283. $.fn.on = function () {
  284. for (var i = 1; i <= 3; i++) {
  285. if (typeof(arguments[i]) === "function") {
  286. arguments[i] = ErrorReport.wrap_function(arguments[i]);
  287. break;
  288. }
  289. }
  290. return oldOn.apply(this, arguments);
  291. };
  292. },
  293. /**
  294. * Wraps all global functions that start with PMA_
  295. * also automatically wraps the callback in AJAX.registerOnload
  296. *
  297. * @return void
  298. */
  299. set_up_error_reporting: function () {
  300. ErrorReport.wrap_global_functions();
  301. ErrorReport._wrap_ajax_onload_callback();
  302. ErrorReport._wrap_$_on_callback();
  303. }
  304. };
  305. TraceKit.report.subscribe(ErrorReport.error_handler);
  306. ErrorReport.set_up_error_reporting();
  307. $(function () {
  308. ErrorReport.wrap_global_functions();
  309. });