OTRS API Reference JavaScript

Source: Core.Agent.Overview.js

  1. // --
  2. // Copyright (C) 2001-2018 OTRS AG, https://otrs.com/
  3. // --
  4. // This software comes with ABSOLUTELY NO WARRANTY. For details, see
  5. // the enclosed file COPYING for license information (GPL). If you
  6. // did not receive this file, see https://www.gnu.org/licenses/gpl-3.0.txt.
  7. // --
  8. "use strict";
  9. var Core = Core || {};
  10. Core.Agent = Core.Agent || {};
  11. /**
  12. * @namespace Core.Agent.Overview
  13. * @memberof Core.Agent
  14. * @author OTRS AG
  15. * @description
  16. * This namespace contains the View functions.
  17. */
  18. Core.Agent.Overview = (function (TargetNS) {
  19. /**
  20. * @name Init
  21. * @memberof Core.Agent.Overview
  22. * @function
  23. * @description
  24. * This function initializes the functionality for the Overview screen.
  25. */
  26. TargetNS.Init = function () {
  27. var Profile = Core.Config.Get('Profile'),
  28. View = Core.Config.Get('View'),
  29. TicketID, ActionRowTickets = Core.Config.Get('ActionRowTickets') || {};
  30. // Disable any event handlers on the "label" elements.
  31. $('ul.Actions form > label').off("click").on("click", function() {
  32. return false;
  33. });
  34. // create open popup event for dropdown actions
  35. $('ul.Actions form > select').off("change").on("change", function() {
  36. var URL;
  37. if ($(this).val() !== '0') {
  38. if (Core.Config.Get('Action') === 'AgentTicketQueue' ||
  39. Core.Config.Get('Action') === 'AgentTicketService' ||
  40. Core.Config.Get('Action') === 'AgentTicketStatusView' ||
  41. Core.Config.Get('Action') === 'AgentTicketEscalationView'
  42. ) {
  43. $(this).closest('form').submit();
  44. }
  45. else {
  46. URL = Core.Config.Get('Baselink') + $(this).parents().serialize();
  47. Core.UI.Popup.OpenPopup(URL, 'TicketAction');
  48. // reset the select box so that it can be used again from the same window
  49. $(this).val('0');
  50. }
  51. }
  52. });
  53. // open ticket search modal dialog
  54. $('#TicketSearch').on('click', function () {
  55. Core.Agent.Search.OpenSearchDialog('AgentTicketSearch', Profile);
  56. return false;
  57. });
  58. // open settings modal dialog
  59. $('#ShowContextSettingsDialog').on('click', function (Event) {
  60. Core.UI.Dialog.ShowContentDialog($('#ContextSettingsDialogContainer'), Core.Language.Translate("Settings"), '15%', 'Center', true,
  61. [
  62. {
  63. Label: Core.Language.Translate("Save"),
  64. Type: 'Submit',
  65. Class: 'Primary',
  66. Function: function () {
  67. var $ListContainer = $('.AllocationListContainer').find('.AssignedFields'),
  68. FieldID;
  69. if (isJQueryObject($ListContainer) && $ListContainer.length) {
  70. $.each($ListContainer.find('li'), function() {
  71. FieldID = 'UserFilterColumnsEnabled-' + $(this).attr('data-fieldname');
  72. // only add this field if its not already there. This could happen
  73. // if e.g. the save button is clicked multiple times
  74. if (!$('#' + FieldID).length) {
  75. $('<input name="UserFilterColumnsEnabled" type="hidden" />').attr('id', FieldID).val($(this).attr('data-fieldname')).appendTo($ListContainer.closest('div'));
  76. }
  77. });
  78. }
  79. return true;
  80. }
  81. }
  82. ], true);
  83. Event.preventDefault();
  84. Event.stopPropagation();
  85. Core.Agent.TableFilters.SetAllocationList();
  86. return false;
  87. });
  88. // change queue for selected ticket
  89. $('.InlineActions, .OverviewActions').on('change', 'select[name=DestQueueID]', function () {
  90. $(this).closest('form').submit();
  91. });
  92. // add actions for selected (or hovered) ticket
  93. for (TicketID in ActionRowTickets) {
  94. Core.UI.ActionRow.AddActions($('#TicketID_' + TicketID), ActionRowTickets[TicketID]);
  95. }
  96. // call functions in regard to a view
  97. if (View === 'Small') {
  98. TargetNS.InitViewSmall();
  99. }
  100. else if (View === 'Medium') {
  101. TargetNS.InitViewMedium();
  102. }
  103. else if (View === 'Preview') {
  104. TargetNS.InitViewPreview();
  105. }
  106. $('a.SplitSelection').off('click').on('click', function() {
  107. Core.Agent.TicketSplit.OpenSplitSelection($(this).attr('href'));
  108. return false;
  109. });
  110. };
  111. /**
  112. * @name InitViewSmall
  113. * @memberof Core.Agent.Overview
  114. * @function
  115. * @description
  116. * This function initializes JS functionality for view Small.
  117. */
  118. TargetNS.InitViewSmall = function () {
  119. var URL, ColumnFilter, NewColumnFilterStrg, MyRegEx, SessionInformation,
  120. $MasterActionLink;
  121. // initializes a click event for table with checkboxes
  122. Core.UI.InitCheckboxSelection($('table td.Checkbox'));
  123. // initializes autocompletion for customer user
  124. Core.Agent.TableFilters.InitCustomerUserAutocomplete($(".CustomerUserAutoComplete"));
  125. // initializes autocompletion for customer ID
  126. Core.Agent.TableFilters.InitCustomerIDAutocomplete($(".CustomerIDAutoComplete"));
  127. // initializes autocompletion for user
  128. Core.Agent.TableFilters.InitUserAutocomplete($(".UserAutoComplete"));
  129. // click event for opening popup
  130. $('a.AsPopup').on('click', function () {
  131. Core.UI.Popup.OpenPopup($(this).attr('href'), 'Action');
  132. return false;
  133. });
  134. // change event for column filter
  135. $('.ColumnFilter').on('change', function () {
  136. // define variables
  137. URL = Core.Config.Get("Baselink") + 'Action=' + Core.Config.Get("Action") + ';' + Core.Config.Get('LinkPage');
  138. SessionInformation = Core.App.GetSessionInformation();
  139. $.each(SessionInformation, function (Key, Value) {
  140. URL += encodeURIComponent(Key) + '=' + encodeURIComponent(Value) + ';';
  141. });
  142. ColumnFilter = $(this)[0].name;
  143. NewColumnFilterStrg = $(this)[0].name + '=' + $(this).val() + ';';
  144. MyRegEx = new RegExp(ColumnFilter+"=[^;]*;");
  145. // check for already set parameter and replace
  146. if (URL.match(MyRegEx)) {
  147. URL = URL.replace(MyRegEx, NewColumnFilterStrg);
  148. }
  149. // otherwise add the new column filter
  150. else {
  151. URL = URL + NewColumnFilterStrg;
  152. }
  153. // redirect
  154. window.location.href = URL;
  155. });
  156. // click event on table header trigger
  157. $('.OverviewHeader').off('click').on('click', '.ColumnSettingsTrigger', function() {
  158. var $TriggerObj = $(this),
  159. FilterName;
  160. if ($TriggerObj.hasClass('Active')) {
  161. $TriggerObj
  162. .next('.ColumnSettingsContainer')
  163. .find('.ColumnSettingsBox')
  164. .fadeOut('fast', function() {
  165. $TriggerObj.removeClass('Active');
  166. });
  167. }
  168. else {
  169. // slide up all open settings widgets
  170. $('.ColumnSettingsTrigger')
  171. .next('.ColumnSettingsContainer')
  172. .find('.ColumnSettingsBox')
  173. .fadeOut('fast', function() {
  174. $(this).parent().prev('.ColumnSettingsTrigger').removeClass('Active');
  175. });
  176. // show THIS settings widget
  177. $TriggerObj
  178. .next('.ColumnSettingsContainer')
  179. .find('.ColumnSettingsBox')
  180. .fadeIn('fast', function() {
  181. $TriggerObj.addClass('Active');
  182. // refresh filter dropdown
  183. FilterName = $TriggerObj
  184. .next('.ColumnSettingsContainer')
  185. .find('select')
  186. .attr('name');
  187. if (
  188. $TriggerObj.closest('th').hasClass('CustomerID') ||
  189. $TriggerObj.closest('th').hasClass('CustomerUserID') ||
  190. $TriggerObj.closest('th').hasClass('Responsible') ||
  191. $TriggerObj.closest('th').hasClass('Owner')
  192. ) {
  193. if (!$TriggerObj.parent().find('.SelectedValue').length) {
  194. Core.AJAX.FormUpdate($('#Nothing'), 'AJAXFilterUpdate', FilterName, [ FilterName ], function() {
  195. var AutoCompleteValue = $TriggerObj
  196. .next('.ColumnSettingsContainer')
  197. .find('select')
  198. .val(),
  199. AutoCompleteText = $TriggerObj
  200. .next('.ColumnSettingsContainer')
  201. .find('select')
  202. .find('option:selected')
  203. .text();
  204. if (AutoCompleteValue !== 'DeleteFilter') {
  205. $TriggerObj
  206. .next('.ColumnSettingsContainer')
  207. .find('select')
  208. .after('<span class="SelectedValue Hidden">' + AutoCompleteText + ' (' + AutoCompleteValue + ')</span>')
  209. .parent()
  210. .find('input[type=text]')
  211. .after('<a href="#" class="DeleteFilter"><i class="fa fa-trash-o"></i></a>')
  212. .parent()
  213. .find('a.DeleteFilter')
  214. .off()
  215. .on('click', function() {
  216. $(this)
  217. .closest('.ColumnSettingsContainer')
  218. .find('select')
  219. .val('DeleteFilter')
  220. .trigger('change');
  221. return false;
  222. });
  223. }
  224. });
  225. }
  226. }
  227. else {
  228. Core.AJAX.FormUpdate($('#ColumnFilterAttributes'), 'AJAXFilterUpdate', FilterName, [ FilterName ]);
  229. }
  230. });
  231. }
  232. return false;
  233. });
  234. // click event for whole table row
  235. $('.MasterAction').off('click').on('click', function (Event) {
  236. $MasterActionLink = $(this).find('.MasterActionLink');
  237. // prevent MasterAction on Dynamic Fields links
  238. if ($(Event.target).hasClass('DynamicFieldLink')) {
  239. return true;
  240. }
  241. // only act if the link was not clicked directly
  242. if (Event.target !== $MasterActionLink.get(0)) {
  243. if (Event.ctrlKey || Event.metaKey) {
  244. Core.UI.Popup.open($MasterActionLink.attr('href'));
  245. }
  246. else {
  247. window.location = $MasterActionLink.attr('href');
  248. }
  249. return false;
  250. }
  251. });
  252. };
  253. /**
  254. * @name InitInlineActions
  255. * @memberof Core.Agent.Overview
  256. * @function
  257. * @description
  258. * This function initializes the inline actions mini overlay in medium/preview views.
  259. */
  260. TargetNS.InitInlineActions = function () {
  261. $('.OverviewMedium > li, .OverviewLarge > li').on('mouseenter', function() {
  262. $(this).find('ul.InlineActions').css('top', '0px');
  263. Core.App.Publish('Event.Agent.TicketOverview.InlineActions.Shown');
  264. });
  265. $('.OverviewMedium > li, .OverviewLarge > li').on('mouseleave', function(Event) {
  266. // The inline actions would hide if hovering over the queue selection due to a bug in IE.
  267. // See bug#12403 for more information.
  268. // The exception has to be added also for modernized dropdowns.
  269. // See bug#13100 for more information.
  270. if (
  271. Event.target.tagName.toLowerCase() === 'select'
  272. || $(Event.target).hasClass('InputField_Search')
  273. )
  274. {
  275. return false;
  276. }
  277. $(this).find('ul.InlineActions').css('top', '-35px');
  278. Core.App.Publish('Event.Agent.TicketOverview.InlineActions.Hidden', [$(this).find('ul.InlineActions')]);
  279. });
  280. };
  281. /**
  282. * @name InitViewMedium
  283. * @memberof Core.Agent.Overview
  284. * @function
  285. * @description
  286. * This function initializes JS functionality for view Medium.
  287. */
  288. TargetNS.InitViewMedium = function () {
  289. var $MasterActionLink,
  290. Matches, PopupType = 'TicketAction';
  291. // initializes a click event for div with checkboxes
  292. Core.UI.InitCheckboxSelection($('div.Checkbox'));
  293. // initialize inline actions overlay
  294. TargetNS.InitInlineActions();
  295. // Stop propagation on click on a part of the InlienActionRow without a link
  296. // Otherwise that would trigger the li-wide link to the ticketzoom
  297. $('ul.InlineActions').click(function (Event) {
  298. Event.cancelBubble = true;
  299. if (Event.stopPropagation) {
  300. Event.stopPropagation();
  301. }
  302. });
  303. // click event for whole table row
  304. $('.MasterAction').off('click').on('click', function (Event) {
  305. $MasterActionLink = $(this).find('.MasterActionLink');
  306. // prevent MasterAction on Dynamic Fields links
  307. if ($(Event.target).hasClass('DynamicFieldLink')) {
  308. return true;
  309. }
  310. // only act if the link was not clicked directly
  311. if (Event.target !== $MasterActionLink.get(0)) {
  312. if (Event.ctrlKey || Event.metaKey) {
  313. Core.UI.Popup.open($MasterActionLink.attr('href'));
  314. }
  315. else {
  316. window.location = $MasterActionLink.attr('href');
  317. }
  318. return false;
  319. }
  320. });
  321. // click event for opening popup
  322. $('a.AsPopup').on('click', function () {
  323. Matches = $(this).attr('class').match(/PopupType_(\w+)/);
  324. if (Matches) {
  325. PopupType = Matches[1];
  326. }
  327. Core.UI.Popup.OpenPopup($(this).attr('href'), PopupType);
  328. return false;
  329. });
  330. if ($('body').hasClass('TouchDevice')) {
  331. $('ul.InlineActions li:not(.ResponsiveActionMenu)').hide();
  332. }
  333. $('li.ResponsiveActionMenu').on('click.ToggleResponsiveActionMenu', function () {
  334. $(this).siblings().toggle();
  335. $(this).toggleClass('Opened');
  336. return false;
  337. });
  338. };
  339. /**
  340. * @name InitViewPreview
  341. * @memberof Core.Agent.Overview
  342. * @function
  343. * @description
  344. * This function initializes JS functionality for view Preview (Large).
  345. */
  346. TargetNS.InitViewPreview = function () {
  347. var Matches, PopupType = 'TicketAction',
  348. $MasterActionLink,
  349. URL, Index, ReplyFieldsFormID = Core.Config.Get('ReplyFieldsFormID');
  350. /**
  351. * @private
  352. * @name ReplyFieldsOnChange
  353. * @memberof Core.Agent.Overview
  354. * @function
  355. * @param {Number} FormID - ID of element
  356. * @description
  357. * Bind change event for element which ID is FormID.
  358. */
  359. function ReplyFieldsOnChange (FormID) {
  360. $('#' + FormID + ' select[name=ResponseID]').on('change', function () {
  361. if ($(this).val() > 0) {
  362. URL = Core.Config.Get('Baselink') + $(this).parents().serialize();
  363. Core.UI.Popup.OpenPopup(URL, 'TicketAction');
  364. // reset the select box so that it can be used again from the same window
  365. $(this).val('0');
  366. }
  367. });
  368. }
  369. /**
  370. * @private
  371. * @name ReplyFieldsOnClick
  372. * @memberof Core.Agent.Overview
  373. * @function
  374. * @param {Number} FormID - ID of element
  375. * @description
  376. * Bind click event for element which ID is FormID.
  377. */
  378. function ReplyFieldsOnClick (FormID) {
  379. $('#' + FormID + ' select[name=ResponseID]').on('click', function (Event) {
  380. Event.stopPropagation();
  381. return false;
  382. });
  383. }
  384. // initializes a click event for div with checkboxes
  385. Core.UI.InitCheckboxSelection($('div.Checkbox'));
  386. // initialize inline actions overlay
  387. TargetNS.InitInlineActions();
  388. // initializes the accordion effect on the specified list
  389. Core.UI.Accordion.Init($('.Preview > ul'), 'li h3 a', '.HiddenBlock');
  390. Core.App.Subscribe('Event.UI.Accordion.OpenElement', function($Element) {
  391. Core.UI.InputFields.Activate($Element);
  392. });
  393. // Stop propagation on click on a part of the InlienActionRow without a link
  394. // Otherwise that would trigger the li-wide link to the ticketzoom
  395. $('ul.InlineActions').click(function (Event) {
  396. Event.cancelBubble = true;
  397. if (Event.stopPropagation) {
  398. Event.stopPropagation();
  399. }
  400. });
  401. // click event for opening popup
  402. $('a.AsPopup').on('click', function () {
  403. Matches = $(this).attr('class').match(/PopupType_(\w+)/);
  404. if (Matches) {
  405. PopupType = Matches[1];
  406. }
  407. Core.UI.Popup.OpenPopup($(this).attr('href'), PopupType);
  408. return false;
  409. });
  410. // click event for whole table row
  411. $('.MasterAction').off('click').on('click', function (Event) {
  412. $MasterActionLink = $(this).find('.MasterActionLink');
  413. // If the user is trying to select text from or use article actions, MasterAction should not be executed.
  414. if (
  415. typeof Event.target === 'object'
  416. && (
  417. $(Event.target).hasClass('ArticleBody')
  418. || $(Event.target).hasClass('ItemActions')
  419. || $(Event.target).parents('.Actions').length
  420. )
  421. )
  422. {
  423. return true;
  424. }
  425. // prevent MasterAction on Dynamic Fields links
  426. if ($(Event.target).hasClass('DynamicFieldLink')) {
  427. return true;
  428. }
  429. // Prevent MasterAction on Modernize input fields.
  430. if ($(Event.target).hasClass('InputField_Search')) {
  431. return true;
  432. }
  433. // only act if the link was not clicked directly
  434. if (Event.target !== $MasterActionLink.get(0)) {
  435. if (Event.ctrlKey || Event.metaKey) {
  436. Core.UI.Popup.open($MasterActionLink.attr('href'));
  437. }
  438. else {
  439. window.location = $MasterActionLink.attr('href');
  440. }
  441. return false;
  442. }
  443. });
  444. // bind events on Reply dropdown elements
  445. if (typeof ReplyFieldsFormID !== 'undefined') {
  446. for (Index in ReplyFieldsFormID) {
  447. ReplyFieldsOnChange(ReplyFieldsFormID[Index]);
  448. ReplyFieldsOnClick(ReplyFieldsFormID[Index]);
  449. }
  450. }
  451. if ($('body').hasClass('TouchDevice')) {
  452. $('ul.InlineActions li:not(.ResponsiveActionMenu)').hide();
  453. }
  454. $('li.ResponsiveActionMenu').on('click.ToggleResponsiveActionMenu', function () {
  455. $(this).siblings().toggle();
  456. $(this).toggleClass('Opened');
  457. return false;
  458. });
  459. };
  460. Core.Init.RegisterNamespace(TargetNS, 'APP_MODULE');
  461. return TargetNS;
  462. }(Core.Agent.Overview || {}));

^ Use Elevator