config.js 24 KB

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