log_filter.js 111 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932
  1. /**
  2. * @file
  3. * Drupal Log Filter module
  4. */
  5. /*jslint browser: true, continue: true, indent: 2, newcap: true, nomen: true, plusplus: true, regexp: true, white: true, ass: true*/
  6. /*global alert: false, confirm: false, console: false*/
  7. /*global jQuery: false, Drupal: false, inspect: false, Judy: false*/
  8. /**
  9. * @param {function} $
  10. * @returns {object}
  11. */
  12. (function($) {
  13. 'use strict';
  14. /**
  15. * Singleton, instantiated to itself.
  16. * @constructor
  17. * @namespace
  18. * @name LogFilter
  19. * @singleton
  20. * @param {function} $
  21. */
  22. var LogFilter = function($) {
  23. /**
  24. * @ignore
  25. * @private
  26. * @type {LogFilter}
  27. */
  28. var self = this,
  29. /**
  30. * @ignore
  31. * @private
  32. * @type {string}
  33. */
  34. _name = "LogFilter",
  35. /**
  36. * @ignore
  37. * @private
  38. * @type {object}
  39. */
  40. _errorCodes = {
  41. unknown: 1,
  42. // Programmatic errors and wrong use of program.
  43. algo: 100,
  44. use: 101,
  45. // Missing permission.
  46. perm_general: 200,
  47. form_expired: 201,
  48. perm_filter_crud: 202,
  49. perm_filter_restricted: 203,
  50. // Database.
  51. db_general: 500,
  52. // Misc.
  53. filter_name_composition: 1001,
  54. filter_name_nonunique: 1002,
  55. filter_doesnt_exist: 1003,
  56. bad_filter_condition: 1010
  57. },
  58. /**
  59. * @ignore
  60. * @private
  61. * @type {object}
  62. */
  63. _ = {
  64. // {arr}
  65. errors: [],
  66. dateFormat: "YYYY-MM-DD",
  67. dateFormat_datepicker: "yy-mm-dd",
  68. mode: "default", // default | adhoc | stored | create | edit | delete_filter
  69. modePrevious: "default",
  70. name: "",
  71. origin: "",
  72. crudFilters: false,
  73. recordedValues: { // For some fields (having pattern validation) we have to record last value to safely detect change.
  74. time_range: "",
  75. uid: "",
  76. hostname: "",
  77. location: "",
  78. referer: "",
  79. orderBy: [],
  80. type_options: []
  81. },
  82. deleteLogs_allowed: false,
  83. saveEditFilterAjaxed: false, // Save/update filter using AJAX or ordinary POST request?
  84. listMessageTruncate: 250,
  85. adminOverlayOffset: 80, // Module Overlay.
  86. currentOffset: 0,
  87. currentMax: 100,
  88. logs: {},
  89. library_judy_version: 2.1,
  90. library_judy_compatible: true
  91. },
  92. /**
  93. * @ignore
  94. * @private
  95. * @type {array}
  96. */
  97. _severity = ['emergency', 'alert', 'critical', 'error', 'warning', 'notice', 'info', 'debug'],
  98. /**
  99. * @ignore
  100. * @private
  101. * @type {boolean|undefined}
  102. */
  103. _submitted,
  104. /**
  105. * @ignore
  106. * @private
  107. * @type {boolean|undefined}
  108. */
  109. _ajaxRequestingBlocking,
  110. /**
  111. * List of previously used localized labels/messages.
  112. *
  113. * @ignore
  114. * @private
  115. * @type {object}
  116. */
  117. _local = {},
  118. /**
  119. * @ignore
  120. * @private
  121. * @type {object}
  122. */
  123. _selectors = {
  124. page: "div#page",
  125. form: "form#log-filter-form",
  126. settings: {
  127. mode: "input[name='log_filter_mode']",
  128. onlyOwn: "input[name='log_filter_only_own']",
  129. delete_logs_max: "input[name='log_filter_delete_logs_max']", // May not exist.
  130. translate: "input[name='log_filter_translate']",
  131. pager_range: "input[name='log_filter_pager_range']"
  132. },
  133. filter: {
  134. filter: "select[name='log_filter_filter']",
  135. name: "input[name='log_filter_name']", // Hidden.
  136. origin: "input[name='log_filter_origin']", // Hidden.
  137. name_suggest: "input[name='log_filter_name_suggest']",
  138. description: "textarea[name='log_filter_description']",
  139. require_admin: "input[name='log_filter_require_admin']" // May not exist.
  140. },
  141. conditions: {
  142. time_range: "input[name='log_filter_time_range']", // For iteration: must go before the other time fields.
  143. time_from: "input[name='log_filter_time_from']",
  144. time_from_proxy: "input[name='log_filter_time_from_proxy']",
  145. time_to: "input[name='log_filter_time_to']",
  146. time_to_proxy: "input[name='log_filter_time_to_proxy']",
  147. severity_any: "input[name='log_filter_severity[-1]']", // For iteration: must go before severity_some.
  148. severity_some: "div#edit-log-filter-severity input:not([name='log_filter_severity[-1]'])", // More elements.
  149. type_any: "input[name='log_filter_type_wildcard']", // For iteration: must go before type_proxy.
  150. type_some: "textarea[name='log_filter_type']", // For iteration: must go before type_proxy.
  151. type_proxy: "div#edit-log-filter-type-proxy input", // We only store the first, because we only need one for getting/setting value.
  152. role: "select[name='log_filter_role']", // For iteration: must go before uid.
  153. uid: "input[name='log_filter_uid']",
  154. username: "input[name='log_filter_username']",
  155. hostname: "input[name='log_filter_hostname']",
  156. location: "input[name='log_filter_location']",
  157. referer: "input[name='log_filter_referer']"
  158. },
  159. orderBy: {
  160. options: "div.filter-orderby select",
  161. bools: "div.filter-orderby input[type='checkbox']"
  162. },
  163. buttons: {
  164. // Not part of filter dialog.
  165. submit: "input#edit-submit",
  166. update_list: "input[name='log_filter_update_list']",
  167. reset: "input[name='log_filter_reset']",
  168. // Filter dialog.
  169. create: "input[name='log_filter_create']",
  170. edit: "input[name='log_filter_edit']",
  171. delete_filter: "input[name='log_filter_delete']",
  172. cancel: "input[name='log_filter_cancel']",
  173. save: "input[name='log_filter_save']", // Doesnt exist if user isnt permitted to create|edit|save filter.
  174. delete_logs_button: "input[name='log_filter_delete_logs_button']"
  175. },
  176. pager: {
  177. first: 'div#log_filter_pager_first',
  178. previous: 'div#log_filter_pager_previous',
  179. current: 'div#log_filter_pager_current',
  180. progress: 'div#log_filter_pager_progress',
  181. next: 'div#log_filter_pager_next',
  182. last: 'div#log_filter_pager_last'
  183. },
  184. misc: {
  185. title: "#log_filter_title_display"
  186. }
  187. },
  188. _elements = {
  189. settings: {},
  190. filter: {},
  191. conditions: {},
  192. orderBy: [], // Array.
  193. buttons: {
  194. crudFilters: [] // create, edit, delete_filter, cancel, save.
  195. },
  196. pager: {
  197. },
  198. misc: {
  199. }
  200. },
  201. /**
  202. * @ignore
  203. * @private
  204. * @type {array}
  205. */
  206. _filters = [],
  207. /**
  208. * @ignore
  209. * @private
  210. * @type {object}
  211. */
  212. _logs = {},
  213. // Declare private methods, to make IDEs list them
  214. _errorHandler, _oGet, _toAscii,
  215. _textareaRemoveWrapper,
  216. _machineNameConvert, _machineNameIllegals, _machineNameValidate,
  217. _validateTimeSequence,
  218. _url, _submit, _typeProxyHandler, _prepareForm, _setMode, _crudRelay, _changedCriterion, _resetCriteria, _deleteLogs, _filterByEventColumn,
  219. _getLogList, _listLogs,
  220. _ajaxResponse, _ajaxRequest;
  221. /**
  222. * @see inspect.errorHandler
  223. * @ignore
  224. * @private
  225. * @param {Error} [error]
  226. * @param {mixed} [variable]
  227. * @param {object|integer|boolean|string} [options]
  228. * @return {void}
  229. */
  230. _errorHandler = function(error, variable, options) {
  231. var u = options, o = {}, t;
  232. // Do nothing, if inspect is the 'no action' type.
  233. if(typeof window.inspect === "function" && inspect.tcepsni) {
  234. if(typeof inspect.errorHandler === "function") {
  235. if(u) {
  236. if((t = typeof u) === "string") {
  237. o.message = u;
  238. o.wrappers = 1; // This function wraps Inspect.errorHandler().
  239. }
  240. else if(t === "object") {
  241. o = u;
  242. o.wrappers = !u.wrappers ? 1 : (u.wrappers + 1);
  243. }
  244. // Otherwise: ignore; use object argument for options if other properties are needed.
  245. }
  246. o.category = "log_filter";
  247. inspect.errorHandler(error, variable, o);
  248. }
  249. else {
  250. inspect.console("Please update Inspect.");
  251. }
  252. }
  253. };
  254. /**
  255. * Object/function property getter, Object.hasOwnproperty() alternative.
  256. *
  257. * @ignore
  258. * @param {object} o
  259. * @param {string|integer} k0
  260. * @param {string|integer} [k1]
  261. * @return {mixed}
  262. * - undefined: o not object, or o doesnt have property k0, or the value of o[k1] is undefined; and the same goes if arg k1 is used
  263. */
  264. _oGet = function(o, k0, k1) {
  265. var t = typeof o;
  266. return o && (t === "object" || t === "function") && o.hasOwnProperty(k0) ?
  267. (k1 === undefined ? o[k0] : (
  268. (o = o[k0]) && ((t = typeof o) === "object" || t === "function") && o.hasOwnProperty(k1) ? o[k1] : undefined
  269. ) ) : undefined;
  270. };
  271. _toAscii = function(s) {
  272. var ndl = _toAscii.needles, rpl = _toAscii.replacers, le = ndl.length, i, u;
  273. if(typeof ndl[0] === "string") { // First time called.
  274. u = ndl.concat();
  275. for(i = 0; i < le; i++) {
  276. ndl[i] = new RegExp("\\u" + Judy.toLeading(u[i].charCodeAt(0).toString(16), 4), "g");
  277. }
  278. }
  279. for(i = 0; i < le; i++) {
  280. s = s.replace(ndl[i], rpl[i]);
  281. }
  282. return s;
  283. };
  284. /**
  285. * Removes parent form-textarea-wrapper div from (non-resizable) textarea, for easier (standard) DOM access.
  286. *
  287. * @ignore
  288. * @param {element} elm
  289. * @return {void}
  290. */
  291. _textareaRemoveWrapper = function(elm) {
  292. var jq;
  293. if ((jq = $(elm.parentNode)).hasClass("form-textarea-wrapper")) {
  294. jq.after( $(elm).remove() );
  295. jq.remove();
  296. }
  297. };
  298. _toAscii.needles = [
  299. // iso-8859-1
  300. //JSLINT_IGNORE--- jslint unsafe chars,but _toAscii() starts out converting them to \uNNNN regexes.
  301. "Ä","Æ","ä","æ","Ö","Ø","ö","ø","Ü","ü","ß","Å","å","À","Á","Â","Ã","à","á","â","ã","Ç","ç","Ð","ð","È","É","Ê","Ë","è","é","ê","ë","Ì","Í","Î","Ï","ì","í","î","ï","Ñ","ñ","Ò","Ó","Ô","Õ","ò","ó","ô","õ","Ù","Ú","Û","ù","ú","û","Ý","ý","ÿ","Þ","þ"
  302. //---JSLINT_IGNORE
  303. ];
  304. _toAscii.replacers = [
  305. // iso-8859-1
  306. "Ae","Ae","ae","ae","Oe","Oe","oe","oe","Ue","ue","ss","Aa","aa","A","A","A","A","a","a","a","a","C","c","D","d","E","E","E","E","e","e","e","e","I","I","I","I","i","i","i","i","N","n","O","O","O","O","o","o","o","o","U","U","U","u","u","u","Y","y","y","Th","th"
  307. ];
  308. /**
  309. * @ignore
  310. * @return {void}
  311. */
  312. _machineNameConvert = function() {
  313. var v = this.value, rgx = /^[a-z\d_]$/;
  314. if(v.length > 1 && !rgx.test(v)) {
  315. if(!rgx.test(v = v.toLowerCase())) {
  316. if(!rgx.test(v = v.replace(/[ \-]/g, "_"))) {
  317. if(!rgx.test(v = _toAscii(v))) {
  318. v = v.replace(/[^a-z\d_]/g, "_");
  319. }
  320. }
  321. }
  322. this.value = v;
  323. }
  324. };
  325. /**
  326. * @ignore
  327. * @type {array}
  328. */
  329. _machineNameIllegals = [
  330. "log_filter",
  331. "default",
  332. "adhoc"
  333. ];
  334. /**
  335. * @ignore
  336. * @param {Event|falsy} evt
  337. * - default: falsy (~ use arg elm)
  338. * @param {element} [elm]
  339. * - default: falsy (~ use arg value)
  340. * @param {string} [value]
  341. * @param {boolean} [noFeedback]
  342. * - default: false (~ do pop alert upon validation failure)
  343. * @return {boolean}
  344. */
  345. _machineNameValidate = function(evt, elm, value, noFeedback) {
  346. var v = evt ? this.value : (elm ? elm.value : value), le = v.length;
  347. if(le < 2 || le > 32 || !/[a-z_]/.test(v.charAt(0)) || !/[a-z\d_]/.test(v) || $.inArray(v.toLowerCase(), _machineNameIllegals) > -1) {
  348. if(!noFeedback) {
  349. self.Message.set( self.local("error_machine_name_composition", {"!illegals": _machineNameIllegals.join(", ")}), "warning", {
  350. modal: true,
  351. close: function() {
  352. Judy.focus(_elements.filter.name_suggest);
  353. }
  354. });
  355. }
  356. return false;
  357. }
  358. return true;
  359. };
  360. /**
  361. * @ignore
  362. * @param {string} nm
  363. * @param {boolean} [date]
  364. * @return {boolean}
  365. */
  366. _validateTimeSequence = function(nm, date) {
  367. var o = _elements.conditions, v, from = (v = o.time_from.value) ? parseInt(v, 10) : 0, to;
  368. if (from && (to = (v = o.time_to.value) ? parseInt(v, 10) : 0) && from > to) {
  369. // Date To and From must be allowed to be the same, otherwise user can't enter same date.
  370. if (date && $.trim(o.time_to_proxy.value) === $.trim(o.time_from_proxy.value)) {
  371. return true;
  372. }
  373. o[ "time_" + nm ].value = o[ "time_" + nm + "_proxy" ].value = o[ "time_" + nm + "_time" ].value = "";
  374. self.Message.set( self.local("invalid_timeSequence_" + nm), "warning", { modal: true });
  375. return false;
  376. }
  377. return true;
  378. };
  379. /**
  380. * @ignore
  381. * @param {boolean} [top]
  382. * - default: false (~ use current window's location, not top.location)
  383. * @return {string}
  384. */
  385. _url = function(top) {
  386. var loc = (!top ? window : top).location, v;
  387. return loc.protocol + "//" + loc.hostname + (!(v = loc.port) ? "" : (":" + v)) + loc.pathname.replace(/\/dblog(\/.+)?$/, "/dblog/log_filter");
  388. };
  389. /**
  390. * @ignore
  391. * @return {void}
  392. */
  393. _submit = function() {
  394. var nm = "", elm;
  395. if(_submitted) {
  396. return;
  397. }
  398. _submitted = true;
  399. switch(_.mode) {
  400. case "adhoc":
  401. nm = "adhoc";
  402. break;
  403. case "stored":
  404. nm = _.name;
  405. break;
  406. }
  407. // Add filter name to action url.
  408. _elements.form.setAttribute(
  409. "action",
  410. _elements.form.getAttribute("action").replace(/\/dblog(\/[^\?&]+)([\?&].+)?$/, "/dblog/log_filter/" + nm + "$2")
  411. );
  412. // Delay; otherwise it may in some situations not submit, presumably because Judy.enable() hasnt finished it's job yet(?).
  413. setTimeout(function() {
  414. $(_elements.buttons.submit).trigger("click");
  415. }, 100);
  416. };
  417. /**
  418. * @ignore
  419. * @return {void}
  420. */
  421. _typeProxyHandler = function() {
  422. var v, i;
  423. if(this.checked) { // Un-check type_any.
  424. _elements.conditions.type_any.checked = false;
  425. // Pass value to type_some.
  426. if (Judy.arrayIndexOf(v = $.trim(_elements.conditions.type_some.value).split(/\n/), this.value) === -1) {
  427. v.push(this.value);
  428. _elements.conditions.type_some.value = $.trim(v.join("\n"));
  429. }
  430. }
  431. else {
  432. // Remove from hidden type_some.
  433. if ((i = Judy.arrayIndexOf(v = $.trim(_elements.conditions.type_some.value).split(/\n/), this.value)) > -1) {
  434. v.splice(i, 1);
  435. if (v.length) {
  436. _elements.conditions.type_some.value = $.trim(v.join("\n"));
  437. }
  438. else {
  439. _elements.conditions.type_some.value = "";
  440. _elements.conditions.type_any.checked = "checked";
  441. }
  442. }
  443. }
  444. _changedCriterion();
  445. };
  446. /**
  447. * @ignore
  448. * @return {void}
  449. */
  450. _prepareForm = function() {
  451. var oSels, oElms, nm, jq, elm, par, aElms, a, le, i, v, nOrderBy, u, elm2, d;
  452. try {
  453. _elements.page = $(_selectors.page).get(0);
  454. _elements.form = $(_selectors.form).get(0);
  455. // Filter; do first because we need references to name and origin.
  456. oSels = _selectors.filter;
  457. oElms = _elements.filter;
  458. for(nm in oSels) {
  459. if(oSels.hasOwnProperty(nm) && (elm = (jq = $(oSels[nm])).get(0))) {
  460. oElms[nm] = elm;
  461. switch(nm) {
  462. case "filter":
  463. // Selecting a stored filter means submit form.
  464. jq.change(function() {
  465. var v;
  466. _elements.filter.name.value = _.name = v = Judy.fieldValue(this);
  467. _elements.settings.mode.value = _.mode = v ? "stored" : "default";
  468. if(!v) { // default|adhoc
  469. _resetCriteria(null, "default");
  470. return;
  471. }
  472. Judy.overlay(1, false, self.local("wait")); // Transparent.
  473. _submit();
  474. });
  475. break;
  476. case "name_suggest": // May not exist.
  477. jq.keyup(_machineNameConvert);
  478. break;
  479. case "description": // May not exist.
  480. _textareaRemoveWrapper(elm); // Remove parent form-textarea-wrapper.
  481. jq.change(function() {
  482. var v;
  483. if((v = this.value)) {
  484. this.value = Judy.stripTags(v);
  485. }
  486. });
  487. break;
  488. }
  489. }
  490. }
  491. _.name = _elements.filter.name.value;
  492. _.origin = _elements.filter.origin.value;
  493. // Fields; get element references, and fix some issues.
  494. // Settings.
  495. oSels = _selectors.settings;
  496. oElms = _elements.settings;
  497. for(nm in oSels) {
  498. if(oSels.hasOwnProperty(nm) && (elm = (jq = $(oSels[nm])).get(0))) {
  499. oElms[nm] = elm;
  500. switch(nm) {
  501. case "mode":
  502. // Get mode.
  503. _.mode = elm.value;
  504. break;
  505. case "onlyOwn": // May not exist.
  506. // Submit if user (un)checks filter_only_own.
  507. jq.change(function() {
  508. if(_.mode === "stored") {
  509. _elements.settings.mode.value = "adhoc";
  510. Judy.fieldValue(_elements.filter.filter, null, "");
  511. _elements.filter.origin.value = _.name; // Pass name to origin.
  512. _elements.filter.name.value = "";
  513. }
  514. Judy.overlay(1, false, self.local("wait")); // Transparent.
  515. _submit();
  516. });
  517. break;
  518. case "delete_logs_max": // May not exist.
  519. jq.change(function() {
  520. var v = this.value;
  521. if(v !== "") {
  522. if((v = $.trim(v)) !== "" && !/^[1-9]\d*$/.test(v)) {
  523. v = "";
  524. }
  525. this.value = v;
  526. }
  527. });
  528. break;
  529. case "pager_range":
  530. _.currentMax = parseInt(elm.value, 10);
  531. // Pass value to delete max logs field.
  532. if ($(_selectors.buttons.delete_logs_button).get(0)) {
  533. oElms.delete_logs_max.value = _.currentMax;
  534. }
  535. jq.change(function() {
  536. var v = this.value, n, m;
  537. if(v !== "") {
  538. if((v = $.trim(v)) !== "" && /^\d+$/.test(v)) {
  539. _.currentMax = n = parseInt(v, 10);
  540. if (_.deleteLogs_allowed &&
  541. ((m = _elements.settings.delete_logs_max.value) === '' || (m = parseInt(m, 10)) > n)
  542. ) {
  543. _elements.settings.delete_logs_max.value = n;
  544. }
  545. }
  546. else {
  547. v = "";
  548. }
  549. this.value = v;
  550. }
  551. });
  552. break;
  553. }
  554. }
  555. }
  556. // Conditions.
  557. oSels = _selectors.conditions;
  558. oElms = _elements.conditions;
  559. for(nm in oSels) {
  560. if(oSels.hasOwnProperty(nm) && (elm = (jq = $(oSels[nm])).get(0))) {
  561. switch(nm) {
  562. case "time_range":
  563. oElms[nm] = elm;
  564. _.recordedValues[nm] = elm.value;
  565. // Clear time_to and time_from when setting a time_range.
  566. jq.change(function() {
  567. var v = this.value, o;
  568. if(v !== "") {
  569. this.value = v = $.trim(v);
  570. }
  571. if(v !== "") {
  572. if(v === "0" || !/^[1-9]\d*$/.test(v)) {
  573. this.value = v = "";
  574. }
  575. else {
  576. if (v.length > 4) {
  577. this.value = v = '9999';
  578. }
  579. (o = _elements.conditions).time_from.value =
  580. o.time_from_proxy.value =
  581. o.time_from_time.value =
  582. o.time_to.value =
  583. o.time_to_proxy.value =
  584. o.time_to_time.value = "";
  585. }
  586. }
  587. if(v !== _.recordedValues.time_range) {
  588. _.recordedValues.time_range = v;
  589. _changedCriterion();
  590. }
  591. });
  592. break;
  593. case "time_from": // Hidden fields.
  594. case "time_to":
  595. oElms[nm] = elm;
  596. break;
  597. case "time_from_proxy":
  598. case "time_to_proxy":
  599. oElms[nm] = elm;
  600. u = nm === "time_from_proxy" ? "from" : "to";
  601. // Create time field.
  602. jq.after(
  603. "<input class=\"form-text\" type=\"text\" maxlength=\"8\" size=\"8\" value=\"\" name=\"log_filter_time_" + u + "_time\" autocomplete=\"off\" />"
  604. );
  605. // Put jQuery UI datepicker on time fields.
  606. jq.datepicker({
  607. dateFormat: _.dateFormat_datepicker
  608. });
  609. // Refer time field.
  610. oElms[ "time_" + u + "_time" ] = elm2 = $("input[name=\'log_filter_time_" + u + "_time\']").get(0);
  611. // Set datepicker and time field values.
  612. if((v = _elements.conditions[ u === "from" ? "time_from" : "time_to" ].value) && (v = parseInt(v, 10))) {
  613. jq.datepicker("setDate", d = new Date(v * 1000));
  614. elm2.value = Judy.timeFormat(d);
  615. }
  616. // Date proxy field handler.
  617. jq.change(function() {
  618. var v, d, nm = this.name.indexOf("from") > 1 ? "from" : "to", r = _elements.conditions[ "time_" + nm ],
  619. rT = _elements.conditions[ "time_" + nm + "_time" ];
  620. if((v = $.trim(this.value)).length) {
  621. if((d = Judy.dateFromFormat(v, _.dateFormat))) {
  622. _.recordedValues.time_range = _elements.conditions.time_range.value = ""; // Clear time_range.
  623. rT.value = Judy.timeFormat(d, rT.value);
  624. r.value = v = Math.floor(d.getTime() / 1000);
  625. // If time_to, and same as time_from, and no hours/minutes/seconds: make time_to the end of the day.
  626. if(nm === "to" && ("" + v) === _elements.conditions.time_from.value &&
  627. d.getHours() === 0 && d.getMinutes() === 0 && d.getSeconds() === 0
  628. ) {
  629. rT.value = Judy.timeFormat(d, "24");
  630. r.value = Math.floor(d.getTime() / 1000);
  631. }
  632. else {
  633. _validateTimeSequence(nm, true);
  634. }
  635. }
  636. else {
  637. self.Message.set( self.local("invalid_date", {"!date": v, "!format": _.dateFormat}), "warning", { modal: true });
  638. r.value = "";
  639. return; // No change, skip _changedCriterion()
  640. }
  641. }
  642. _changedCriterion();
  643. });
  644. // Time field handler.
  645. $(elm2).change(function() {
  646. var nm = this.name.indexOf("from") > -1 ? "from" : "to", rD = _elements.conditions[ "time_" + nm ], d;
  647. // Cant set time when no date.
  648. if(!(d = rD.value)) {
  649. this.value = "";
  650. return;
  651. }
  652. d = new Date(d * 1000);
  653. this.value = Judy.timeFormat(d, this.value);
  654. rD.value = Math.floor(d / 1000);
  655. _validateTimeSequence(nm);
  656. _changedCriterion();
  657. });
  658. break;
  659. case "severity_any":
  660. oElms[nm] = elm;
  661. // Un-check specific severities upon checking severity:any.
  662. jq.change(function() {
  663. var a = _elements.conditions.severity_some, le = a.length, i, v;
  664. if(this.checked) { // Un-check all severity_some.
  665. for(i = 0; i < le; i++) {
  666. a[i].checked = false;
  667. }
  668. }
  669. else { // If no severity_some, re-check severity_any.
  670. for(i = 0; i < le; i++) {
  671. if(a[i].checked) {
  672. v = true;
  673. break;
  674. }
  675. }
  676. if(!v) {
  677. this.checked = "checked";
  678. return; // No change.
  679. }
  680. }
  681. _changedCriterion();
  682. });
  683. break;
  684. case "severity_some": // More elements.
  685. oElms[nm] = jq.get();
  686. // Un-check severity:any upon change in list of severity.
  687. jq.change(function() {
  688. var a, le, i, someChecked;
  689. if(this.checked) {
  690. _elements.conditions.severity_any.checked = false;
  691. }
  692. else {
  693. le = (a = _elements.conditions.severity_some).length;
  694. for(i = 0; i < le; i++) {
  695. if(a[i].checked) {
  696. someChecked = true;
  697. break;
  698. }
  699. }
  700. if(!someChecked) {
  701. _elements.conditions.severity_any.checked = "checked";
  702. }
  703. }
  704. _changedCriterion();
  705. });
  706. break;
  707. case "type_any": // check list
  708. oElms[nm] = elm;
  709. jq.change(function() {
  710. var elm;
  711. if(this.checked) {
  712. _elements.conditions.type_some.value = "";
  713. Judy.fieldValue(_elements.conditions.type_proxy, null, "", "checkboxes");
  714. }
  715. _changedCriterion();
  716. });
  717. break;
  718. case "type_some": // Real name: log_filter_type.
  719. oElms[nm] = elm;
  720. _textareaRemoveWrapper(elm);
  721. elm.value = elm.value.replace(/\r/g, '');
  722. break;
  723. case "type_proxy": // check list
  724. oElms[nm] = elm;
  725. // Un-name checklist options, to prevent backend validation error (Illegal choice...).
  726. // And make list of all options.
  727. $("input[type='checkbox']", par = Judy.ancestor(elm, 'div.form-checkboxes')).each(function() {
  728. this.id = '';
  729. this.setAttribute('name', '');
  730. _.recordedValues.type_options.push(this.value);
  731. });
  732. // Pass values from type_some (hidden textarea; real name: log_filter_type).
  733. Judy.fieldValue(_elements.conditions.type_proxy, _elements.form, $.trim(_elements.conditions.type_some.value).split(/\n/), "checkboxes");
  734. jq.change(_typeProxyHandler);
  735. // Insert 'Add type' option.
  736. $(par).prepend(
  737. '<div class="form-item form-type-checkbox">' +
  738. '<input type="checkbox" class="form-checkbox" value="" name="log_filter_type_proxy_add_item" autocomplete="off" />' +
  739. ' <input type="text" value="" name="log_filter_type_proxy_add_item_value" autocomplete="off" class="form-text" placeholder="' +
  740. self.local('add_type_item') + '" />' +
  741. '</div>'
  742. );
  743. $('input[name="log_filter_type_proxy_add_item"]', _elements.form).change(function() {
  744. var elm, v;
  745. if (this.checked) {
  746. elm = $('input[name="log_filter_type_proxy_add_item_value"]', _elements.form).get(0);
  747. if ((v = elm.value) && (v = $.trim(Judy.stripTags(v.replace(/[\r\n]/g, ''))))) {
  748. if (Judy.arrayIndexOf(_.recordedValues.type_options, v) === -1) { // IDE may wrongly report error.
  749. _.recordedValues.type_options.push(v);
  750. _elements.conditions.type_some.value += (_elements.conditions.type_some.value ? "\n" : '') + v;
  751. $(elm.parentNode).after(
  752. '<div class="form-item form-type-checkbox">' +
  753. '<input type="checkbox" class="form-checkbox" value="' + v + '" checked="checked" />' +
  754. ' <label class="option">' + v + '</label>' +
  755. '</div>'
  756. );
  757. $('input[value="' + v +'"]', par).change(_typeProxyHandler);
  758. _elements.conditions.type_any.checked = false;
  759. }
  760. else {
  761. self.Message.set(self.local('type_option_dupe', { '!option': v }), "warning", {
  762. modal: true,
  763. close: function() {
  764. Judy.focus(elm);
  765. }
  766. });
  767. }
  768. }
  769. this.checked = false;
  770. elm.value = '';
  771. }
  772. });
  773. break;
  774. case "role":
  775. oElms[nm] = elm;
  776. // Clear uid when selecting a role.
  777. jq.change(function() {
  778. if(Judy.fieldValue(this)) {
  779. _elements.conditions.uid.value = _elements.conditions.username.value = "";
  780. }
  781. _changedCriterion();
  782. });
  783. break;
  784. case "uid":
  785. oElms[nm] = elm;
  786. _.recordedValues[nm] = elm.value;
  787. // Clear role when setting a uid.
  788. jq.change(function() {
  789. var v = this.value;
  790. if(v !== "") {
  791. this.value = v = $.trim(v);
  792. }
  793. if(v !== "") {
  794. if(!/^\d+$/.test(v)) {
  795. self.Message.set( self.local("invalid_uid"), "warning", {
  796. modal: true,
  797. close: function() {
  798. Judy.focus(_elements.conditions.uid);
  799. }
  800. });
  801. this.value = v = "";
  802. }
  803. else {
  804. // Clear role when setting a uid.
  805. Judy.fieldValue(_elements.conditions.role, null, "");
  806. _elements.conditions.username.value = '';
  807. }
  808. }
  809. // Always clear username when setting uid.
  810. _elements.conditions.username.value = '';
  811. if(v !== _.recordedValues.uid) {
  812. _.recordedValues.uid = v;
  813. _changedCriterion();
  814. }
  815. });
  816. break;
  817. case "username":
  818. oElms[nm] = elm;
  819. $(elm).autocomplete({
  820. source: "/log_filter/ajax/username_autocomplete",
  821. minLength: 2,
  822. select: function(event, ui) {
  823. var v;
  824. if (ui.item) {
  825. _elements.conditions.uid.value = (v = ui.item.value);
  826. _elements.conditions.username.value = ui.item.label;
  827. if(v !== _.recordedValues.uid) {
  828. _.recordedValues.uid = v;
  829. Judy.fieldValue(_elements.conditions.role, null, ""); // Clear role when setting a uid.
  830. _changedCriterion();
  831. }
  832. }
  833. return false;
  834. }
  835. }).bind('autocompletesearch', function() {
  836. $(this).addClass('throbbing');
  837. }).bind('autocompleteresponse', function() { // Doesnt work, propably old version of jQuery UI.
  838. $(this).removeClass('throbbing');
  839. });
  840. Judy.ajaxcomplete(_selectors.conditions.username, '/log_filter/ajax/username_autocomplete', function(event) { // This works, instead.
  841. $(this).removeClass('throbbing');
  842. });
  843. break;
  844. case "hostname":
  845. oElms[nm] = elm;
  846. _.recordedValues[nm] = elm.value;
  847. jq.change(function() {
  848. var v = this.value;
  849. if(v !== "") {
  850. this.value = v = Judy.stripTags(v);
  851. }
  852. if(v !== _.recordedValues.hostname) {
  853. _.recordedValues.hostname = v;
  854. _changedCriterion();
  855. }
  856. });
  857. break;
  858. case "location":
  859. case "referer":
  860. oElms[nm] = elm;
  861. _.recordedValues[nm]= elm.value;
  862. // Check for url pattern.
  863. jq.change(function() {
  864. var v = $.trim(this.value), nm = this.name === "log_filter_location" ? "location" : "referer"; // Not the same nm as iteration nm ;-)
  865. if(nm === "referer" && (v === "none" || v === "<none>")) {
  866. this.value = "none";
  867. }
  868. else {
  869. if(v !== "") {
  870. this.value = v = Judy.stripTags(v);
  871. }
  872. if(v !== "" && v !== "*" && !/^https?:\/\/.+$/.test(v)) {
  873. if(!/^https?:\/\/.+$/.test(v = "http://" + v)) {
  874. self.Message.set( self.local(nm === "location" ? "invalid_location" : "invalid_referer"), "warning", {
  875. modal: true,
  876. close: function() {
  877. Judy.focus(_elements.conditions[ nm ]);
  878. }
  879. });
  880. this.value = v = "";
  881. }
  882. else {
  883. this.value = v;
  884. }
  885. }
  886. }
  887. if(v !== _.recordedValues[nm]) {
  888. _.recordedValues[nm] = v;
  889. _changedCriterion();
  890. }
  891. });
  892. break;
  893. default:
  894. oElms[nm] = elm;
  895. jq.change(_changedCriterion); // Criterion change handler.
  896. }
  897. }
  898. }
  899. // Order by.
  900. oElms = _elements.orderBy; // Array.
  901. if((nOrderBy = (aElms = $(_selectors.orderBy.options).get()).length)) {
  902. for(i = 0; i < nOrderBy; i++) {
  903. oElms.push(
  904. [ elm = aElms[i] ]
  905. );
  906. _.recordedValues.orderBy.push(Judy.fieldValue(elm));
  907. // There can't be two orderBys having same value.
  908. $(elm).change(function() {
  909. var v, index, i, a;
  910. if((v = Judy.fieldValue(this)) && v !== "_none") {
  911. index = parseInt(this.name.replace(/^log_filter_orderby_/, ""), 10) - 1;
  912. a = _elements.orderBy;
  913. for(i = 0; i < nOrderBy; i++) {
  914. if(i !== index && Judy.fieldValue(a[i][0]) === v) {
  915. Judy.fieldValue(this, null, v = "");
  916. break;
  917. }
  918. }
  919. }
  920. if(v !== _.recordedValues.orderBy[index]) {
  921. _.recordedValues.orderBy[index] = v;
  922. _changedCriterion();
  923. }
  924. });
  925. }
  926. if((le = (aElms = $(_selectors.orderBy.bools).get()).length)) {
  927. for(i = 0; i < le; i++) {
  928. oElms[i].push(
  929. elm = aElms[i]
  930. );
  931. $(elm).change(_changedCriterion);
  932. }
  933. }
  934. }
  935. // Miscellaneous.
  936. oSels = _selectors.pager;
  937. oElms = _elements.pager;
  938. for(nm in oSels) {
  939. if(oSels.hasOwnProperty(nm) && (elm = (jq = $(oSels[nm])).get(0))) {
  940. oElms[nm] = elm;
  941. switch(nm) {
  942. case "first":
  943. jq.click(function() {
  944. _ajaxRequestingBlocking = true; // Prevent consecutive clicks on update buttons.
  945. _getLogList(0, 0);
  946. });
  947. break;
  948. case "previous":
  949. jq.click(function() {
  950. _ajaxRequestingBlocking = true; // Prevent consecutive clicks on update buttons.
  951. _getLogList(0, (v = _.currentOffset - _.currentMax) > 0 ? v : 0);
  952. });
  953. break;
  954. case "current":
  955. jq.click(function() {
  956. _ajaxRequestingBlocking = true; // Prevent consecutive clicks on update buttons.
  957. _getLogList();
  958. });
  959. break;
  960. case "next":
  961. jq.click(function() {
  962. _ajaxRequestingBlocking = true; // Prevent consecutive clicks on update buttons.
  963. _getLogList(0, _.currentOffset + _.currentMax);
  964. });
  965. break;
  966. case "last":
  967. jq.click(function() {
  968. _ajaxRequestingBlocking = true; // Prevent consecutive clicks on update buttons.
  969. _getLogList(0, -1);
  970. });
  971. break;
  972. }
  973. }
  974. }
  975. // Miscellaneous.
  976. oSels = _selectors.misc;
  977. oElms = _elements.misc;
  978. for(nm in oSels) {
  979. if(oSels.hasOwnProperty(nm) && (elm = (jq = $(oSels[nm])).get(0))) {
  980. oElms[nm] = elm;
  981. }
  982. }
  983. // Buttons; get element references, and fix some issues.
  984. oSels = _selectors.buttons;
  985. oElms = _elements.buttons;
  986. for(nm in oSels) {
  987. if(oSels.hasOwnProperty(nm) && (elm = (jq = $(oSels[nm])).get(0))) {
  988. switch(nm) {
  989. case "submit":
  990. // Hidden, but we do submit by triggering a click on it anyway, in case Form API sets some javascript behaviour on it.
  991. // ...jQuery behaviour, really. Because a jQuery(elm).trigger("click") apparantly doesnt trigger a real click event(?).
  992. oElms[nm] = elm;
  993. break;
  994. case "update_list":
  995. oElms[nm] = elm;
  996. elm.setAttribute("type", "button");
  997. jq.unbind(); // Remove Drupal native button handlers.
  998. jq.click(function() {
  999. _ajaxRequestingBlocking = true; // Prevent consecutive clicks on update buttons.
  1000. _getLogList();
  1001. });
  1002. Judy.keydown(document.documentElement, "ctr+u cmd+u", function(event) {
  1003. event.preventDefault();
  1004. _ajaxRequestingBlocking = true; // Prevent consecutive clicks on update buttons.
  1005. _getLogList();
  1006. });
  1007. break;
  1008. default:
  1009. oElms[nm] = elm;
  1010. elm.setAttribute("type", "button"); // Fix type (apparant Form API shortcoming).
  1011. jq.unbind(); // Remove Drupal native button handlers.
  1012. switch(nm) {
  1013. case "create":
  1014. case "edit":
  1015. case "delete_filter":
  1016. case "cancel":
  1017. case "save":
  1018. _.crudFilters = true;
  1019. oElms.crudFilters.push(elm);
  1020. jq.click(_crudRelay); // Set our common button handler.
  1021. break;
  1022. case "delete_logs_button":
  1023. _.deleteLogs_allowed = true;
  1024. Judy.disable(elm, null, self.local("deleteLogs_prohibit"));
  1025. jq.click(_crudRelay); // Set our common button handler.
  1026. break;
  1027. case "reset":
  1028. jq.click(_resetCriteria);
  1029. break;
  1030. }
  1031. }
  1032. }
  1033. }
  1034. // Prevent click on hover title label span from resulting in checking/unchecking checkbox.
  1035. $("label span").click(function(evt) {
  1036. evt.stopPropagation();
  1037. return false;
  1038. });
  1039. }
  1040. catch(er) {
  1041. _errorHandler(er, 0, _name + "._prepareForm()");
  1042. }
  1043. };
  1044. self.inspector = function(u) {
  1045. inspect(u, {wrappers:1});
  1046. };
  1047. /**
  1048. * Sets current mode.
  1049. *
  1050. * Values:
  1051. * - default
  1052. * - adhoc
  1053. * - stored
  1054. * - create
  1055. * - edit
  1056. * - delete
  1057. *
  1058. * @ignore
  1059. * @param {string} mode
  1060. * @param {boolean} [submit]
  1061. * @param {boolean} [initially]
  1062. * @return {void}
  1063. */
  1064. _setMode = function(mode, submit, initially) {
  1065. var fromMode = _.mode, doSubmit, elm, nm;
  1066. try {
  1067. if(_submitted) {
  1068. return;
  1069. }
  1070. if(!initially && mode !== "delete_filter") {
  1071. if(!submit && _.crudFilters) {
  1072. // Hide all filter buttons.
  1073. $(_elements.buttons.crudFilters).hide();
  1074. }
  1075. }
  1076. switch(mode) {
  1077. case "default":
  1078. $("option[value='']", _elements.filter.filter).html( self.local("default") ); // Set visual value of filter selector's empty option.
  1079. $(_elements.misc.title).html(self.local("default"));
  1080. if(!initially) {
  1081. Judy.fieldValue(_elements.filter.filter, null, "");
  1082. _elements.filter.name.value = _.name = _elements.filter.origin.value = _.origin = "";
  1083. }
  1084. if(_.crudFilters) {
  1085. $(_elements.settings.onlyOwn.parentNode).show();
  1086. $(_elements.buttons.create).show();
  1087. if ((elm = _elements.filter.require_admin)) {
  1088. $(elm.parentNode).hide();
  1089. }
  1090. $(_elements.filter.name_suggest.parentNode).hide();
  1091. $(_elements.filter.description.parentNode).hide();
  1092. }
  1093. if(_.deleteLogs_allowed) {
  1094. $(_elements.settings.delete_logs_max).show();
  1095. $(elm = _elements.buttons.delete_logs_button).show();
  1096. $(elm.parentNode).show();
  1097. }
  1098. if(fromMode === "create") {
  1099. fromMode = ""; // Dont keep 'create' as _.modePrevious.
  1100. }
  1101. break;
  1102. case "adhoc":
  1103. if(!initially) {
  1104. Judy.fieldValue(_elements.filter.filter, null, "");
  1105. }
  1106. if(fromMode === "stored") {
  1107. // Pass current name to origin field.
  1108. _elements.filter.origin.value = _.origin = nm = _.name;
  1109. _elements.filter.name.value = _.name = "";
  1110. $("option[value='']", _elements.filter.filter).html("(" + nm + ")"); // Set visual value of filter selector's empty option.
  1111. $(_elements.misc.title).html( self.local("adhocForOrigin", {"!origin": nm} ) );
  1112. }
  1113. else {
  1114. fromMode = ""; // Dont keep 'create' as _.modePrevious.
  1115. $("option[value='']", _elements.filter.filter).html(self.local("adhoc")); // Set visual value of filter selector's empty option.
  1116. $(_elements.misc.title).html(self.local("adhoc"));
  1117. }
  1118. if(_.crudFilters) {
  1119. $(_elements.settings.onlyOwn.parentNode).show();
  1120. $(_elements.buttons.create).show();
  1121. if ((elm = _elements.filter.require_admin)) {
  1122. $(elm.parentNode).hide();
  1123. }
  1124. $(_elements.filter.name_suggest.parentNode).hide();
  1125. $(_elements.filter.description.parentNode).hide();
  1126. }
  1127. if(_.deleteLogs_allowed) {
  1128. $(_elements.settings.delete_logs_max).show();
  1129. $(elm = _elements.buttons.delete_logs_button).show();
  1130. $(elm.parentNode).show();
  1131. }
  1132. break;
  1133. case "stored": // stored mode may only appear on page load and after cancelling create.
  1134. if(!initially) {
  1135. if(fromMode === "create") {
  1136. _elements.filter.name.value = _.name = _.origin;
  1137. _elements.filter.origin.value = _.origin = "";
  1138. }
  1139. Judy.fieldValue(elm = _elements.filter.filter, null, nm = _.name);
  1140. $("option[value='']", elm).html( self.local("default") ); // Set visual value of filter selector's empty option.
  1141. $(_elements.misc.title).html( nm );
  1142. if(_.crudFilters) {
  1143. if ((elm = _elements.filter.require_admin)) {
  1144. $(elm.parentNode).hide();
  1145. }
  1146. $(_elements.filter.name_suggest.parentNode).hide();
  1147. $(_elements.filter.description.parentNode).hide();
  1148. }
  1149. }
  1150. if(_.crudFilters) {
  1151. $(_elements.settings.onlyOwn.parentNode).show();
  1152. $(_elements.buttons.create).show();
  1153. $(_elements.buttons.edit).show();
  1154. $(_elements.buttons.delete_filter).show();
  1155. }
  1156. if(_.deleteLogs_allowed) {
  1157. $(_elements.settings.delete_logs_max).show();
  1158. $(elm = _elements.buttons.delete_logs_button).show();
  1159. $(elm.parentNode).show();
  1160. }
  1161. switch(fromMode) {
  1162. case "create":
  1163. case "edit":
  1164. fromMode = "stored"; // Dont keep 'create' as _.modePrevious.
  1165. break;
  1166. }
  1167. break;
  1168. case "create":
  1169. if(!_.crudFilters) {
  1170. throw new Error("Mode[" + mode + "] not allowed.");
  1171. }
  1172. switch(fromMode) {
  1173. case "default":
  1174. case "adhoc":
  1175. $("option[value='']", _elements.filter.filter).html("(" + self.local("newName") + ")"); // Set visual value of filter selector's empty option.
  1176. $(_elements.misc.title).html( self.local("newTitle") );
  1177. break;
  1178. case "stored":
  1179. Judy.fieldValue(_elements.filter.filter, null, "");
  1180. // Pass current name to origin field.
  1181. _elements.filter.origin.value = _.origin = nm = _.name;
  1182. _elements.filter.name.value = _.name = "";
  1183. $("option[value='']", _elements.filter.filter).html("(" + nm + ")"); // Set visual value of filter selector's empty option.
  1184. $(_elements.misc.title).html( self.local("newForOrigin", {"!origin": nm} ) );
  1185. break;
  1186. default:
  1187. throw new Error("Cant create from mode[" + fromMode + "].");
  1188. }
  1189. $(_elements.settings.onlyOwn.parentNode).hide();
  1190. $(_elements.filter.name_suggest.parentNode).show();
  1191. if ((elm = _elements.filter.require_admin)) {
  1192. $(elm.parentNode).show();
  1193. }
  1194. $(_elements.filter.description.parentNode).show();
  1195. $(_elements.buttons.save).show();
  1196. $(_elements.buttons.cancel).show();
  1197. if(_.deleteLogs_allowed) {
  1198. $(_elements.buttons.delete_logs_button.parentNode).hide();
  1199. }
  1200. break;
  1201. case "edit":
  1202. if(!_.crudFilters) {
  1203. throw new Error("Mode[" + mode + "] not allowed.");
  1204. }
  1205. if(fromMode === "create") {
  1206. // If going from create to edit: memorize mode right before create, to prevent ending up having (useless) create as previous mode.
  1207. fromMode = _.modePrevious;
  1208. $("option[value='']", elm = _elements.filter.filter).after(
  1209. "<option value=\"" + (nm = _.name) + "\">" + nm + "</option>"
  1210. );
  1211. $("option[value='']", elm).html( self.local("default") );
  1212. Judy.fieldValue(elm, null, nm);
  1213. }
  1214. if ((elm = _elements.filter.require_admin)) {
  1215. $(elm.parentNode).show();
  1216. }
  1217. $(_elements.filter.name_suggest.parentNode).hide();
  1218. $(_elements.filter.description.parentNode).show();
  1219. $(_elements.buttons.cancel).show();
  1220. $(_elements.buttons.save).show();
  1221. $(_elements.settings.onlyOwn.parentNode).hide();
  1222. if(_.deleteLogs_allowed) {
  1223. $(_elements.buttons.delete_logs_button.parentNode).hide();
  1224. }
  1225. break;
  1226. case "delete_filter": // Pop confirm(), and submit upon positive confirmation.
  1227. if(!_.crudFilters) {
  1228. throw new Error("Mode[" + mode + "] not allowed.");
  1229. }
  1230. Judy.overlay(1, true); // Opaque.
  1231. if (_elements.filter.name.value) {
  1232. if(!confirm( self.local(
  1233. "confirmDelete",
  1234. {"!filter": _elements.filter.name.value}
  1235. ))) {
  1236. Judy.overlay(0);
  1237. return;
  1238. }
  1239. doSubmit = true;
  1240. Judy.overlay(1, false, self.local("wait")); // Transparent.
  1241. }
  1242. else {
  1243. throw new Error("Cant delete filter having empty name[" + _elements.filter.name.value + "].");
  1244. }
  1245. break;
  1246. default:
  1247. throw new Error("Mode[" + mode + "] not supported.");
  1248. }
  1249. _.modePrevious = fromMode;
  1250. _elements.settings.mode.value = _.mode = mode;
  1251. if(submit || doSubmit) {
  1252. _submit();
  1253. }
  1254. }
  1255. catch(er) {
  1256. _errorHandler(er, 0, _name + "._setMode()");
  1257. }
  1258. };
  1259. /**
  1260. * Common handler for all CRUD buttons.
  1261. *
  1262. * @ignore
  1263. * @return {boolean}
  1264. */
  1265. _crudRelay = function() {
  1266. var nm = this.name, // The element's name, not _.name.
  1267. elm, v, rqa;
  1268. try {
  1269. switch(nm) {
  1270. case "log_filter_reset":
  1271. _resetCriteria();
  1272. break;
  1273. case "log_filter_create":
  1274. _setMode("create");
  1275. Judy.focus(_elements.filter.name_suggest);
  1276. break;
  1277. case "log_filter_edit":
  1278. _setMode("edit");
  1279. break;
  1280. case "log_filter_delete":
  1281. _setMode("delete_filter");
  1282. break;
  1283. case "log_filter_cancel":
  1284. switch(_.mode) {
  1285. case "create":
  1286. case "edit":
  1287. switch(_.modePrevious) {
  1288. case "default":
  1289. case "adhoc":
  1290. break;
  1291. case "stored":
  1292. break;
  1293. default:
  1294. throw new Error("Previous mode[" + _.modePrevious + "] not supported when cancelling.");
  1295. }
  1296. _setMode(_.modePrevious);
  1297. break;
  1298. default:
  1299. throw new Error("Cant cancel in mode[" + _.mode + "].");
  1300. }
  1301. break;
  1302. case "log_filter_save":
  1303. if(_.mode === "edit" && !_.saveEditFilterAjaxed) {
  1304. Judy.overlay(1, false, self.local("wait_" + _.mode));
  1305. _submit();
  1306. return false;
  1307. }
  1308. else {
  1309. // Prevent double-click.
  1310. if(_ajaxRequestingBlocking) {
  1311. return false; // false for IE<9's sake.
  1312. }
  1313. if(_.mode === "create") {
  1314. // No reason to trim(), because change handler (_machineNameChange()) replaces spaces with underscores.
  1315. if(!_machineNameValidate(null, null, v = (elm = _elements.filter.name_suggest).value)) {
  1316. Judy.focus(elm);
  1317. return false; // false for IE<9's sake.
  1318. }
  1319. if($.inArray(v, _filters) > -1) {
  1320. Judy.overlay(1, true);
  1321. if (!confirm(self.local("error_filter_name_nonunique", {"!name": v}))) {
  1322. Judy.overlay(0);
  1323. return false;
  1324. }
  1325. else {
  1326. Judy.overlay(1, false, self.local("wait_edit"));
  1327. _elements.settings.mode.value = _.mode = "edit";
  1328. _elements.filter.name.value = v;
  1329. _submit();
  1330. return false;
  1331. }
  1332. }
  1333. nm = v;
  1334. rqa = _elements.filter.require_admin ? 1 : 0; // Create with require_admin if the element exists (the user has the permission).
  1335. }
  1336. else {
  1337. nm = _.name;
  1338. rqa = (elm = _elements.filter.require_admin) && Judy.fieldValue(elm);
  1339. }
  1340. Judy.overlay(1, false, self.local("wait_" + _.mode));
  1341. _ajaxRequestingBlocking = true;
  1342. v = self.getCriteria();
  1343. _ajaxRequest("filter_" + _.mode, { // filter_create|filter_edit
  1344. name: nm,
  1345. filter: {
  1346. require_admin: rqa,
  1347. description: $.trim(Judy.stripTags(_elements.filter.description.value).replace(/[\r\n\t]/g, " ").replace(/\ +/g, " ")).substr(0, 255)
  1348. },
  1349. conditions: v.conditions,
  1350. order_by: v.order_by
  1351. });
  1352. }
  1353. break;
  1354. case "log_filter_delete_logs_button":
  1355. if(_.deleteLogs_allowed) {
  1356. Judy.overlay(1, false, self.local("wait"));
  1357. setTimeout(_deleteLogs, 200);
  1358. }
  1359. else {
  1360. throw new Error("Button name[" + nm + "] not allowed.");
  1361. }
  1362. break;
  1363. default:
  1364. throw new Error("Unsupported button name[" + nm + "].");
  1365. }
  1366. }
  1367. catch(er) {
  1368. _errorHandler(er, 0, _name + "._crudRelay()");
  1369. }
  1370. return false; // false for IE<9's sake.
  1371. };
  1372. /**
  1373. * Change handler for all condition and orderBy fields.
  1374. *
  1375. * @ignore
  1376. * @return {void}
  1377. */
  1378. _changedCriterion = function() {
  1379. if(_.deleteLogs_allowed) {
  1380. Judy.disable(_elements.buttons.delete_logs_button, null, self.local("deleteLogs_prohibit"));
  1381. }
  1382. try {
  1383. switch(_.mode) {
  1384. case "default":
  1385. _setMode("adhoc");
  1386. break;
  1387. case "adhoc":
  1388. break;
  1389. case "stored":
  1390. // A change of a stored filter triggers edit mode if the user is allowed to edit filters.
  1391. _setMode(!_.crudFilters ? "adhoc" : "edit");
  1392. break;
  1393. case "create":
  1394. break;
  1395. case "edit":
  1396. break;
  1397. case "delete_filter":
  1398. break;
  1399. default:
  1400. throw new Error("Mode[" + _.mode + "] not supported.");
  1401. }
  1402. }
  1403. catch(er) {
  1404. _errorHandler(er, 0, _name + "._changedCriterion()");
  1405. }
  1406. };
  1407. /**
  1408. * Clear all condition and orderby fields, and set defaults.
  1409. *
  1410. * @ignore
  1411. * @param {Event} [evt]
  1412. * - when used as event handler
  1413. * @param {string|falsy} [mode]
  1414. * - set mode to that
  1415. * @param {boolean} [noModeChange]
  1416. * - do not change mode
  1417. * @return {void}
  1418. */
  1419. _resetCriteria = function(evt, mode, noModeChange) {
  1420. var o = _elements.conditions, nm, r, a, le, i;
  1421. if(_.deleteLogs_allowed) {
  1422. Judy.disable(_elements.buttons.delete_logs_button, null, self.local("deleteLogs_prohibit"));
  1423. }
  1424. for(nm in o) {
  1425. if(o.hasOwnProperty(nm)) {
  1426. r = o[nm];
  1427. // Default to severity any and type any.
  1428. switch(nm) {
  1429. case "severity_any":
  1430. case "type_any":
  1431. r.checked = true;
  1432. break;
  1433. case "severity_some": // Array.
  1434. le = r.length;
  1435. for(i = 0; i < le; i++) {
  1436. r[i].checked = false;
  1437. }
  1438. break;
  1439. case "type_proxy":
  1440. if(r) { // Doesnt exists if no logs at all.
  1441. Judy.fieldValue(r, null, "", "checkboxes");
  1442. }
  1443. break;
  1444. default:
  1445. r.value = "";
  1446. }
  1447. }
  1448. }
  1449. le = (a = _elements.orderBy).length;
  1450. // Default to order by time ascending, only.
  1451. for(i = 0; i < le; i++) {
  1452. Judy.fieldValue(a[i][0], null, i ? "" : "time");
  1453. a[i][1].checked = i ? false : "checked";
  1454. }
  1455. if(!noModeChange) {
  1456. // Degrade mode.
  1457. if(mode) {
  1458. _setMode(mode);
  1459. }
  1460. else {
  1461. _setMode("default");
  1462. }
  1463. }
  1464. };
  1465. /**
  1466. * @ignore
  1467. * @return {void}
  1468. */
  1469. _deleteLogs = function() {
  1470. var o = self.getCriteria(), v, offset = _.currentOffset, max = (v = _elements.settings.delete_logs_max.value) !== "" ? parseInt(v) : 0;
  1471. if(!o.nConditions) { // Even stored filters go here; if a stored filter has no conditions, than THAT is the important thing.
  1472. // We warn every time, when no conditions at all.
  1473. if(!max) {
  1474. if (!offset) {
  1475. if(!confirm( self.local("deleteLogs_all") )) {
  1476. Judy.overlay(0);
  1477. Judy.focus(_elements.settings.delete_logs_max);
  1478. return;
  1479. }
  1480. }
  1481. else if(!confirm( self.local("deleteLogs_noMax", {"!offset": offset}) )) {
  1482. Judy.overlay(0);
  1483. Judy.focus(_elements.settings.delete_logs_max);
  1484. return;
  1485. }
  1486. }
  1487. else if (!offset) {
  1488. if(!confirm( self.local("deleteLogs_noOffset", {"!max": max}) )) {
  1489. Judy.overlay(0);
  1490. Judy.focus(_elements.settings.delete_logs_max);
  1491. return;
  1492. }
  1493. }
  1494. else if(!confirm( self.local("deleteLogs_noConditions", {"!offset": offset, "!max": max}) )) {
  1495. Judy.overlay(0);
  1496. Judy.focus(_elements.settings.delete_logs_max);
  1497. return;
  1498. }
  1499. }
  1500. else if(_.mode === "stored") {
  1501. if(!max) {
  1502. if (!offset) {
  1503. if(!confirm( self.local("deleteLogs_storedAll", {"!name": _.name}) )) {
  1504. Judy.overlay(0);
  1505. Judy.focus(_elements.settings.delete_logs_max);
  1506. return;
  1507. }
  1508. }
  1509. else if(!confirm( self.local("deleteLogs_storedNoMax", {"!offset": offset, "!name": _.name}) )) {
  1510. Judy.overlay(0);
  1511. Judy.focus(_elements.settings.delete_logs_max);
  1512. return;
  1513. }
  1514. }
  1515. else if (!offset) {
  1516. if(!confirm( self.local("deleteLogs_storedNoOffset", {"!max": max, "!name": _.name}) )) {
  1517. Judy.overlay(0);
  1518. Judy.focus(_elements.settings.delete_logs_max);
  1519. return;
  1520. }
  1521. }
  1522. else if(!confirm( self.local("deleteLogs_stored", {"!offset": offset, "!max": max, "!name": _.name}) )) {
  1523. Judy.overlay(0);
  1524. Judy.focus(_elements.settings.delete_logs_max);
  1525. return;
  1526. }
  1527. }
  1528. else if(!max) {
  1529. if (!offset) {
  1530. if(!confirm( self.local("deleteLogs_adhocAll") )) {
  1531. Judy.overlay(0);
  1532. Judy.focus(_elements.settings.delete_logs_max);
  1533. return;
  1534. }
  1535. }
  1536. else if(!confirm( self.local("deleteLogs_adhocNoMax", {"!offset": offset}) )) {
  1537. Judy.overlay(0);
  1538. Judy.focus(_elements.settings.delete_logs_max);
  1539. return;
  1540. }
  1541. }
  1542. else if (!offset) {
  1543. if(!confirm( self.local("deleteLogs_adhocNoOffset", {"!max": max}) )) {
  1544. Judy.overlay(0);
  1545. Judy.focus(_elements.settings.delete_logs_max);
  1546. return;
  1547. }
  1548. }
  1549. else if(!confirm( self.local("deleteLogs_adhoc", {"!offset": offset, "!max": max}) )) {
  1550. Judy.overlay(0);
  1551. Judy.focus(_elements.settings.delete_logs_max);
  1552. return;
  1553. }
  1554. _ajaxRequestingBlocking = true;
  1555. v = self.getCriteria();
  1556. _ajaxRequest("delete_logs", {
  1557. conditions: v.conditions,
  1558. order_by: v.order_by,
  1559. offset: offset,
  1560. max: max
  1561. });
  1562. };
  1563. /**
  1564. * @ignore
  1565. * @param {Event} evt
  1566. * @return {void}
  1567. */
  1568. _filterByEventColumn = function(evt) {
  1569. var that = evt.target, tag, logId, col, log, u, o = _elements.conditions, elm, elm1, v, v1, a, vShow, username;
  1570. if (evt.type === 'contextmenu') {
  1571. evt.preventDefault();
  1572. }
  1573. // Get out if not td or link within td.
  1574. switch ((tag = that.tagName || 'none').toLowerCase()) {
  1575. case 'td':
  1576. break;
  1577. case 'a': // User column may contain link.
  1578. username = $(that).text();
  1579. that = that.parentNode;
  1580. break;
  1581. default:
  1582. return;
  1583. }
  1584. // The td must have column attribute.
  1585. if (!(col = that.getAttribute('log_filter_list_event_column'))) {
  1586. return;
  1587. }
  1588. // Parent tr must have a log id attribute, and the log must exist.
  1589. if (!(logId = that.parentNode.getAttribute('log_filter_list_event_id')) ||
  1590. !(log = _logs['_' + logId]) || !_logs.hasOwnProperty('_' + logId)
  1591. ) {
  1592. return;
  1593. }
  1594. switch (col) {
  1595. case 'severity':
  1596. vShow = self.local(_severity[ log.severity ]);
  1597. v = log.severity || 'zero';
  1598. if ((a = Judy.fieldValue(elm = o.severity_some, _elements.form, undefined, 'checklist'))) {
  1599. a.push(v);
  1600. v = a;
  1601. }
  1602. Judy.fieldValue(elm, _elements.form, v, 'checklist');
  1603. $(elm).trigger('change');
  1604. break;
  1605. case 'type':
  1606. // If no such option exists yet: add it.
  1607. if (Judy.arrayIndexOf(_.recordedValues.type_options, v = log.type) === -1) {
  1608. $('input[name="log_filter_type_proxy_add_item_value"]', _elements.form).val(v);
  1609. $('input[name="log_filter_type_proxy_add_item"]', _elements.form).get(0).checked = 'checked';
  1610. $('input[name="log_filter_type_proxy_add_item"]', _elements.form).trigger('change');
  1611. }
  1612. else {
  1613. if ((a = Judy.fieldValue(elm = o.type_proxy, _elements.form, undefined, 'checklist'))) {
  1614. a.push(v);
  1615. v = a;
  1616. }
  1617. Judy.fieldValue(elm, _elements.form, v, 'checklist');
  1618. $('div#edit-log-filter-type-proxy input[value="' + v + '"]').trigger('change');
  1619. }
  1620. vShow = v;
  1621. break;
  1622. case 'time': // Time: right-click/f means Time From, shift+f means Time To.
  1623. u = evt.type === 'keydown' && evt.keystrokes !== 'f' ? 'time_to' : 'time_from';
  1624. (elm = o[u + '_proxy']).value = v = log.time.substr(0, 10);
  1625. $(elm).trigger('change');
  1626. (elm1 = o[u + '_time']).value = v1 = log.time.substr(11);
  1627. $(elm1).trigger('change');
  1628. if (elm.value !== v || elm1.value !== v1) {
  1629. return; // Dont set message.
  1630. }
  1631. col = u; // For Message.
  1632. vShow = log.time;
  1633. break;
  1634. default:
  1635. (elm = o[col]).value = vShow = v = log[col];
  1636. $(elm).trigger('change');
  1637. if (col === 'uid' && username) {
  1638. _elements.conditions.username.value = username;
  1639. }
  1640. }
  1641. self.Message.set( self.local("filtered_event_column", { '!column': self.local('log_' + col), '!value': vShow }), "info");
  1642. };
  1643. /**
  1644. * @ignore
  1645. * @param {integer} [wid]
  1646. * - for single log view
  1647. * @param {integer|undefined} [offset]
  1648. * - default: current offset
  1649. * - minus one means last
  1650. * @return {void}
  1651. */
  1652. _getLogList = function(wid, offset) {
  1653. var v = self.getCriteria();
  1654. Judy.overlay(1, false, self.local("wait"));
  1655. if(wid) {
  1656. v.conditions = {
  1657. wid: wid
  1658. };
  1659. offset = 0;
  1660. }
  1661. _ajaxRequest("list_logs", {
  1662. conditions: v.conditions,
  1663. order_by: v.order_by,
  1664. offset: offset || offset === 0 ? offset : _.currentOffset,
  1665. max: _.currentMax,
  1666. translate: Judy.fieldValue(_elements.settings.translate)
  1667. });
  1668. $(_elements.pager.first).addClass("log-filter-pager-button-disabled");
  1669. $(_elements.pager.previous).addClass("log-filter-pager-button-disabled");
  1670. $(_elements.pager.current).hide();
  1671. $(_elements.pager.progress).show();
  1672. $(_elements.pager.next).addClass("log-filter-pager-button-disabled");
  1673. $(_elements.pager.last).addClass("log-filter-pager-button-disabled");
  1674. };
  1675. /**
  1676. * @ignore
  1677. * @param {array} logs
  1678. * @param {object} conditions
  1679. * - list of conditions used, values are always true (except for the 'wid' condition)
  1680. * @param {integer} offset
  1681. * @param {integer} nTotal
  1682. * @return {void}
  1683. */
  1684. _listLogs = function(logs, conditions, offset, nTotal) {
  1685. var le = logs.length, i, o, v, css = 'log-filter-list', s, nCols = 5, wid, optionalColumns = {}, tabindex = 999;
  1686. _logs = {};
  1687. _.currentOffset = offset || 0;
  1688. if(le) {
  1689. for(i = 0; i < le; i++) {
  1690. o = logs[i];
  1691. // Replace variables if exist and not done already by backend (is done if translate is on).
  1692. if(o.variables) {
  1693. o.message = Drupal.formatString(o.message, o.variables);
  1694. }
  1695. delete o.variables;
  1696. // Resolve severity.
  1697. o.severity = parseInt('' + o.severity, 10);
  1698. o.severity_string = _severity[o.severity];
  1699. // Set other properties.
  1700. o.time = Judy.dateTime(new Date(o.timestamp * 1000));
  1701. if (!o.uid || o.uid === "0") {
  1702. o.uid = 0;
  1703. o.name = self.local("anonymous_user");
  1704. }
  1705. _logs[ "_" + o.wid ] = o;
  1706. }
  1707. }
  1708. // Render.
  1709. s = '<table id="log_filter_log_list_table" class="sticky-enabled" tabindex="' + (++tabindex) + '"><thead><tr>' +
  1710. '<th>' + Drupal.t('Severity') + '</th>' +
  1711. '<th>' + Drupal.t('Type') + '</th>' +
  1712. '<th>' + Drupal.t('Time') + '</th>' +
  1713. '<th>' + Drupal.t('User') + '</th>';
  1714. if(conditions.hostname || _elements.conditions.hostname.value === '*') {
  1715. ++nCols;
  1716. optionalColumns.hostname = true;
  1717. s += '<th>' + Drupal.t('Hostname') + '</th>';
  1718. }
  1719. if(conditions.location || _elements.conditions.location.value === '*') {
  1720. ++nCols;
  1721. optionalColumns.location = true;
  1722. s += '<th>' + Drupal.t('Location') + '</th>';
  1723. }
  1724. if(conditions.referer || _elements.conditions.referer.value === '*') {
  1725. ++nCols;
  1726. optionalColumns.referer = true;
  1727. s += '<th>' + Drupal.t('Referrer') + '</th>';
  1728. }
  1729. s += '<th>' + Drupal.t('Message') + '</th>' +
  1730. '</tr></thead><tbody>';
  1731. if(le) {
  1732. // Listing only a single log (from url)?
  1733. if ((wid = conditions.wid) && conditions.hasOwnProperty('wid')) {
  1734. s += '<tr class="even">' +
  1735. '<td class="' + css + '-event-from-url" colspan="' + nCols + '">' +
  1736. self.local('event_from_url', { '!number': wid }) +
  1737. '</td>' +
  1738. '</tr>';
  1739. setTimeout(function() {
  1740. self.displayLog(wid);
  1741. }, 100);
  1742. }
  1743. for(i = 0; i < le; i++) {
  1744. o = logs[i];
  1745. s += '<tr id="log_filter_list_log_' + o.wid + '" log_filter_list_event_id="' + o.wid + '" onclick="LogFilter.displayLog(' + o.wid +
  1746. ');" class="' + (i % 2 ? 'even' : 'odd') + '" title="' + self.local("eventItem_display", { '!logId': o.wid }) + '">' +
  1747. '<td log_filter_list_event_column="severity" class="' + css + '-severity ' + css + '-' + (v = o.severity_string) + '" title="' +
  1748. self.local('eventItemHover_severity', { '!logId': o.wid, '!severity': self.local(v) }) + '" tabindex="' + (++tabindex) +
  1749. '" onmouseover="focus(this);">&#160;</td>' +
  1750. '<td log_filter_list_event_column="type" class="' + css + '-type" title="' +
  1751. self.local('eventItemHover_filter', { '!logId': o.wid, '!filter': self.local('log_type') }) +
  1752. '" tabindex="' + (++tabindex) + '" onmouseover="focus(this);">' + o.type + '</td>' +
  1753. '<td log_filter_list_event_column="time" class="' + css + '-time" title="' + self.local('eventItemHover_time', { '!logId': o.wid }) +
  1754. '" tabindex="' + (++tabindex) + '" onmouseover="focus(this);">' + o.time + '</td>' +
  1755. '<td log_filter_list_event_column="uid" class="' + css + '-user" title="' +
  1756. self.local('eventItemHover_user', { '!logId': o.wid, '!uid': o.uid }) + '"' +
  1757. (!o.uid || o.name === null ? (!o.uid ? (' onmouseover="focus(this);">' + (o.name)) : ('>-' + self.local("deleted_user") + '-')) :
  1758. ('><a href="/user/' + o.uid + '" onmouseover="focus(this);">' + o.name + '</a>')) +
  1759. '</td>' +
  1760. (!optionalColumns.hostname ? '' :
  1761. '<td log_filter_list_event_column="hostname" class="' + css + '-hostname" title="' +
  1762. self.local('eventItemHover_filter', { '!logId': o.wid, '!filter': self.local('log_hostname') }) +
  1763. '" tabindex="' + (++tabindex) + '" onmouseover="focus(this);">' + o.hostname + '</td>') +
  1764. (!optionalColumns.location ? '' :
  1765. '<td log_filter_list_event_column="location" class="' + css + '-location" title="' +
  1766. self.local('eventItemHover_filter', { '!logId': o.wid, '!filter': self.local('log_location') }) +
  1767. '" tabindex="' + (++tabindex) + '" onmouseover="focus(this);">' + o.location + '</td>') +
  1768. (!optionalColumns.referer ? '' :
  1769. '<td log_filter_list_event_column="referer" class="' + css + '-referer" title="' +
  1770. self.local('eventItemHover_filter', { '!logId': o.wid, '!filter': self.local('log_referer') }) +
  1771. '" tabindex="' + (++tabindex) + '" onmouseover="focus(this);">' + o.referer + '</td>') +
  1772. '<td class="' + css + '-message"><div>' +
  1773. Judy.stripTags(o.message.replace(/\r?\n/g, " ")).substr(0, _.listMessageTruncate) + '</div></td>' +
  1774. '</tr>';
  1775. }
  1776. // Pager.
  1777. $(_elements.pager.progress).hide();
  1778. if (offset) {
  1779. $(_elements.pager.first).removeClass("log-filter-pager-button-disabled");
  1780. $(_elements.pager.previous).removeClass("log-filter-pager-button-disabled");
  1781. }
  1782. $(_elements.pager.current).html(self.local('pager_current', { '!first': (offset + 1), '!last': (offset + le), '!total': nTotal })).show();
  1783. if (offset + le < nTotal) {
  1784. $(_elements.pager.next).removeClass("log-filter-pager-button-disabled");
  1785. $(_elements.pager.last).removeClass("log-filter-pager-button-disabled");
  1786. }
  1787. }
  1788. else {
  1789. s += '<tr class="odd">' +
  1790. '<td class="' + css + '-no-match" colspan="' + nCols + '">' +
  1791. (!conditions.wid ? self.local('no_event_matches') : self.local('non_existing_event', { '!number': conditions.wid })) +
  1792. '</td>' +
  1793. '</tr>';
  1794. // Pager.
  1795. $(_elements.pager.progress).hide();
  1796. if (offset) {
  1797. $(_elements.pager.first).removeClass("log-filter-pager-button-disabled");
  1798. $(_elements.pager.previous).removeClass("log-filter-pager-button-disabled");
  1799. }
  1800. if (!nTotal) {
  1801. $(_elements.pager.current).html(self.local('pager_current_none')).show();
  1802. }
  1803. else {
  1804. $(_elements.pager.current).html(self.local('pager_current_outofrange', { '!offset': offset, '!total': nTotal })).show();
  1805. }
  1806. }
  1807. s += "</tbody></table>";
  1808. // Display the table, after updating pager (displaying the table may take some time).
  1809. $("#log_filter_log_list").html(s);
  1810. setTimeout(function() {
  1811. // Apply Drupal tableheader.
  1812. $('#log_filter_log_list table.sticky-enabled').once('tableheader', function () {
  1813. $(this).data("drupal-tableheader", new Drupal.tableHeader(this));
  1814. });
  1815. // Add filter by event column value handlers.
  1816. $('table#log_filter_log_list_table').bind('contextmenu', _filterByEventColumn);
  1817. Judy.keydown('table#log_filter_log_list_table', 'f shift+f', _filterByEventColumn, true); // preventDefault
  1818. }, 100);
  1819. };
  1820. /**
  1821. * @ignore
  1822. * @param {string} action
  1823. * @param {object} oData
  1824. * @return {void}
  1825. */
  1826. _ajaxRequest = function(action, oData) {
  1827. $.ajax({
  1828. url: "/log_filter/ajax/" + action,
  1829. type: "POST",
  1830. data: oData,
  1831. dataType: "json", // expects json formatted response data
  1832. cache: false,
  1833. /**
  1834. * @return {void}
  1835. * @param {object} oResp
  1836. * - (string) action
  1837. * - (boolean) success
  1838. * - (string) error
  1839. * - (integer) error_code
  1840. * @param {string} textStatus
  1841. * @param {object} jqXHR
  1842. */
  1843. success: function(oResp, textStatus, jqXHR) {
  1844. var o;
  1845. if(textStatus === "success" && typeof action === "string" && $.type(oResp) === "object") {
  1846. _ajaxResponse(action, oResp);
  1847. }
  1848. else {
  1849. o = {
  1850. source: "ajax request",
  1851. action: action,
  1852. textStatus: textStatus,
  1853. oResp: oResp
  1854. };
  1855. _.errors.push(o);
  1856. _errorHandler(null, o, _name + "._ajaxRequest()");
  1857. }
  1858. },
  1859. error: function(jqXHR, textStatus, errorThrown) {
  1860. var o;
  1861. if(jqXHR && jqXHR.status === 403) {
  1862. _ajaxResponse(action, { success: false, error_code: _errorCodes.perm_general });
  1863. }
  1864. else {
  1865. o = {
  1866. source: "ajax request",
  1867. action: action,
  1868. textStatus: textStatus,
  1869. errorThrown: errorThrown
  1870. };
  1871. _.errors.push(o);
  1872. _errorHandler(null, o, _name + "._ajaxRequest()");
  1873. }
  1874. }
  1875. });
  1876. };
  1877. /**
  1878. * @ignore
  1879. * @param {string} action
  1880. * @param {object} oResp
  1881. * @return {void}
  1882. */
  1883. _ajaxResponse = function(action, oResp) {
  1884. var errorCode = oResp.error_code || 0, url;
  1885. // Handle general errors.
  1886. if (!oResp.success || errorCode) {
  1887. switch(errorCode) {
  1888. // General errors.
  1889. case _errorCodes.perm_general: // Probably session timeout.
  1890. // Reload page, to get 403. And remove form.
  1891. $(_elements.form).html("");
  1892. self.Message.set( self.local("error_form_expired", { "!url": url = _url() }), "warning", { // In case Javascript redirect fails.
  1893. modal: true,
  1894. close: function() {
  1895. window.location.href = url;
  1896. }
  1897. });
  1898. return;
  1899. case _errorCodes.form_expired:
  1900. self.Message.set( self.local("error_form_expired", { "!url": url = _url() }), "warning", {
  1901. modal: true,
  1902. close: function() {
  1903. window.location.href = url;
  1904. }
  1905. });
  1906. return;
  1907. // Errors by more than one request type.
  1908. case _errorCodes.perm_filter_crud:
  1909. self.Message.set( self.local("error_perm_filter_crud"), "warning", {
  1910. modal: true,
  1911. close: function() {
  1912. window.location.href = _url(); // Reload to make GUI reflect permissions; omitting create/edit/save/delete controls.
  1913. }
  1914. });
  1915. return;
  1916. case _errorCodes.db_general: // Database error.
  1917. self.Message.set( self.local("error_db_general"), "error", {
  1918. modal: true,
  1919. close: function() {
  1920. window.location.href = _url();
  1921. }
  1922. });
  1923. break;
  1924. // default: Let action function handle the error, and optionally return false if it doesnt know that error code.
  1925. }
  1926. }
  1927. if(_ajaxResponse.hasOwnProperty(action)) { // IE<9 wont like that, has no function.hasOwnProperty() method ;-)
  1928. if(!_ajaxResponse[action](oResp)) {
  1929. _errorHandler(null, oResp, _name + "._ajaxResponse." + action + "()");
  1930. self.Message.set( self.local("error_unknown"), "error", {
  1931. modal: true,
  1932. close: function() {
  1933. window.location.href = _url();
  1934. }
  1935. });
  1936. }
  1937. }
  1938. else {
  1939. _errorHandler(null, oResp, _name + "._ajaxResponse(), unsupported action[" + action + "]");
  1940. }
  1941. };
  1942. /**
  1943. * @ignore
  1944. * @param {object} oResp
  1945. * @return {boolean}
  1946. */
  1947. _ajaxResponse.filter_create = function(oResp) { // Only saves a default filter with a name; progress to edit mode on success.
  1948. var nm = oResp.name;
  1949. if(oResp.success) {
  1950. _elements.filter.name_suggest.value = "";
  1951. _elements.filter.origin.value = _.origin = _.name;
  1952. _elements.filter.name.value = _.name = nm;
  1953. _filters.push(nm);
  1954. _setMode("edit");
  1955. $(_elements.misc.title).html(nm + "<span> - " + oResp.description + "</span>");
  1956. Judy.overlay(0);
  1957. self.Message.set(self.local("savedNew", {"!filter": nm}));
  1958. }
  1959. else {
  1960. switch(oResp.error_code) {
  1961. case _errorCodes.filter_name_composition: // Invalid machine name.
  1962. Judy.overlay(0);
  1963. self.Message.set( self.local("error_machine_name_composition"), "warning", {
  1964. modal: true,
  1965. close: function() {
  1966. Judy.focus(_elements.filter.name_suggest);
  1967. }
  1968. });
  1969. break;
  1970. case _errorCodes.filter_name_nonunique: // Filter name already exists.
  1971. Judy.overlay(0);
  1972. self.Message.set( self.local("error_filter_name_nonunique", {"!name": nm}), "warning", {
  1973. modal: true,
  1974. close: function() {
  1975. Judy.focus(_elements.filter.name_suggest);
  1976. }
  1977. });
  1978. break;
  1979. default: // Unknown error code.
  1980. return false;
  1981. }
  1982. }
  1983. _ajaxRequestingBlocking = false;
  1984. return true;
  1985. };
  1986. /**
  1987. * @ignore
  1988. * @param {object} oResp
  1989. * @return {boolean}
  1990. */
  1991. _ajaxResponse.filter_edit = function(oResp) {
  1992. var nm = oResp.name;
  1993. if(oResp.success) {
  1994. $("span", _elements.misc.title).html(" - " + oResp.description);
  1995. Judy.overlay(0);
  1996. self.Message.set(self.local("saved", {"!filter": nm}));
  1997. }
  1998. else if(oResp.error_code === _errorCodes.filter_doesnt_exist) {
  1999. self.Message.set( self.local("error_filter_doesnt_exist", {"!name": nm}), "warning", {
  2000. modal: true,
  2001. close: function() {
  2002. window.location.href = _url(); // Reload to make GUI reflect missing filter.
  2003. }
  2004. });
  2005. }
  2006. else if(oResp.error_code === _errorCodes.perm_filter_restricted) {
  2007. self.Message.set( self.local("error_perm_filter_restricted"), "error", {
  2008. modal: true,
  2009. close: function() {
  2010. window.location.href = _url(); // Reload to make get out of that situation.
  2011. }
  2012. });
  2013. }
  2014. else {
  2015. return false;
  2016. }
  2017. _ajaxRequestingBlocking = false;
  2018. return true;
  2019. };
  2020. /**
  2021. * @ignore
  2022. * @param {object} oResp
  2023. * @return {boolean}
  2024. */
  2025. _ajaxResponse.list_logs = function(oResp) {
  2026. var nm = oResp.name, conditions = oResp.log_list[1];
  2027. if(oResp.success) {
  2028. _listLogs(oResp.log_list[0], oResp.log_list[1], oResp.log_list[2], oResp.log_list[3]);
  2029. // Deleting logs is allowed when evenever the log list reflects the filter.
  2030. if(_.deleteLogs_allowed &&
  2031. // If wid condition, we list a single log (from url) and thus the list doesnt reflect current filter.
  2032. (!conditions.wid || !conditions.hasOwnProperty('wid'))
  2033. ) {
  2034. Judy.enable(_elements.buttons.delete_logs_button, null, "");
  2035. }
  2036. Judy.overlay(0);
  2037. }
  2038. else {
  2039. return false;
  2040. }
  2041. _ajaxRequestingBlocking = false;
  2042. return true;
  2043. };
  2044. /**
  2045. * @ignore
  2046. * @param {object} oResp
  2047. * @return {boolean}
  2048. */
  2049. _ajaxResponse.delete_logs = function(oResp) {
  2050. if(oResp.success) {
  2051. self.Message.set(self.local("deleteLogs_success", { "!number": oResp.delete_logs }), "notice", { noFade: false });
  2052. _getLogList();
  2053. return true;
  2054. }
  2055. else {
  2056. return false;
  2057. }
  2058. };
  2059. /**
  2060. * Does nothing if no Inspect module (or no-action version of Inspect; user not allowed to use frontend instection).
  2061. *
  2062. * @function
  2063. * @name LogFilter.inspect
  2064. * @param {string|falsy} [prop]
  2065. * @return {void}
  2066. */
  2067. this.inspect = function(prop) {
  2068. if(typeof window.inspect === "function" && inspect.tcepsni === true) {
  2069. inspect(!prop ? _ : _[prop], _name + (!prop ? "" : (" - " + prop)));
  2070. }
  2071. };
  2072. /**
  2073. * @function
  2074. * @name LogFilter.inspectElements
  2075. * @param {string|falsy} [group]
  2076. * @return {void}
  2077. */
  2078. this.inspectElements = function(group) {
  2079. if(typeof window.inspect === "function" && inspect.tcepsni === true) {
  2080. inspect(!group ? _elements : _elements[group], "_elements" + (!group ? "" : ("." + group)));
  2081. }
  2082. };
  2083. /**
  2084. * Caches translated labels/message having no replacers.
  2085. *
  2086. * @function
  2087. * @name LogFilter.local
  2088. * @param {string} name
  2089. * @param {object|falsy} [replacers]
  2090. * @return {string}
  2091. */
  2092. this.local = function(name, replacers) {
  2093. var nm = name, s;
  2094. // S.... Drupal.t() doesnt use the 'g' flag when replace()'ing, so Drupal.t() replacement is utterly useless - and nowhere to report the bug :-(
  2095. if(!(s = _oGet(_local, nm))) {
  2096. switch(nm) {
  2097. case "default":
  2098. _local[nm] = s = Drupal.t("Default");
  2099. break;
  2100. case "adhoc":
  2101. _local[nm] = s = Drupal.t("Ad hoc");
  2102. break;
  2103. case "adhocForOrigin":
  2104. // {"!origin": nm}
  2105. s = Drupal.t("Ad hoc - based on !origin", replacers );
  2106. break;
  2107. case "newForOrigin":
  2108. // {"!origin": nm}
  2109. s = Drupal.t("New - based on !origin", replacers );
  2110. break;
  2111. case "newTitle":
  2112. _local[nm] = s = Drupal.t("New");
  2113. break;
  2114. case "newName":
  2115. _local[nm] = s = Drupal.t("new");
  2116. break;
  2117. case "savedNew":
  2118. // { "!filter": name }
  2119. s = Drupal.t("Saved new filter '!filter'.", replacers);
  2120. break;
  2121. case "saved":
  2122. // { "!filter": name }
  2123. s = Drupal.t("Saved filter '!filter'.", replacers);
  2124. break;
  2125. case "confirmDelete":
  2126. // { "!filter": _elements.filter.name.value }
  2127. s = Drupal.t("Are you sure you want to delete the filter!newline!filter?", replacers);
  2128. break;
  2129. case "invalid_date":
  2130. // {"!date": v, "!format": _.dateFormat}
  2131. s = Drupal.t("The date '!date' is not valid!newline- please use the format: !format", replacers);
  2132. break;
  2133. case "invalid_timeSequence_from":
  2134. _local[nm] = s = Drupal.t("'From' time cannot be later than 'To' time.");
  2135. break;
  2136. case "invalid_timeSequence_to":
  2137. _local[nm] = s = Drupal.t("'To' time cannot be earlier than 'From' time.");
  2138. break;
  2139. case "invalid_uid":
  2140. _local[nm] = s = Drupal.t("User ID must be a positive number, or empty.");
  2141. break;
  2142. case "invalid_location":
  2143. _local[nm] = s = Drupal.t("Requested URL must be a URL, or empty.");
  2144. break;
  2145. case "invalid_referer":
  2146. _local[nm] = s = Drupal.t("Referrer URL must be a URL, 'none', or empty.");
  2147. break;
  2148. case "error_machine_name_composition":
  2149. // { "!illegals": "default, adhoc" }
  2150. s = Drupal.t("The filter name:!newline- must be 2 to 32 characters long!newline- must only consist of the characters a-z, letters, and underscore (_)!newline- cannot start with a number!newline- cannot be: !illegals", replacers);
  2151. break;
  2152. case "error_filter_name_nonunique":
  2153. // {"!name": name}
  2154. s = Drupal.t("There's already a filter named!newline'!name'.!newlineDo you want to overwrite that filter?", replacers);
  2155. break;
  2156. case "error_filter_doesnt_exist":
  2157. // {"!name": name}
  2158. s = Drupal.t("There's no filter named!newline'!name'.", replacers);
  2159. break;
  2160. case "wait":
  2161. _local[nm] = s = Drupal.t("Please wait a sec...");
  2162. break;
  2163. case "wait_create":
  2164. _local[nm] = s = Drupal.t("Creating new filter. Please wait a sec...");
  2165. break;
  2166. case "wait_ereate":
  2167. _local[nm] = s = Drupal.t("Saving filter changes. Please wait a sec...");
  2168. break;
  2169. case "deleteLogs_prohibit":
  2170. _local[nm] = s = Drupal.t("Only allowed when the log list is freshly updated,!newlinereflecting current filter - press the 'Update list' button.");
  2171. break;
  2172. case "deleteLogs_all":
  2173. _local[nm] = s = Drupal.t("Do you want to delete!newlineALL logs?");
  2174. break;
  2175. case "deleteLogs_noMax":
  2176. // {"!offset": offset}
  2177. s = Drupal.t("Do you want to delete!newlineALL logs after event no. !offset?", replacers);
  2178. break;
  2179. case "deleteLogs_noOffset":
  2180. // {"!max": max}
  2181. s = Drupal.t("Do you want to delete logs!newlinewithout ANY condition!newlineexcept limited by a maximum of !max?", replacers);
  2182. break;
  2183. case "deleteLogs_noConditions":
  2184. // {"!offset": offset, "!max": max}
  2185. s = Drupal.t("Do you want to delete logs after event no. !offset!newlinewithout ANY condition!newlineexcept limited by a maximum of !max?", replacers);
  2186. break;
  2187. case "deleteLogs_storedAll":
  2188. // {"!name": name}
  2189. s = Drupal.t("Do you want to delete all logs matching!newlinethe '!name' filter!newlinelimited by NO maximum?", replacers);
  2190. break;
  2191. case "deleteLogs_storedNoMax":
  2192. // {"!offset": offset, !name": name}
  2193. s = Drupal.t("Do you want to delete all logs matching!newlinethe '!name' filter!newlineafter matching event no. !offset!newlinelimited by NO maximum?", replacers);
  2194. break;
  2195. case "deleteLogs_storedNoOffset":
  2196. // {"!offset": offset, !name": name}
  2197. s = Drupal.t("Do you want to delete all logs matching!newlinethe '!name' filter!newlineexcept limited by a maximum of !max?", replacers);
  2198. break;
  2199. case "deleteLogs_stored":
  2200. // {"!offset": offset, "!max": max, "!name": name}
  2201. s = Drupal.t("Do you want to delete all logs matching!newlinethe '!name' filter!newlineafter matching event no. !offset!newlinelimited by a maximum of !max?", replacers);
  2202. break;
  2203. case "deleteLogs_adhocAll":
  2204. _local[nm] = s = Drupal.t("Do you want to delete all logs!newlinematching current ad hoc filter!newlinelimited by NO maximum?");
  2205. break;
  2206. case "deleteLogs_adhocNoMax":
  2207. // {"!offset": offset}
  2208. s = Drupal.t("Do you want to delete all logs!newlinematching current ad hoc filter!newlineafter matching event no. !offset!newlinelimited by NO maximum?", replacers);
  2209. break;
  2210. case "deleteLogs_adhocNoOffset":
  2211. // {"!max": max}
  2212. s = Drupal.t("Do you want to delete all logs!newlinematching current ad hoc filter!newlineexcept limited by a maximum of !max?", replacers);
  2213. break;
  2214. case "deleteLogs_adhoc":
  2215. // {"!offset": offset, "!max": max}
  2216. s = Drupal.t("Do you want to delete all logs!newlinematching current ad hoc filter!newlineafter matching event no. !offset!newlinelimited by a maximum of !max?", replacers);
  2217. break;
  2218. case "deleteLogs_success":
  2219. // {"!number": integer}
  2220. s = Drupal.t("Deleted !number log events.", replacers);
  2221. break;
  2222. case "error_form_expired":
  2223. // {"!url": url}
  2224. s = Drupal.t("The form has become outdated!newline- please <a href=\"!url\">reload this page</a>.", replacers);
  2225. break;
  2226. case "error_perm_filter_crud":
  2227. _local[nm] = s = Drupal.t("Sorry, you're not allowed to edit saveable filters.");
  2228. break;
  2229. case "error_perm_filter_restricted":
  2230. _local[nm] = s = Drupal.t("You're not allowed to use that filter.");
  2231. break;
  2232. case "error_db_general":
  2233. _local[nm] = s = Drupal.t("Sorry, failed to save data.");
  2234. break;
  2235. case "error_unknown":
  2236. _local[nm] = s = Drupal.t("Sorry, something unexpected happened.");
  2237. break;
  2238. case "emergency":
  2239. _local[nm] = s = Drupal.t("emergency");
  2240. break;
  2241. case "alert":
  2242. _local[nm] = s = Drupal.t("alert");
  2243. break;
  2244. case "critical":
  2245. _local[nm] = s = Drupal.t("critical");
  2246. break;
  2247. case "error":
  2248. _local[nm] = s = Drupal.t("error");
  2249. break;
  2250. case "warning":
  2251. _local[nm] = s = Drupal.t("warning");
  2252. break;
  2253. case "notice":
  2254. _local[nm] = s = Drupal.t("notice");
  2255. break;
  2256. case "info":
  2257. _local[nm] = s = Drupal.t("info");
  2258. break;
  2259. case "debug":
  2260. _local[nm] = s = Drupal.t("debug");
  2261. break;
  2262. case "anonymous_user":
  2263. _local[nm] = s = Drupal.t("anonymous");
  2264. break;
  2265. case "deleted_user":
  2266. _local[nm] = s = Drupal.t("deleted");
  2267. break;
  2268. case "log_event":
  2269. _local[nm] = s = Drupal.t("Event");
  2270. break;
  2271. case "log_severity":
  2272. _local[nm] = s = Drupal.t("Severity");
  2273. break;
  2274. case "log_type":
  2275. _local[nm] = s = Drupal.t("Type");
  2276. break;
  2277. case "log_time":
  2278. _local[nm] = s = Drupal.t("Time");
  2279. break;
  2280. case "log_time_from":
  2281. _local[nm] = s = Drupal.t("Time From");
  2282. break;
  2283. case "log_time_to":
  2284. _local[nm] = s = Drupal.t("Time To");
  2285. break;
  2286. case "log_user":
  2287. case "log_uid":
  2288. _local[nm] = s = Drupal.t("User");
  2289. break;
  2290. case "log_location":
  2291. _local[nm] = s = Drupal.t("Location");
  2292. break;
  2293. case "log_referer":
  2294. _local[nm] = s = Drupal.t("Referrer");
  2295. break;
  2296. case "log_hostname":
  2297. _local[nm] = s = Drupal.t("Hostname");
  2298. break;
  2299. case "log_message":
  2300. _local[nm] = s = Drupal.t("Message");
  2301. break;
  2302. case "log_link":
  2303. _local[nm] = s = Drupal.t("Link");
  2304. break;
  2305. case "eventItem_display":
  2306. // {"!logId": integer}
  2307. s = Drupal.t("Event !logId", replacers);
  2308. break;
  2309. case "eventItemHover_filter":
  2310. // {"!logId": logId, '!filter': filter }
  2311. s = Drupal.t("Event !logId - press F key (or right-click) to filter !filter", replacers);
  2312. break;
  2313. case "eventItemHover_severity":
  2314. // {"!logId": logId, '!severity': severity}
  2315. s = Drupal.t("Event !logId (!severity) - press F key (or right-click) to filter Severity", replacers);
  2316. break;
  2317. case "eventItemHover_time":
  2318. // {"!logId": logId }
  2319. s = Drupal.t("Event !logId!newline - press F key (or right-click) to filter Time From!newline - press shift+F to filter Time To", replacers);
  2320. break;
  2321. case "eventItemHover_user":
  2322. // {"!logId": logId, '!uid': uid}
  2323. s = Drupal.t("Event !logId (user !uid) - press F key (or right-click) to filter User", replacers);
  2324. break;
  2325. case "filtered_event_column":
  2326. // {"!logId": logId, '!value': value }
  2327. s = Drupal.t("Filter !column by '!value'.", replacers);
  2328. break;
  2329. case "event_link":
  2330. _local[nm] = s = Drupal.t("Link to this log event");
  2331. break;
  2332. case "no_event_matches":
  2333. _local[nm] = s = Drupal.t("The current filter matches no events.");
  2334. break;
  2335. case "non_existing_event":
  2336. // {"!number": integer}
  2337. s = Drupal.t("Event ID !number doesn't exist.", replacers);
  2338. break;
  2339. case "event_from_url":
  2340. // {"!number": integer}
  2341. s = Drupal.t("Listing event ID !number, according to URL. Press 'Update list' button to reflect current filter.", replacers);
  2342. break;
  2343. case "add_type_item":
  2344. _local[nm] = s = Drupal.t("Add type...");
  2345. break;
  2346. case "type_option_dupe":
  2347. // {"!option": string}
  2348. s = Drupal.t("Type !option already exists.", replacers);
  2349. break;
  2350. case "pager_current":
  2351. // { '!first': (offset + 1), '!last': (offset + le), '!total': nTotal }
  2352. s = Drupal.t("!first-!last of !total", replacers);
  2353. break;
  2354. case "pager_current_none":
  2355. _local[nm] = s = Drupal.t("None");
  2356. break;
  2357. case "pager_current_outofrange":
  2358. // { '!offset': offset, '!total': nTotal }
  2359. s = Drupal.t("None after !offset, of !total", replacers);
  2360. break;
  2361. case "library_judy_incompatible":
  2362. // { '!version': version }
  2363. s = Drupal.t("Log Filter doesn't work without the Judy library, version !version or newer.", replacers);
  2364. break;
  2365. default:
  2366. s = "[LOCAL: " + nm + "]";
  2367. }
  2368. }
  2369. return s.replace(/\!newline/g, "\n");
  2370. };
  2371. /**
  2372. * For querying backend.
  2373. *
  2374. * Must be called delayed (after displaying overlay) to secure that validation (set-up in _prepareForm()) has done it's job.
  2375. *
  2376. * @function
  2377. * @name LogFilter.getCriteria
  2378. * @return {object}
  2379. */
  2380. this.getCriteria = function() {
  2381. var n = 0, conditions = {}, order_by = [], oElms = _elements.conditions, nm, r, v, le, i;
  2382. try {
  2383. // Rely on validation set-up in _prepareForm(), dont do the same thing once over.
  2384. for(nm in oElms) {
  2385. if(oElms.hasOwnProperty(nm)) {
  2386. r = oElms[nm];
  2387. switch(nm) {
  2388. case "time_from_proxy":
  2389. case "time_to_proxy":
  2390. case "time_from_time":
  2391. case "time_to_time":
  2392. break;
  2393. case "time_range":
  2394. case "time_from":
  2395. case "time_to":
  2396. case "uid":
  2397. if((v = r.value) !== "" && (v = $.trim(v)).length && (v = parseInt(v, 10)) > -1) {
  2398. ++n;
  2399. conditions[nm] = v;
  2400. }
  2401. break;
  2402. case "username":
  2403. // Skip, we use uid instead.
  2404. break;
  2405. case "role":
  2406. if((v = Judy.fieldValue(r)) !== "" && v !== "_none" && (v = $.trim(v)) && (v = parseInt(v, 10))) {
  2407. ++n;
  2408. conditions[nm] = v;
  2409. }
  2410. break;
  2411. case "severity_any":
  2412. case "type_any":
  2413. case "type_proxy":
  2414. // Check at severity_some/type_some instead.
  2415. break;
  2416. case "severity_some":
  2417. if(!oElms.severity_any.checked) {
  2418. v = [];
  2419. le = r.length;
  2420. for(i = 0; i < le; i++) {
  2421. if(r[i].checked) {
  2422. v.push(r[i].value);
  2423. }
  2424. }
  2425. if(v.length) {
  2426. ++n;
  2427. conditions.severity = v;
  2428. }
  2429. }
  2430. break;
  2431. case "type_some":
  2432. if((v = r.value) !== "" && (v = $.trim(v))) {
  2433. ++n;
  2434. conditions.type = v.split(/\n/);
  2435. }
  2436. break;
  2437. case "hostname":
  2438. case "location":
  2439. case "referer":
  2440. if((v = r.value) !== "" && (v = $.trim(v)) && v !== '*') {
  2441. ++n;
  2442. conditions[nm] = v;
  2443. }
  2444. break;
  2445. default:
  2446. throw new Error("Condition[" + nm + "] not supported.");
  2447. }
  2448. }
  2449. }
  2450. le = (oElms = _elements.orderBy).length;
  2451. for(i = 0; i < le; i++) {
  2452. if((v = Judy.fieldValue(oElms[i][0])) && v !== "_none" && (v = $.trim(v))) {
  2453. order_by.push([
  2454. v,
  2455. oElms[i][1].checked ? "DESC" : "ASC"
  2456. ]);
  2457. }
  2458. }
  2459. }
  2460. catch(er) {
  2461. _errorHandler(er, 0, _name + ".getCriteria()");
  2462. }
  2463. return {
  2464. nConditions: n,
  2465. conditions: conditions,
  2466. order_by: order_by
  2467. };
  2468. };
  2469. /**
  2470. * Singleton, instantiated to itself.
  2471. * @constructor
  2472. * @namespace
  2473. * @name LogFilter.Message
  2474. * @singleton
  2475. */
  2476. this.Message = function() {
  2477. var _self = this,
  2478. _n = -1,
  2479. _htmlList = "<div id=\"log_filter__message\"><div><div id=\"log_filter__message_list\"></div></div></div>",
  2480. _htmlItem = "<div id=\"log_filter__message___NO__\" class=\"log-filter-message-__TYPE__\"><div class=\"log-filter--message-content\"><span>__CONTENT__</span></div><div title=\"" +
  2481. Drupal.t("Close") + "\">x</div></div>",
  2482. _list,
  2483. _faders = {},
  2484. /**
  2485. * @function
  2486. * @name LogFilter.Message._close
  2487. * @return {void}
  2488. */
  2489. _close = function() {
  2490. $(this.parentNode).hide();
  2491. },
  2492. /**
  2493. * Message item fader.
  2494. *
  2495. * Not prototypal because the 'this' of prototypal methods as event handlers is masked by jQuery's element 'this' (or for inline handlers the global window 'this').
  2496. * Could use prototypal methods if we passed the the 'this' of the fader to jQuery handlers, but that would result in lots of references to the fader object (and probably more overall overhead).
  2497. *
  2498. * @constructor
  2499. * @class
  2500. * @name LogFilter.Message._fader
  2501. * @param {string} selector
  2502. * @param {integer|float|falsy} [delay]
  2503. * - default: 3000 (milliseconds)
  2504. * - if less than 1000 it will be used as multiplier against the default delay
  2505. */
  2506. _fader = function(selector, delay) {
  2507. var __self = this,
  2508. /**
  2509. * Default delay.
  2510. *
  2511. * @name LogFilter.Message._fader#_delayDefault
  2512. * @type integer
  2513. */
  2514. _delayDefault = 3000,
  2515. /**
  2516. * Interval setting.
  2517. *
  2518. * @name LogFilter.Message._fader#_pause
  2519. * @type integer
  2520. */
  2521. _pause = 150, // Milliseconds.
  2522. /**
  2523. * Opacity decrease factor setting.
  2524. *
  2525. * @name LogFilter.Message._fader#_factor
  2526. * @type float
  2527. */
  2528. _factor = 1.2,
  2529. /**
  2530. * State.
  2531. *
  2532. * @name LogFilter.Message._fader#_stopped
  2533. * @type boolean
  2534. */
  2535. _stopped,
  2536. /**
  2537. * @name LogFilter.Message._fader#_opacity
  2538. * @type integer
  2539. */
  2540. _opacity = 100,
  2541. /**
  2542. * @name LogFilter.Message._fader#_subtractor
  2543. * @type integer
  2544. */
  2545. _subtractor = 1,
  2546. /**
  2547. * @function
  2548. * @name LogFilter.Message._fader#_start
  2549. * @return {void}
  2550. */
  2551. _start = function() {
  2552. /** @ignore */
  2553. __self._interval = setInterval(_fade, _pause)
  2554. },
  2555. /**
  2556. * @function
  2557. * @name LogFilter.Message._fader#_fade
  2558. * @return {void}
  2559. */
  2560. _fade = function() {
  2561. var n = _opacity, jq = __self._jq;
  2562. if(!_stopped) {
  2563. if((_opacity = (n -= (_subtractor *= _factor))) > 0) {
  2564. if(Judy.browserIE < 11) {
  2565. jq.css("opacity", n / 100);
  2566. }
  2567. else {
  2568. jq.css({
  2569. "-ms-filter": "progid:DXImageTransform.Microsoft.Alpha(Opacity=" + (n = Math.round(n)) + ")",
  2570. filter: "alpha(opacity=" + n + ")"
  2571. });
  2572. }
  2573. }
  2574. else {
  2575. _stopped = true;
  2576. clearInterval(__self._interval);
  2577. jq.hide();
  2578. }
  2579. }
  2580. },
  2581. /** @ignore */
  2582. jq;
  2583. /**
  2584. * @function
  2585. * @name LogFilter.Message._fader#stop
  2586. * @return {void}
  2587. */
  2588. this.stop = function() {
  2589. if(!_stopped) {
  2590. _stopped = true;
  2591. clearTimeout(__self._timeout);
  2592. clearInterval(__self._interval);
  2593. }
  2594. };
  2595. /**
  2596. * @function
  2597. * @name LogFilter.Message._fader#unfade
  2598. * @return {void}
  2599. */
  2600. this.unfade = function() {
  2601. __self.stop();
  2602. if(_opacity < 100) {
  2603. if(Judy.browserIE < 11) {
  2604. __self._jq.css("opacity", 1);
  2605. }
  2606. else {
  2607. __self._jq.css({
  2608. "-ms-filter": "progid:DXImageTransform.Microsoft.Alpha(Opacity=100)",
  2609. filter: "alpha(opacity=100)"
  2610. });
  2611. }
  2612. }
  2613. };
  2614. /**
  2615. * @function
  2616. * @name LogFilter.Message._fader#destroy
  2617. * @return {void}
  2618. */
  2619. this.destroy = function() {
  2620. __self.stop();
  2621. delete __self._jq;
  2622. };
  2623. // Construction logics.
  2624. if((jq = $(selector)).get(0)) {
  2625. /**
  2626. * @name LogFilter.Message._fader#_jq
  2627. * @type jquery
  2628. */
  2629. this._jq = jq;
  2630. /** @ignore */
  2631. this._timeout = setTimeout(
  2632. _start,
  2633. !delay ? _delayDefault : (delay < 1000 ? Math.floor(delay * _delayDefault) : _delayDefault)
  2634. );
  2635. }
  2636. };
  2637. /**
  2638. * @function
  2639. * @name LogFilter.Message.setup
  2640. * @return {void}
  2641. */
  2642. this.setup = function() {
  2643. var elm, jq;
  2644. if((elm = document.getElementById("console"))) {
  2645. $(elm).after(_htmlList);
  2646. }
  2647. else {
  2648. $("#content").prepend(_htmlList);
  2649. }
  2650. _list = document.getElementById("log_filter__message_list");
  2651. // Draggable.
  2652. if((jq = $(_list)).draggable) {
  2653. jq.draggable({ handle: "div.log-filter--message-content", cancel: "span", cursor: "move" });
  2654. }
  2655. };
  2656. /**
  2657. * @function
  2658. * @name LogFilter.Message.set
  2659. * @param {mixed} txt
  2660. * @param {string} [type]
  2661. * - default: 'status'
  2662. * - values: 'status' | 'info' | 'notice' | 'warning' | 'error'
  2663. * @param {object} [options]
  2664. * - (boolean) noFade: default false ~ a 'status' or 'info' message will eventually fade away, unless clicked/mousedowned
  2665. * - (number) fadeDelay: default zero ~ use default delay before starting fade ('status' message only)
  2666. * - (number) fadeDelay: >1000 ~ use that delay | < 1000 multiply default delay with that number (both 'status' message only)
  2667. * - (boolean) modal: default false ~ do not display blocking overlay
  2668. * - (function) close: function to execute upon click on close button
  2669. * @param {integer} [delay]
  2670. * - default: 4000 (milliseconds)
  2671. * @return {void}
  2672. */
  2673. this.set = function(txt, type, options) {
  2674. var t = type || "status", s, f, k, jq, o = {
  2675. noFade: true,
  2676. fadeDelay: 0,
  2677. modal: false,
  2678. close: null
  2679. };
  2680. switch(t) {
  2681. case "status":
  2682. case "info":
  2683. o.noFade = false;
  2684. break;
  2685. case "notice":
  2686. case "warning":
  2687. break;
  2688. default:
  2689. t = "error";
  2690. }
  2691. if(options) {
  2692. for(k in o) {
  2693. if(o.hasOwnProperty(k) && options.hasOwnProperty(k)) {
  2694. o[k] = options[k];
  2695. }
  2696. }
  2697. }
  2698. // Add message to DOM.
  2699. $(_list).prepend(
  2700. _htmlItem.replace(/__NO__/, ++_n).replace(/__TYPE__/, t).replace(/__CONTENT__/, txt ? txt.replace(/\n/g, "<br/>") : "")
  2701. );
  2702. // Close behaviours.
  2703. (jq = $((s = "#log_filter__message_" + _n) + " > div:last-child")).click(_close);
  2704. // If modal, show overlay.
  2705. if(o.modal) {
  2706. jq.click(Judy.overlay); // And hide it on close click.
  2707. Judy.overlay(1, true); // Opaque, no hover title.
  2708. }
  2709. // Close function.
  2710. if(o.close) {
  2711. jq.click(o.close);
  2712. }
  2713. // If to be fading, make click on message content unfade the message.
  2714. if(!o.noFade) {
  2715. _faders[ "_" + _n ] = f = new _fader(s, o.fadeDelay);
  2716. $(s + " > div:first-child").bind("click mousedown", f.unfade); // And mousedown, otherwise dragging wont prevent fade.
  2717. }
  2718. // Display the message.
  2719. $(s).show();
  2720. };
  2721. /**
  2722. * @function
  2723. * @name LogFilter.Message.showAll
  2724. * @return {void}
  2725. */
  2726. this.showAll = function() {
  2727. var le = _n + 1, i, f;
  2728. for(i = 0; i < le; i++) {
  2729. if((f = _faders[ "_" + i ]) && _faders.hasOwnProperty("_" + i)) {
  2730. f.unfade();
  2731. }
  2732. $("#log_filter__message_" + i).show();
  2733. }
  2734. };
  2735. };
  2736. /**
  2737. * @param {integer|falsy|string} logId
  2738. * @return {void}
  2739. */
  2740. this.displayLog = function(logId) {
  2741. var o, s, v, css = 'log-filter-log-display', dialId = 'log_filter_logDisplay_' + logId, elm, $dialOuter, dialInner;
  2742. if ((o = _logs['_' + logId]) && _logs.hasOwnProperty('_' + logId)) {
  2743. // If already open: close the dialog.
  2744. if ((elm = document.getElementById(dialId))) {
  2745. $('#log_filter_list_log_' + logId).removeClass('log-filter-list-displayed');
  2746. Judy.dialog(dialId, "close");
  2747. }
  2748. else {
  2749. $('#log_filter_list_log_' + logId).addClass('log-filter-list-displayed');
  2750. o = _logs['_' + logId];
  2751. s = '<div class="' + css + '">' +
  2752. '<table class="dblog-event"><tbody>' +
  2753. '<tr class="odd"><th>' + self.local('log_severity') + '</th>' +
  2754. '<td>' + (v = o.severity_string) + '<div class="' + css + '-severity ' + css + '-' + v + '">&#160;</div></td></tr>' +
  2755. '<tr class="even"><th>' + self.local('log_type') + '</th><td>' + o.type + '</td></tr>' +
  2756. '<tr class="odd"><th>' + self.local('log_time') + '</th><td>' + o.time + '</td></tr>' +
  2757. '<tr class="even"><th>' + self.local('log_user') + '</th>' +
  2758. '<td>' + (!o.uid ? o.name : ('<a href="/user/' + o.uid + '" title="' + o.uid + '">(' + o.uid + ') ' + o.name + '</a>')) +
  2759. ' &#160; &bull; &#160; ' + self.local('log_hostname') + ': ' + o.hostname + '</td></tr>' +
  2760. '<tr class="odd"><th>' + self.local('log_location') + '</th><td><a href="' + o.location + '">' + o.location + '</a></td></tr>' +
  2761. '<tr class="even"><th>' + self.local('log_referer') + '</th>' +
  2762. '<td>' + (!o.referer ? '&#160;' : ('<a href="' + o.referer + '">' + o.referer + '</a>')) + '</td></tr>' +
  2763. '<tr class="odd"><th>' + self.local('log_message') + '</th><td>' + o.message + '</td></tr>' +
  2764. (!o.link ? '' : ('<tr class="even"><th>' + self.local('log_link') + '</th><td><a href="' + o.link + '">' + o.link + '</a></td></tr>')) +
  2765. '</tbody></table>' +
  2766. '</div>';
  2767. Judy.dialog(dialId, {
  2768. title: '<a href="' + _url() + '/' + o.wid + '" title="' + self.local('event_link') + '">' + self.local('log_event') + ': ' + o.wid + '</a>',
  2769. content: s,
  2770. fixed: true,
  2771. resizable: false,
  2772. closeOnEscape: false, // Set behaviour that closes all log filter dialogs on escape, disregarding current focus.
  2773. dialogClass: "log-filter-log-display-dialog",
  2774. contentClass: "log-filter-log-display-content",
  2775. autoOpen: false,
  2776. close: function(event, ui) {
  2777. setTimeout(function() {
  2778. $('#log_filter_logDisplay_' + logId).dialog('destroy').remove();
  2779. $('#log_filter_list_log_' + logId).removeClass('log-filter-list-displayed');
  2780. });
  2781. }
  2782. });
  2783. ($dialOuter = $( (dialInner = $('#' + dialId).get(0)).parentNode )).css({
  2784. visibility: 'hidden',
  2785. overflow: 'visible'
  2786. });
  2787. Judy.dialog(dialId, "open");
  2788. Judy.outerWidth($dialOuter, true, Judy.innerWidth(window) - 200, 2);
  2789. Judy.outerHeight('#' + dialId, true,
  2790. Judy.outerHeight($dialOuter, true, Judy.outerHeight(window) - 10, 1) -
  2791. Judy.outerHeight($('div.ui-dialog-titlebar', $dialOuter)) -
  2792. Math.ceil(parseFloat($dialOuter.css("padding-top")) + parseFloat($dialOuter.css("padding-bottom"))) -
  2793. _.adminOverlayOffset,
  2794. 1
  2795. );
  2796. $dialOuter.css({
  2797. visibility: 'visible',
  2798. left: '150px', // jQuery UI dialog position apparantly doesnt work well when css position is fixed.
  2799. top: (4 + _.adminOverlayOffset) + 'px'
  2800. });
  2801. // Apply behaviours (if any).
  2802. Drupal.attachBehaviors($dialOuter.get(0));
  2803. }
  2804. }
  2805. };
  2806. /**
  2807. * Called before page load.
  2808. *
  2809. * @function
  2810. * @name LogFilter.init
  2811. * @param {boolean|integer} useModuleCss
  2812. * @param {string} theme
  2813. * @return {void}
  2814. */
  2815. this.init = function(useModuleCss, theme) {
  2816. var v;
  2817. /** @ignore */
  2818. self.init = function() {};
  2819. // Make sure Judy exists and is version 2.0+.
  2820. if (typeof window.Judy !== 'object' || !(v = Judy.version) || Judy.version < _.library_judy_version) {
  2821. _.library_judy_compatible = false;
  2822. return;
  2823. }
  2824. // Tell styles about theme.
  2825. if((_.useModuleCss = useModuleCss)) {
  2826. $("div#page").addClass("theme-" + theme);
  2827. }
  2828. // Set overlay, to prevent user from doing anything before page load and after form submission.
  2829. Judy.overlay(1, false, self.local("wait"));
  2830. };
  2831. /**
  2832. * Called upon page load.
  2833. *
  2834. * @function
  2835. * @name LogFilter.setup
  2836. * @param {object} [filters]
  2837. * @param {array} [messages]
  2838. * @return {void}
  2839. */
  2840. this.setup = function(filters, messages) {
  2841. var a = messages, le, i, o = { fadeDelay: 2 }, url, wid; // Long (double) delay when at page load.
  2842. /** @ignore */
  2843. self.setup = function() {};
  2844. _filters = filters || [];
  2845. if (!_.library_judy_compatible) {
  2846. alert(self.local('library_judy_incompatible', { '!version': _.library_judy_version }));
  2847. return;
  2848. }
  2849. _prepareForm();
  2850. _setMode(_.mode, false, true);
  2851. // Display messages, if any.
  2852. (self.Message = new self.Message()).setup();
  2853. if(a) {
  2854. le = a.length;
  2855. // Check if any message isnt of type status; status message should fade, unless there's another message of a different (more urgent) type.
  2856. for(i = 0; i < le; i++) {
  2857. if(a[i][1] && a[i][1] !== "status") {
  2858. o.noFade = true;
  2859. break;
  2860. }
  2861. }
  2862. for(i = 0; i < le; i++) {
  2863. self.Message.set(a[i][0], a[i][1], o);
  2864. }
  2865. }
  2866. // Set title attribute of all labels containing a span that has a non-empty title attribute.
  2867. $('label > span[title]').each(function() {
  2868. var t = this.getAttribute('title');
  2869. if (t) {
  2870. this.parentNode.setAttribute('title', t);
  2871. }
  2872. });
  2873. // Check if administrative Overlay is on.
  2874. if (!/^#overlay=admin\//.test(top.location.hash)) {
  2875. url = window.location.href;
  2876. _.adminOverlayOffset = 0;
  2877. }
  2878. else {
  2879. url = top.location.href + top.location.hash;
  2880. }
  2881. // Prepare log list.
  2882. _getLogList(
  2883. // Check if url ends with /integer ~ single log view.
  2884. /^.+\/(\d+)\/?$/.test(url) && (wid = parseInt(url.replace(/^.+\/(\d+)\/?$/, '$1'), 10)) &&
  2885. wid <= Math.pow(2, 31) ? wid : 0
  2886. );
  2887. // Make all event dialogs close on escape, and no matter what has focus.
  2888. Judy.keydown(document.documentElement, "escape", function() {
  2889. $('div.log-filter-log-display-content').each(function() {
  2890. $(this).dialog("close");
  2891. });
  2892. });
  2893. Judy.overlay(0);
  2894. };
  2895. }
  2896. window.LogFilter = new LogFilter($);
  2897. })(jQuery);