form.js 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702
  1. (function ($) {
  2. /*
  3. *
  4. * provides feedback form for zammad
  5. *
  6. <button id="zammad-feedback-form">Feedback</button>
  7. <script id="zammad_form_script" src="http://localhost:3000/assets/form/form.js"></script>
  8. <script>
  9. $(function() {
  10. $('#zammad-feedback-form').ZammadForm({
  11. messageTitle: 'Feedback Form', // optional
  12. messageSubmit: 'Submit', // optional
  13. messageThankYou: 'Thank you for your inquiry (#%s)! We\'ll contact you as soon as possible.', // optional
  14. messageNoConfig: 'Unable to load form config from server. Maybe feature is disabled.', // optional
  15. showTitle: true,
  16. lang: 'de', // optional, <html lang="xx"> will be used per default
  17. modal: true,
  18. attachmentSupport: false,
  19. attributes: [
  20. {
  21. display: 'Name',
  22. name: 'name',
  23. tag: 'input',
  24. type: 'text',
  25. placeholder: 'Your Name',
  26. defaultValue: '',
  27. },
  28. {
  29. display: 'Email',
  30. name: 'email',
  31. tag: 'input',
  32. type: 'email',
  33. required: true,
  34. placeholder: 'Your Email',
  35. defaultValue: function () {return User.email;},
  36. },
  37. {
  38. display: 'Message',
  39. name: 'body',
  40. tag: 'textarea',
  41. required: true,
  42. placeholder: 'Your Message…',
  43. defaultValue: '',
  44. rows: 7,
  45. },
  46. {
  47. display: 'Attachments',
  48. name: 'file[]',
  49. tag: 'input',
  50. type: 'file',
  51. repeat: 3,
  52. },
  53. ]
  54. });
  55. });
  56. </script>
  57. */
  58. var pluginName = 'ZammadForm',
  59. defaults = {
  60. lang: undefined,
  61. debug: false,
  62. noCSS: false,
  63. prefixCSS: 'zammad-form-',
  64. showTitle: false,
  65. messageTitle: 'Zammad Form',
  66. messageSubmit: 'Submit',
  67. messageThankYou: 'Thank you for your inquiry! We\'ll contact you as soon as possible.',
  68. messageNoConfig: 'Unable to load form config from server. Maybe feature is disabled.',
  69. attachmentSupport: false,
  70. attributes: [
  71. {
  72. display: 'Name',
  73. name: 'name',
  74. tag: 'input',
  75. type: 'text',
  76. id: 'zammad-form-name',
  77. required: true,
  78. placeholder: 'Your Name',
  79. defaultValue: '',
  80. },
  81. {
  82. display: 'Email',
  83. name: 'email',
  84. tag: 'input',
  85. type: 'email',
  86. id: 'zammad-form-email',
  87. required: true,
  88. placeholder: 'Your Email',
  89. defaultValue: '',
  90. },
  91. {
  92. display: 'Message',
  93. name: 'body',
  94. tag: 'textarea',
  95. id: 'zammad-form-body',
  96. required: true,
  97. placeholder: 'Your Message…',
  98. defaultValue: '',
  99. rows: 7,
  100. },
  101. ],
  102. translations: {
  103. // ZAMMAD_TRANSLATIONS_START
  104. 'cs': {
  105. 'Attachments': 'Přílohy',
  106. 'Email': 'Email',
  107. 'Message': 'Zpráva',
  108. 'Name': 'Jméno',
  109. 'Your Email': 'Váš e-mail',
  110. 'Your Message…': 'Vaše zpráva…',
  111. 'Your Name': 'Vaše jméno',
  112. },
  113. 'de': {
  114. 'Attachments': 'Anhänge',
  115. 'Email': 'E-Mail',
  116. 'Message': 'Nachricht',
  117. 'Name': 'Name',
  118. 'Your Email': 'Ihre E-Mail',
  119. 'Your Message…': 'Ihre Nachricht…',
  120. 'Your Name': 'Ihr Name',
  121. },
  122. 'es': {
  123. 'Attachments': 'Adjuntos',
  124. 'Email': 'Correo electrónico',
  125. 'Message': 'Mensaje',
  126. 'Name': 'Nombre',
  127. 'Your Email': 'Tu correo electrónico',
  128. 'Your Message…': 'Su mensaje…',
  129. 'Your Name': 'tu Nombre',
  130. },
  131. 'et': {
  132. 'Attachments': 'Manused',
  133. 'Email': 'E-post',
  134. 'Message': 'Teade',
  135. 'Name': 'Nimi',
  136. 'Your Email': 'Sinu Meiliaadress',
  137. 'Your Message…': 'Sinu Teade…',
  138. 'Your Name': 'Sinu Nimi',
  139. },
  140. 'fa': {
  141. 'Attachments': 'ضمایم',
  142. 'Email': 'رایانامه',
  143. 'Message': 'پیام',
  144. 'Name': 'نام',
  145. 'Your Email': 'ایمیل شما',
  146. 'Your Message…': 'پیام شما…',
  147. 'Your Name': 'نام شما',
  148. },
  149. 'fr': {
  150. 'Attachments': 'Pièces jointes',
  151. 'Email': 'E-mail',
  152. 'Message': 'Message',
  153. 'Name': 'Nom',
  154. 'Your Email': 'Votre email',
  155. 'Your Message…': 'Votre message…',
  156. 'Your Name': 'Votre nom',
  157. },
  158. 'hr': {
  159. 'Attachments': 'Privici',
  160. 'Email': 'E-Mail',
  161. 'Message': 'Poruka',
  162. 'Name': 'Ime',
  163. 'Your Email': 'Vaš e-mail',
  164. 'Your Message…': 'Vaša poruka…',
  165. 'Your Name': 'Vaše ime',
  166. },
  167. 'hu': {
  168. 'Attachments': 'Csatolmányok',
  169. 'Email': 'E-mail',
  170. 'Message': 'Üzenet',
  171. 'Name': 'Név',
  172. 'Your Email': 'Az Ön e-mail címe',
  173. 'Your Message…': 'Az Ön üzenete…',
  174. 'Your Name': 'Az Ön neve',
  175. },
  176. 'it': {
  177. 'Attachments': 'Allegati',
  178. 'Email': 'Email',
  179. 'Message': 'Messaggio',
  180. 'Name': 'Nome',
  181. 'Your Email': 'Il tuo indirizzo e-mail',
  182. 'Your Message…': 'Il tuo messaggio…',
  183. 'Your Name': 'Il tuo nome',
  184. },
  185. 'lt': {
  186. 'Attachments': 'Prisegtukai',
  187. 'Email': 'El. paštas',
  188. 'Message': 'Žinutė',
  189. 'Name': 'Vardas',
  190. 'Your Email': 'Jūsų el. paštas',
  191. 'Your Message…': 'Jūsų žinutė…',
  192. 'Your Name': 'Jūsų vardas',
  193. },
  194. 'nl': {
  195. 'Attachments': 'Bijlagen',
  196. 'Email': 'E-mail',
  197. 'Message': 'Bericht',
  198. 'Name': 'Naam',
  199. 'Your Email': 'Je e-mailadres',
  200. 'Your Message…': 'Je bericht…',
  201. 'Your Name': 'Je naam',
  202. },
  203. 'pl': {
  204. 'Attachments': 'Załączniki',
  205. 'Email': 'E-mail',
  206. 'Message': 'Wiadomość',
  207. 'Name': 'Nazwa',
  208. 'Your Email': 'Adres e-mail',
  209. 'Your Message…': 'Twoja wiadomość…',
  210. 'Your Name': 'Imię i nazwisko',
  211. },
  212. 'pt-br': {
  213. 'Attachments': 'Anexos',
  214. 'Email': 'Email',
  215. 'Message': 'Mensagem',
  216. 'Name': 'Nome',
  217. 'Your Email': 'Seu Email',
  218. 'Your Message…': 'Sua Mensagem…',
  219. 'Your Name': 'Seu nome',
  220. },
  221. 'ro': {
  222. 'Attachments': 'Atașamente',
  223. 'Email': 'E-mail',
  224. 'Message': 'Mesaj',
  225. 'Name': 'Nume',
  226. 'Your Email': 'Adresă de e-mail',
  227. 'Your Message…': 'Mesajul tău…',
  228. 'Your Name': 'Numele tău',
  229. },
  230. 'ru': {
  231. 'Attachments': 'Вложения',
  232. 'Email': 'Электронная почта',
  233. 'Message': 'Сообщение',
  234. 'Name': 'Имя',
  235. 'Your Email': 'Ваша почта',
  236. 'Your Message…': 'Ваше сообщение…',
  237. 'Your Name': 'Ваше имя',
  238. },
  239. 'sk': {
  240. 'Attachments': 'Prílohy',
  241. 'Email': 'E-mail',
  242. 'Message': 'Správa',
  243. 'Name': 'Meno',
  244. 'Your Email': 'Váš e-mail',
  245. 'Your Message…': 'Vaša správa…',
  246. 'Your Name': 'Vaše meno',
  247. },
  248. 'sr': {
  249. 'Attachments': 'Прилози',
  250. 'Email': 'Имејл',
  251. 'Message': 'Порука',
  252. 'Name': 'Назив',
  253. 'Your Email': 'Ваш имејл',
  254. 'Your Message…': 'Ваша порука…',
  255. 'Your Name': 'Ваше име',
  256. },
  257. 'sr-latn-rs': {
  258. 'Attachments': 'Prilozi',
  259. 'Email': 'Imejl',
  260. 'Message': 'Poruka',
  261. 'Name': 'Naziv',
  262. 'Your Email': 'Vaš imejl',
  263. 'Your Message…': 'Vaša poruka…',
  264. 'Your Name': 'Vaše ime',
  265. },
  266. 'sv': {
  267. 'Attachments': 'Bilagor',
  268. 'Email': 'E-post',
  269. 'Message': 'Meddelande',
  270. 'Name': 'Namn',
  271. 'Your Email': 'Din mejl',
  272. 'Your Message…': 'Ditt meddelande…',
  273. 'Your Name': 'Ditt namn',
  274. },
  275. 'uk': {
  276. 'Attachments': 'Вкладення',
  277. 'Email': 'Email',
  278. 'Message': 'Повідомлення',
  279. 'Name': 'Ім\'я',
  280. 'Your Email': 'Ваша електронна пошта',
  281. 'Your Message…': 'Ваше повідомлення…',
  282. 'Your Name': 'Ваше ім\'я',
  283. },
  284. 'zh-cn': {
  285. 'Attachments': '附件',
  286. 'Email': '邮件地址',
  287. 'Message': '消息',
  288. 'Name': '名称',
  289. 'Your Email': '您的邮件地址',
  290. 'Your Message…': '',
  291. 'Your Name': '您的尊姓大名',
  292. },
  293. 'zh-tw': {
  294. 'Attachments': '附件',
  295. 'Email': '電子郵件',
  296. 'Message': '訊息',
  297. 'Name': '名稱',
  298. 'Your Email': '請留下您的電子郵件地址',
  299. 'Your Message…': '',
  300. 'Your Name': '您的尊姓大名',
  301. },
  302. // ZAMMAD_TRANSLATIONS_END
  303. }
  304. };
  305. function Plugin(element, options) {
  306. this.element = element
  307. this.$element = $(element)
  308. this._defaults = defaults;
  309. this._name = pluginName;
  310. this._endpoint_config = '/api/v1/form_config'
  311. this._endpoint_submit = '/api/v1/form_submit'
  312. this._script_location = '/assets/form/form.js'
  313. this._css_location = '/assets/form/form.css'
  314. this._src = document.getElementById('zammad_form_script').src
  315. this.css_location = this._src.replace(this._script_location, this._css_location)
  316. this.endpoint_config = this._src.replace(this._script_location, this._endpoint_config)
  317. this.endpoint_submit = this._src.replace(this._script_location, this._endpoint_submit)
  318. this.options = $.extend(true, {}, defaults, options)
  319. if (!this.options.lang) {
  320. this.options.lang = $('html').attr('lang')
  321. }
  322. if (this.options.lang) {
  323. this.options.lang = this.options.lang.replace(/-.+?$/, '')
  324. this.log('debug', "lang: " + this.options.lang)
  325. }
  326. this._config = {}
  327. this._token = ''
  328. this.init()
  329. }
  330. Plugin.prototype.init = function () {
  331. var _this = this,
  332. params = {}
  333. _this.log('debug', 'init', this._src)
  334. if (!_this.options.noCSS) {
  335. _this.loadCss(_this.css_location)
  336. }
  337. if (_this.options.attachmentSupport === true || _this.options.attachmentSupport === 'true') {
  338. var attachment = {
  339. display: 'Attachments',
  340. name: 'file[]',
  341. tag: 'input',
  342. type: 'file',
  343. repeat: 1,
  344. }
  345. _this.options.attributes.push(attachment)
  346. }
  347. if (_this.options.agreementMessage) {
  348. var agreement = {
  349. display: _this.options.agreementMessage,
  350. name: 'agreement',
  351. tag: 'input',
  352. type: 'checkbox',
  353. id: 'zammad-form-agreement',
  354. required: true,
  355. defaultValue: '',
  356. }
  357. _this.options.attributes.push(agreement)
  358. }
  359. _this.log('debug', 'endpoint_config: ' + _this.endpoint_config)
  360. _this.log('debug', 'endpoint_submit: ' + _this.endpoint_submit)
  361. // load config
  362. if (this.options.test) {
  363. params.test = true
  364. }
  365. params.fingerprint = this.fingerprint()
  366. $.ajax({
  367. method: 'post',
  368. url: _this.endpoint_config,
  369. cache: false,
  370. processData: true,
  371. data: params
  372. }).done(function(data) {
  373. _this.log('debug', 'config:', data)
  374. _this._config = data
  375. }).fail(function(jqXHR, textStatus, errorThrown) {
  376. if (jqXHR.status == 401) {
  377. _this.log('error', 'Faild to load form config, wrong authentication data!')
  378. }
  379. else if (jqXHR.status == 403) {
  380. _this.log('error', 'Faild to load form config, feature is disabled or request is wrong!')
  381. }
  382. else {
  383. _this.log('error', 'Faild to load form config!')
  384. }
  385. _this.noConfig()
  386. });
  387. // show form
  388. if (!this.options.modal) {
  389. _this.render()
  390. }
  391. // bind form on call
  392. else {
  393. this.$element.off('click.zammad-form').on('click.zammad-form', function (e) {
  394. e.preventDefault()
  395. _this.render()
  396. return true
  397. })
  398. }
  399. }
  400. // load css
  401. Plugin.prototype.loadCss = function(filename) {
  402. if (document.createStyleSheet) {
  403. document.createStyleSheet(filename)
  404. }
  405. else {
  406. $('<link rel="stylesheet" type="text/css" href="' + filename + '" />').appendTo('head')
  407. }
  408. }
  409. // send
  410. Plugin.prototype.submit = function() {
  411. var _this = this
  412. // check min modal open time
  413. if (_this.modalOpenTime) {
  414. var currentTime = new Date().getTime()
  415. var diff = currentTime - _this.modalOpenTime.getTime()
  416. _this.log('debug', 'currentTime', currentTime)
  417. _this.log('debug', 'modalOpenTime', _this.modalOpenTime.getTime())
  418. _this.log('debug', 'diffTime', diff)
  419. if (diff < 1000*10) {
  420. alert('Sorry, you look like a robot!')
  421. return
  422. }
  423. }
  424. // disable form
  425. _this.$form.find('button').prop('disabled', true)
  426. $.ajax({
  427. method: 'post',
  428. url: _this.endpoint_submit,
  429. data: _this.getParams(),
  430. cache: false,
  431. contentType: false,
  432. processData: false,
  433. }).done(function(data) {
  434. // Remove the errors from the form.
  435. _this.$form.find('.zammad-form-group--has-error').removeClass('zammad-form-group--has-error')
  436. // Deprecated code, can be removed in future versions:
  437. _this.$form.find('.has-error').removeClass('has-error')
  438. // set errors
  439. if (data.errors) {
  440. $.each(data.errors, function( key, value ) {
  441. _this.$form.find('[name=' + key + ']').closest('.'+ _this.options.prefixCSS +'group').addClass('zammad-form-group--has-error')
  442. // Deprecated code, can be removed in future versions:
  443. _this.$form.find('[name=' + key + ']').closest('.form-group').addClass('has-error')
  444. })
  445. if (data.errors.token) {
  446. alert(data.errors.token)
  447. }
  448. _this.$form.find('button').prop('disabled', false)
  449. return
  450. }
  451. // ticket has been created
  452. _this.thanks(data)
  453. }).fail(function() {
  454. _this.$form.find('button').prop('disabled', false)
  455. alert('The form could not be submitted!')
  456. });
  457. }
  458. // get params
  459. Plugin.prototype.getParams = function() {
  460. var _this = this
  461. var formData = new FormData(_this.$form[0])
  462. /* unfortunaly not working in safari and some IEs - https://developer.mozilla.org/en-US/docs/Web/API/FormData
  463. if (!formData.has('title')) {
  464. formData.append('title', this.options.messageTitle)
  465. }
  466. */
  467. if (!_this.$form.find('[name=title]').val()) {
  468. formData.append('title', this.options.messageTitle)
  469. }
  470. if (this.options.test) {
  471. formData.append('test', true)
  472. }
  473. formData.append('token', this._config.token)
  474. formData.append('fingerprint', this.fingerprint())
  475. _this.log('debug', 'formData', formData)
  476. return formData
  477. }
  478. Plugin.prototype.closeModal = function() {
  479. if (this.$modal) {
  480. this.$modal.remove()
  481. }
  482. }
  483. // render form
  484. Plugin.prototype.render = function(e) {
  485. var _this = this
  486. _this.closeModal()
  487. _this.modalOpenTime = new Date()
  488. _this.log('debug', 'modalOpenTime:', _this.modalOpenTime)
  489. var element = "<div class=\"" + _this.options.prefixCSS + "modal\">\
  490. <div class=\"" + _this.options.prefixCSS + "modal-backdrop js-zammad-form-modal-backdrop\"></div>\
  491. <div class=\"" + _this.options.prefixCSS + "modal-body js-zammad-form-modal-body\">\
  492. <form class=\"zammad-form\"></form>\
  493. </div>\
  494. </div>"
  495. if (!this.options.modal) {
  496. element = '<div><form class="zammad-form"></form></div>'
  497. }
  498. var $element = $(element)
  499. var $form = $element.find('form')
  500. if (this.options.showTitle && this.options.messageTitle != '') {
  501. $form.append('<h2>' + this.options.messageTitle + '</h2>')
  502. }
  503. $.each(this.options.attributes, function(index, value) {
  504. var valueId = _this.options.modal ? value.id + '-modal' : value.id + '-inline'
  505. var item
  506. if (value.type == 'checkbox'){
  507. item = $('<div class="form-group '+ _this.options.prefixCSS +'group"></div>');
  508. } else {
  509. // Deprecated class "form-group" can be removed in future versions.
  510. item = $('<div class="form-group '+ _this.options.prefixCSS +'group"><label for="' + valueId +'"> ' + _this.T(value.display) + '</label></div>');
  511. }
  512. var defaultValue = (typeof value.defaultValue === 'function') ? value.defaultValue() : value.defaultValue;
  513. for (var i=0; i < (value.repeat ? value.repeat : 1); i++) {
  514. if (value.tag === 'input') {
  515. if (value.type === 'checkbox'){
  516. var label = $('<label for="' + valueId + '"><input type="' + value.type + '" name="' + value.name + '" id="' + valueId + '" class="' + _this.options.prefixCSS + 'checkbox" ' + (value.required === true ? ' required' : '') + '>' + _this.T(value.display) + '</label>')
  517. item.append(label)
  518. } else {
  519. // Deprecated class "form-control" can be removed in future versions.
  520. item.append('<input class="form-control '+ _this.options.prefixCSS +'control" id="' + valueId + '" name="' + value.name + '" type="' + value.type + '" placeholder="' + _this.T(value.placeholder) + '" value="' + (defaultValue || '') + '"' + (value.required === true ? ' required' : '') + '>')
  521. }
  522. }
  523. else if (value.tag == 'textarea') {
  524. // Deprecated class "form-control" can be removed in future versions.
  525. item.append('<textarea class="form-control '+ _this.options.prefixCSS +'control" id="' + valueId + '" name="' + value.name + '" placeholder="' + _this.T(value.placeholder) + '" rows="' + value.rows + '"' + (value.required === true ? ' required' : '') + '>' + (defaultValue || '') + '</textarea>')
  526. }
  527. }
  528. $form.append(item)
  529. })
  530. $form.append('<button type="submit" class="btn">' + this.options.messageSubmit + '</button')
  531. this.$modal = $element
  532. this.$form = $form
  533. // bind on close
  534. $element.find('.js-zammad-form-modal-backdrop').off('click.zammad-form').on('click.zammad-form', function (e) {
  535. e.preventDefault()
  536. _this.closeModal()
  537. return true
  538. })
  539. // bind form submit
  540. $element.off('submit.zammad-form').on('submit.zammad-form', function (e) {
  541. e.preventDefault()
  542. _this.submit()
  543. return true
  544. })
  545. // show form
  546. if (!this.options.modal) {
  547. _this.$element.html($element)
  548. }
  549. // append modal to body
  550. else {
  551. $('body').append($element)
  552. }
  553. }
  554. // thanks
  555. Plugin.prototype.thanks = function(data) {
  556. var thankYou = this.options.messageThankYou
  557. if (data.ticket && data.ticket.number) {
  558. thankYou = thankYou.replace('%s', data.ticket.number)
  559. }
  560. var message = $('<div class="js-thankyou zammad-form-thankyou">' + thankYou + '</div>')
  561. this.$form.html(message)
  562. }
  563. // unable to load config
  564. Plugin.prototype.noConfig = function(e) {
  565. var message = $('<div class="js-noConfig">' + this.options.messageNoConfig + '</div>')
  566. if (this.$form) {
  567. this.$form.html(message)
  568. }
  569. this.$element.html(message)
  570. }
  571. // log method
  572. Plugin.prototype.log = function() {
  573. var args = Array.prototype.slice.call(arguments)
  574. var level = args.shift()
  575. if (!this.options.debug && level == 'debug') {
  576. return
  577. }
  578. args.unshift(this._name + '||' + level)
  579. console.log.apply(console, args)
  580. var logString = ''
  581. $.each( args, function(index, item) {
  582. logString = logString + ' '
  583. if (typeof item == 'object') {
  584. logString = logString + JSON.stringify(item)
  585. }
  586. else if (item && item.toString) {
  587. logString = logString + item.toString()
  588. }
  589. else {
  590. logString = logString + item
  591. }
  592. })
  593. $('.js-logDisplay').prepend('<div>' + logString + '</div>')
  594. }
  595. // translation method
  596. Plugin.prototype.T = function() {
  597. var string = arguments[0]
  598. var items = 2 <= arguments.length ? slice.call(arguments, 1) : []
  599. if (this.options.lang && this.options.lang !== 'en') {
  600. if (!this.options.translations[this.options.lang]) {
  601. this.log('debug', "Translation '" + this.options.lang + "' needed!")
  602. }
  603. else {
  604. translations = this.options.translations[this.options.lang]
  605. if (!translations[string]) {
  606. this.log('debug', "Translation needed for '" + this.options.lang + "' " + string + "'")
  607. }
  608. string = translations[string] || string
  609. }
  610. }
  611. if (items) {
  612. for (i = 0, len = items.length; i < len; i++) {
  613. item = items[i]
  614. string = string.replace(/%s/, item)
  615. }
  616. }
  617. return string
  618. }
  619. Plugin.prototype.fingerprint = function () {
  620. var canvas = document.createElement('canvas')
  621. var ctx = canvas.getContext('2d')
  622. var txt = 'https://zammad.com'
  623. ctx.textBaseline = 'top'
  624. ctx.font = '12px \'Arial\''
  625. ctx.textBaseline = 'alphabetic'
  626. ctx.fillStyle = '#f60'
  627. ctx.fillRect(125,1,62,20)
  628. ctx.fillStyle = '#069'
  629. ctx.fillText(txt, 2, 15)
  630. ctx.fillStyle = 'rgba(100, 200, 0, 0.7)'
  631. ctx.fillText(txt, 4, 17)
  632. return canvas.toDataURL()
  633. }
  634. $.fn[pluginName] = function (options) {
  635. return this.each(function () {
  636. var instance = $.data(this, 'plugin_' + pluginName)
  637. if (instance) {
  638. instance.$element.empty()
  639. $.data(this, 'plugin_' + pluginName, undefined)
  640. }
  641. $.data(
  642. this, 'plugin_' + pluginName,
  643. new Plugin(this, options)
  644. );
  645. });
  646. }
  647. }(jQuery));