config.js 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776
  1. /* vim: set expandtab sw=4 ts=4 sts=4: */
  2. /**
  3. * Functions used in configuration forms and on user preferences pages
  4. */
  5. /**
  6. * Unbind all event handlers before tearing down a page
  7. */
  8. AJAX.registerTeardown('config.js', function() {
  9. $('input[id], select[id], textarea[id]').unbind('change').unbind('keyup');
  10. $('input[type=button][name=submit_reset]').unbind('click');
  11. $('div.tabs_contents').undelegate();
  12. $('#import_local_storage, #export_local_storage').unbind('click');
  13. $('form.prefs-form').unbind('change').unbind('submit');
  14. $('div.click-hide-message').die('click');
  15. $('#prefs_autoload').find('a').unbind('click');
  16. });
  17. AJAX.registerOnload('config.js', function() {
  18. $('#topmenu2').find('li.active a').attr('rel', 'samepage');
  19. $('#topmenu2').find('li:not(.active) a').attr('rel', 'newpage');
  20. });
  21. // default values for fields
  22. var defaultValues = {};
  23. /**
  24. * Returns field type
  25. *
  26. * @param {Element} field
  27. */
  28. function getFieldType(field)
  29. {
  30. field = $(field);
  31. var tagName = field.prop('tagName');
  32. if (tagName == 'INPUT') {
  33. return field.attr('type');
  34. } else if (tagName == 'SELECT') {
  35. return 'select';
  36. } else if (tagName == 'TEXTAREA') {
  37. return 'text';
  38. }
  39. return '';
  40. }
  41. /**
  42. * Sets field value
  43. *
  44. * value must be of type:
  45. * o undefined (omitted) - restore default value (form default, not PMA default)
  46. * o String - if field_type is 'text'
  47. * o boolean - if field_type is 'checkbox'
  48. * o Array of values - if field_type is 'select'
  49. *
  50. * @param {Element} field
  51. * @param {String} field_type see {@link #getFieldType}
  52. * @param {String|Boolean} [value]
  53. */
  54. function setFieldValue(field, field_type, value)
  55. {
  56. field = $(field);
  57. switch (field_type) {
  58. case 'text':
  59. //TODO: replace to .val()
  60. field.attr('value', (value != undefined ? value : field.attr('defaultValue')));
  61. break;
  62. case 'checkbox':
  63. //TODO: replace to .prop()
  64. field.attr('checked', (value != undefined ? value : field.attr('defaultChecked')));
  65. break;
  66. case 'select':
  67. var options = field.prop('options');
  68. var i, imax = options.length;
  69. if (value == undefined) {
  70. for (i = 0; i < imax; i++) {
  71. options[i].selected = options[i].defaultSelected;
  72. }
  73. } else {
  74. for (i = 0; i < imax; i++) {
  75. options[i].selected = (value.indexOf(options[i].value) != -1);
  76. }
  77. }
  78. break;
  79. }
  80. markField(field);
  81. }
  82. /**
  83. * Gets field value
  84. *
  85. * Will return one of:
  86. * o String - if type is 'text'
  87. * o boolean - if type is 'checkbox'
  88. * o Array of values - if type is 'select'
  89. *
  90. * @param {Element} field
  91. * @param {String} field_type returned by {@link #getFieldType}
  92. * @type Boolean|String|String[]
  93. */
  94. function getFieldValue(field, field_type)
  95. {
  96. field = $(field);
  97. switch (field_type) {
  98. case 'text':
  99. return field.prop('value');
  100. case 'checkbox':
  101. return field.prop('checked');
  102. case 'select':
  103. var options = field.prop('options');
  104. var i, imax = options.length, items = [];
  105. for (i = 0; i < imax; i++) {
  106. if (options[i].selected) {
  107. items.push(options[i].value);
  108. }
  109. }
  110. return items;
  111. }
  112. return null;
  113. }
  114. /**
  115. * Returns values for all fields in fieldsets
  116. */
  117. function getAllValues()
  118. {
  119. var elements = $('fieldset input, fieldset select, fieldset textarea');
  120. var values = {};
  121. var type, value;
  122. for (var i = 0; i < elements.length; i++) {
  123. type = getFieldType(elements[i]);
  124. value = getFieldValue(elements[i], type);
  125. if (typeof value != 'undefined') {
  126. // we only have single selects, fatten array
  127. if (type == 'select') {
  128. value = value[0];
  129. }
  130. values[elements[i].name] = value;
  131. }
  132. }
  133. return values;
  134. }
  135. /**
  136. * Checks whether field has its default value
  137. *
  138. * @param {Element} field
  139. * @param {String} type
  140. * @return boolean
  141. */
  142. function checkFieldDefault(field, type)
  143. {
  144. field = $(field);
  145. var field_id = field.attr('id');
  146. if (typeof defaultValues[field_id] == 'undefined') {
  147. return true;
  148. }
  149. var isDefault = true;
  150. var currentValue = getFieldValue(field, type);
  151. if (type != 'select') {
  152. isDefault = currentValue == defaultValues[field_id];
  153. } else {
  154. // compare arrays, will work for our representation of select values
  155. if (currentValue.length != defaultValues[field_id].length) {
  156. isDefault = false;
  157. }
  158. else {
  159. for (var i = 0; i < currentValue.length; i++) {
  160. if (currentValue[i] != defaultValues[field_id][i]) {
  161. isDefault = false;
  162. break;
  163. }
  164. }
  165. }
  166. }
  167. return isDefault;
  168. }
  169. /**
  170. * Returns element's id prefix
  171. * @param {Element} element
  172. */
  173. function getIdPrefix(element)
  174. {
  175. return $(element).attr('id').replace(/[^-]+$/, '');
  176. }
  177. // ------------------------------------------------------------------
  178. // Form validation and field operations
  179. //
  180. // form validator assignments
  181. var validate = {};
  182. // form validator list
  183. var validators = {
  184. // regexp: numeric value
  185. _regexp_numeric: /^[0-9]+$/,
  186. // regexp: extract parts from PCRE expression
  187. _regexp_pcre_extract: /(.)(.*)\1(.*)?/,
  188. /**
  189. * Validates positive number
  190. *
  191. * @param {boolean} isKeyUp
  192. */
  193. validate_positive_number: function (isKeyUp) {
  194. if (isKeyUp && this.value == '') {
  195. return true;
  196. }
  197. var result = this.value != '0' && validators._regexp_numeric.test(this.value);
  198. return result ? true : PMA_messages['error_nan_p'];
  199. },
  200. /**
  201. * Validates non-negative number
  202. *
  203. * @param {boolean} isKeyUp
  204. */
  205. validate_non_negative_number: function (isKeyUp) {
  206. if (isKeyUp && this.value == '') {
  207. return true;
  208. }
  209. var result = validators._regexp_numeric.test(this.value);
  210. return result ? true : PMA_messages['error_nan_nneg'];
  211. },
  212. /**
  213. * Validates port number
  214. *
  215. * @param {boolean} isKeyUp
  216. */
  217. validate_port_number: function(isKeyUp) {
  218. if (this.value == '') {
  219. return true;
  220. }
  221. var result = validators._regexp_numeric.test(this.value) && this.value != '0';
  222. return result && this.value <= 65535 ? true : PMA_messages['error_incorrect_port'];
  223. },
  224. /**
  225. * Validates value according to given regular expression
  226. *
  227. * @param {boolean} isKeyUp
  228. * @param {string} regexp
  229. */
  230. validate_by_regex: function(isKeyUp, regexp) {
  231. if (isKeyUp && this.value == '') {
  232. return true;
  233. }
  234. // convert PCRE regexp
  235. var parts = regexp.match(validators._regexp_pcre_extract);
  236. var valid = this.value.match(new RegExp(parts[2], parts[3])) != null;
  237. return valid ? true : PMA_messages['error_invalid_value'];
  238. },
  239. /**
  240. * Validates upper bound for numeric inputs
  241. *
  242. * @param {boolean} isKeyUp
  243. * @param {int} max_value
  244. */
  245. validate_upper_bound: function(isKeyUp, max_value) {
  246. var val = parseInt(this.value);
  247. if (isNaN(val)) {
  248. return true;
  249. }
  250. return val <= max_value ? true : $.sprintf(PMA_messages['error_value_lte'], max_value);
  251. },
  252. // field validators
  253. _field: {
  254. },
  255. // fieldset validators
  256. _fieldset: {
  257. }
  258. };
  259. /**
  260. * Registers validator for given field
  261. *
  262. * @param {String} id field id
  263. * @param {String} type validator (key in validators object)
  264. * @param {boolean} onKeyUp whether fire on key up
  265. * @param {Array} params validation function parameters
  266. */
  267. function validateField(id, type, onKeyUp, params)
  268. {
  269. if (typeof validators[type] == 'undefined') {
  270. return;
  271. }
  272. if (typeof validate[id] == 'undefined') {
  273. validate[id] = [];
  274. }
  275. validate[id].push([type, params, onKeyUp]);
  276. }
  277. /**
  278. * Returns valdiation functions associated with form field
  279. *
  280. * @param {String} field_id form field id
  281. * @param {boolean} onKeyUpOnly see validateField
  282. * @type Array
  283. * @return array of [function, paramseters to be passed to function]
  284. */
  285. function getFieldValidators(field_id, onKeyUpOnly)
  286. {
  287. // look for field bound validator
  288. var name = field_id.match(/[^-]+$/)[0];
  289. if (typeof validators._field[name] != 'undefined') {
  290. return [[validators._field[name], null]];
  291. }
  292. // look for registered validators
  293. var functions = [];
  294. if (typeof validate[field_id] != 'undefined') {
  295. // validate[field_id]: array of [type, params, onKeyUp]
  296. for (var i = 0, imax = validate[field_id].length; i < imax; i++) {
  297. if (onKeyUpOnly && !validate[field_id][i][2]) {
  298. continue;
  299. }
  300. functions.push([validators[validate[field_id][i][0]], validate[field_id][i][1]]);
  301. }
  302. }
  303. return functions;
  304. }
  305. /**
  306. * Displays errors for given form fields
  307. *
  308. * WARNING: created DOM elements must be identical with the ones made by
  309. * display_input() in FormDisplay.tpl.php!
  310. *
  311. * @param {Object} error_list list of errors in the form {field id: error array}
  312. */
  313. function displayErrors(error_list)
  314. {
  315. for (var field_id in error_list) {
  316. var errors = error_list[field_id];
  317. var field = $('#'+field_id);
  318. var isFieldset = field.attr('tagName') == 'FIELDSET';
  319. var errorCnt = isFieldset
  320. ? field.find('dl.errors')
  321. : field.siblings('.inline_errors');
  322. // remove empty errors (used to clear error list)
  323. errors = $.grep(errors, function(item) {
  324. return item != '';
  325. });
  326. // CSS error class
  327. if (!isFieldset) {
  328. // checkboxes uses parent <span> for marking
  329. var fieldMarker = (field.attr('type') == 'checkbox') ? field.parent() : field;
  330. fieldMarker[errors.length ? 'addClass' : 'removeClass']('field-error');
  331. }
  332. if (errors.length) {
  333. // if error container doesn't exist, create it
  334. if (errorCnt.length == 0) {
  335. if (isFieldset) {
  336. errorCnt = $('<dl class="errors" />');
  337. field.find('table').before(errorCnt);
  338. } else {
  339. errorCnt = $('<dl class="inline_errors" />');
  340. field.closest('td').append(errorCnt);
  341. }
  342. }
  343. var html = '';
  344. for (var i = 0, imax = errors.length; i < imax; i++) {
  345. html += '<dd>' + errors[i] + '</dd>';
  346. }
  347. errorCnt.html(html);
  348. } else if (errorCnt !== null) {
  349. // remove useless error container
  350. errorCnt.remove();
  351. }
  352. }
  353. }
  354. /**
  355. * Validates fieldset and puts errors in 'errors' object
  356. *
  357. * @param {Element} fieldset
  358. * @param {boolean} isKeyUp
  359. * @param {Object} errors
  360. */
  361. function validate_fieldset(fieldset, isKeyUp, errors)
  362. {
  363. fieldset = $(fieldset);
  364. if (fieldset.length && typeof validators._fieldset[fieldset.attr('id')] != 'undefined') {
  365. var fieldset_errors = validators._fieldset[fieldset.attr('id')].apply(fieldset[0], [isKeyUp]);
  366. for (var field_id in fieldset_errors) {
  367. if (typeof errors[field_id] == 'undefined') {
  368. errors[field_id] = [];
  369. }
  370. if (typeof fieldset_errors[field_id] == 'string') {
  371. fieldset_errors[field_id] = [fieldset_errors[field_id]];
  372. }
  373. $.merge(errors[field_id], fieldset_errors[field_id]);
  374. }
  375. }
  376. }
  377. /**
  378. * Validates form field and puts errors in 'errors' object
  379. *
  380. * @param {Element} field
  381. * @param {boolean} isKeyUp
  382. * @param {Object} errors
  383. */
  384. function validate_field(field, isKeyUp, errors)
  385. {
  386. field = $(field);
  387. var field_id = field.attr('id');
  388. errors[field_id] = [];
  389. var functions = getFieldValidators(field_id, isKeyUp);
  390. for (var i = 0; i < functions.length; i++) {
  391. var args = functions[i][1] != null
  392. ? functions[i][1].slice(0)
  393. : [];
  394. args.unshift(isKeyUp);
  395. var result = functions[i][0].apply(field[0], args);
  396. if (result !== true) {
  397. if (typeof result == 'string') {
  398. result = [result];
  399. }
  400. $.merge(errors[field_id], result);
  401. }
  402. }
  403. }
  404. /**
  405. * Validates form field and parent fieldset
  406. *
  407. * @param {Element} field
  408. * @param {boolean} isKeyUp
  409. */
  410. function validate_field_and_fieldset(field, isKeyUp)
  411. {
  412. field = $(field);
  413. var errors = {};
  414. validate_field(field, isKeyUp, errors);
  415. validate_fieldset(field.closest('fieldset'), isKeyUp, errors);
  416. displayErrors(errors);
  417. }
  418. /**
  419. * Marks field depending on its value (system default or custom)
  420. *
  421. * @param {Element} field
  422. */
  423. function markField(field)
  424. {
  425. field = $(field);
  426. var type = getFieldType(field);
  427. var isDefault = checkFieldDefault(field, type);
  428. // checkboxes uses parent <span> for marking
  429. var fieldMarker = (type == 'checkbox') ? field.parent() : field;
  430. setRestoreDefaultBtn(field, !isDefault);
  431. fieldMarker[isDefault ? 'removeClass' : 'addClass']('custom');
  432. }
  433. /**
  434. * Enables or disables the "restore default value" button
  435. *
  436. * @param {Element} field
  437. * @param {boolean} display
  438. */
  439. function setRestoreDefaultBtn(field, display)
  440. {
  441. var el = $(field).closest('td').find('.restore-default img');
  442. el[display ? 'show' : 'hide']();
  443. }
  444. AJAX.registerOnload('config.js', function() {
  445. // register validators and mark custom values
  446. var elements = $('input[id], select[id], textarea[id]');
  447. $('input[id], select[id], textarea[id]').each(function(){
  448. markField(this);
  449. var el = $(this);
  450. el.bind('change', function() {
  451. validate_field_and_fieldset(this, false);
  452. markField(this);
  453. });
  454. var tagName = el.attr('tagName');
  455. // text fields can be validated after each change
  456. if (tagName == 'INPUT' && el.attr('type') == 'text') {
  457. el.keyup(function() {
  458. validate_field_and_fieldset(el, true);
  459. markField(el);
  460. });
  461. }
  462. // disable textarea spellcheck
  463. if (tagName == 'TEXTAREA') {
  464. el.attr('spellcheck', false);
  465. }
  466. });
  467. // check whether we've refreshed a page and browser remembered modified
  468. // form values
  469. var check_page_refresh = $('#check_page_refresh');
  470. if (check_page_refresh.length == 0 || check_page_refresh.val() == '1') {
  471. // run all field validators
  472. var errors = {};
  473. for (var i = 0; i < elements.length; i++) {
  474. validate_field(elements[i], false, errors);
  475. }
  476. // run all fieldset validators
  477. $('fieldset').each(function(){
  478. validate_fieldset(this, false, errors);
  479. });
  480. displayErrors(errors);
  481. } else if (check_page_refresh) {
  482. check_page_refresh.val('1');
  483. }
  484. });
  485. //
  486. // END: Form validation and field operations
  487. // ------------------------------------------------------------------
  488. // ------------------------------------------------------------------
  489. // Tabbed forms
  490. //
  491. /**
  492. * Sets active tab
  493. *
  494. * @param {String} tab_id
  495. */
  496. function setTab(tab_id)
  497. {
  498. $('ul.tabs li').removeClass('active').find('a[href=#' + tab_id + ']').parent().addClass('active');
  499. $('div.tabs_contents fieldset').hide().filter('#' + tab_id).show();
  500. location.hash = 'tab_' + tab_id;
  501. $('form.config-form input[name=tab_hash]').val(location.hash);
  502. }
  503. AJAX.registerOnload('config.js', function() {
  504. var tabs = $('ul.tabs');
  505. if (!tabs.length) {
  506. return;
  507. }
  508. // add tabs events and activate one tab (the first one or indicated by location hash)
  509. tabs.find('a')
  510. .click(function(e) {
  511. e.preventDefault();
  512. setTab($(this).attr('href').substr(1));
  513. })
  514. .filter(':first')
  515. .parent()
  516. .addClass('active');
  517. $('div.tabs_contents fieldset').hide().filter(':first').show();
  518. // tab links handling, check each 200ms
  519. // (works with history in FF, further browser support here would be an overkill)
  520. var prev_hash;
  521. var tab_check_fnc = function() {
  522. if (location.hash != prev_hash) {
  523. prev_hash = location.hash;
  524. if (prev_hash.match(/^#tab_[a-zA-Z0-9_]+$/) && $('#' + prev_hash.substr(5)).length) {
  525. setTab(prev_hash.substr(5));
  526. }
  527. }
  528. };
  529. tab_check_fnc();
  530. setInterval(tab_check_fnc, 200);
  531. });
  532. //
  533. // END: Tabbed forms
  534. // ------------------------------------------------------------------
  535. // ------------------------------------------------------------------
  536. // Form reset buttons
  537. //
  538. AJAX.registerOnload('config.js', function() {
  539. $('input[type=button][name=submit_reset]').click(function() {
  540. var fields = $(this).closest('fieldset').find('input, select, textarea');
  541. for (var i = 0, imax = fields.length; i < imax; i++) {
  542. setFieldValue(fields[i], getFieldType(fields[i]));
  543. }
  544. });
  545. });
  546. //
  547. // END: Form reset buttons
  548. // ------------------------------------------------------------------
  549. // ------------------------------------------------------------------
  550. // "Restore default" and "set value" buttons
  551. //
  552. /**
  553. * Restores field's default value
  554. *
  555. * @param {String} field_id
  556. */
  557. function restoreField(field_id)
  558. {
  559. var field = $('#'+field_id);
  560. if (field.length == 0 || defaultValues[field_id] == undefined) {
  561. return;
  562. }
  563. setFieldValue(field, getFieldType(field), defaultValues[field_id]);
  564. }
  565. AJAX.registerOnload('config.js', function() {
  566. $('div.tabs_contents')
  567. .delegate('.restore-default, .set-value', 'mouseenter', function(){$(this).css('opacity', 1)})
  568. .delegate('.restore-default, .set-value', 'mouseleave', function(){$(this).css('opacity', 0.25)})
  569. .delegate('.restore-default, .set-value', 'click', function(e) {
  570. e.preventDefault();
  571. var href = $(this).attr('href');
  572. var field_sel;
  573. if ($(this).hasClass('restore-default')) {
  574. field_sel = href;
  575. restoreField(field_sel.substr(1));
  576. } else {
  577. field_sel = href.match(/^[^=]+/)[0];
  578. var value = href.match(/=(.+)$/)[1];
  579. setFieldValue($(field_sel), 'text', value);
  580. }
  581. $(field_sel).trigger('change');
  582. })
  583. .find('.restore-default, .set-value')
  584. // inline-block for IE so opacity inheritance works
  585. .css({display: 'inline-block', opacity: 0.25});
  586. });
  587. //
  588. // END: "Restore default" and "set value" buttons
  589. // ------------------------------------------------------------------
  590. // ------------------------------------------------------------------
  591. // User preferences import/export
  592. //
  593. AJAX.registerOnload('config.js', function() {
  594. offerPrefsAutoimport();
  595. var radios = $('#import_local_storage, #export_local_storage');
  596. if (!radios.length) {
  597. return;
  598. }
  599. // enable JavaScript dependent fields
  600. radios
  601. .prop('disabled', false)
  602. .add('#export_text_file, #import_text_file')
  603. .click(function(){
  604. var enable_id = $(this).attr('id');
  605. var disable_id = enable_id.match(/local_storage$/)
  606. ? enable_id.replace(/local_storage$/, 'text_file')
  607. : enable_id.replace(/text_file$/, 'local_storage');
  608. $('#opts_'+disable_id).addClass('disabled').find('input').prop('disabled', true);
  609. $('#opts_'+enable_id).removeClass('disabled').find('input').prop('disabled', false);
  610. });
  611. // detect localStorage state
  612. var ls_supported = window.localStorage || false;
  613. var ls_exists = ls_supported ? (window.localStorage['config'] || false) : false;
  614. $('div.localStorage-'+(ls_supported ? 'un' : '')+'supported').hide();
  615. $('div.localStorage-'+(ls_exists ? 'empty' : 'exists')).hide();
  616. if (ls_exists) {
  617. updatePrefsDate();
  618. }
  619. $('form.prefs-form').change(function(){
  620. var form = $(this);
  621. var disabled = false;
  622. if (!ls_supported) {
  623. disabled = form.find('input[type=radio][value$=local_storage]').prop('checked');
  624. } else if (!ls_exists && form.attr('name') == 'prefs_import'
  625. && $('#import_local_storage')[0].checked) {
  626. disabled = true;
  627. }
  628. form.find('input[type=submit]').prop('disabled', disabled);
  629. }).submit(function(e) {
  630. var form = $(this);
  631. if (form.attr('name') == 'prefs_export' && $('#export_local_storage')[0].checked) {
  632. e.preventDefault();
  633. // use AJAX to read JSON settings and save them
  634. savePrefsToLocalStorage(form);
  635. } else if (form.attr('name') == 'prefs_import' && $('#import_local_storage')[0].checked) {
  636. // set 'json' input and submit form
  637. form.find('input[name=json]').val(window.localStorage['config']);
  638. }
  639. });
  640. $('div.click-hide-message').live('click', function(){
  641. $(this)
  642. .hide()
  643. .parent('.group')
  644. .css('height', '')
  645. .next('form')
  646. .show();
  647. });
  648. });
  649. /**
  650. * Saves user preferences to localStorage
  651. *
  652. * @param {Element} form
  653. */
  654. function savePrefsToLocalStorage(form)
  655. {
  656. form = $(form);
  657. var submit = form.find('input[type=submit]');
  658. submit.prop('disabled', true);
  659. $.ajax({
  660. url: 'prefs_manage.php',
  661. cache: false,
  662. type: 'POST',
  663. data: {
  664. ajax_request: true,
  665. token: form.find('input[name=token]').val(),
  666. submit_get_json: true
  667. },
  668. success: function(response) {
  669. window.localStorage['config'] = response.prefs;
  670. window.localStorage['config_mtime'] = response.mtime;
  671. window.localStorage['config_mtime_local'] = (new Date()).toUTCString();
  672. updatePrefsDate();
  673. $('div.localStorage-empty').hide();
  674. $('div.localStorage-exists').show();
  675. var group = form.parent('.group');
  676. group.css('height', group.height() + 'px');
  677. form.hide('fast');
  678. form.prev('.click-hide-message').show('fast');
  679. },
  680. complete: function() {
  681. submit.prop('disabled', false);
  682. }
  683. });
  684. }
  685. /**
  686. * Updates preferences timestamp in Import form
  687. */
  688. function updatePrefsDate()
  689. {
  690. var d = new Date(window.localStorage['config_mtime_local']);
  691. var msg = PMA_messages.strSavedOn.replace(
  692. '@DATE@',
  693. PMA_formatDateTime(d)
  694. );
  695. $('#opts_import_local_storage div.localStorage-exists').html(msg);
  696. }
  697. /**
  698. * Prepares message which informs that localStorage preferences are available and can be imported
  699. */
  700. function offerPrefsAutoimport()
  701. {
  702. var has_config = (window.localStorage || false) && (window.localStorage['config'] || false);
  703. var cnt = $('#prefs_autoload');
  704. if (!cnt.length || !has_config) {
  705. return;
  706. }
  707. cnt.find('a').click(function(e) {
  708. e.preventDefault();
  709. var a = $(this);
  710. if (a.attr('href') == '#no') {
  711. cnt.remove();
  712. $.post('index.php', {
  713. token: cnt.find('input[name=token]').val(),
  714. prefs_autoload: 'hide'});
  715. return;
  716. }
  717. cnt.find('input[name=json]').val(window.localStorage['config']);
  718. cnt.find('form').submit();
  719. });
  720. cnt.show();
  721. }
  722. //
  723. // END: User preferences import/export
  724. // ------------------------------------------------------------------