entries.js 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002
  1. // Copyright 2009 The Closure Library Authors. All Rights Reserved.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS-IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. /**
  15. * @fileoverview Definitions for all tweak entries.
  16. * The class hierarchy is as follows (abstract entries are denoted with a *):
  17. * BaseEntry(id, description) *
  18. * -> ButtonAction(buttons in the UI)
  19. * -> BaseSetting(query parameter) *
  20. * -> BooleanGroup(child booleans)
  21. * -> BasePrimitiveSetting(value, defaultValue) *
  22. * -> BooleanSetting
  23. * -> StringSetting
  24. * -> NumericSetting
  25. * -> BooleanInGroupSetting(token)
  26. * Most clients should not use these classes directly, but instead use the API
  27. * defined in tweak.js. One possible use case for directly using them is to
  28. * register tweaks that are not known at compile time.
  29. *
  30. * @author agrieve@google.com (Andrew Grieve)
  31. */
  32. goog.provide('goog.tweak.BaseEntry');
  33. goog.provide('goog.tweak.BasePrimitiveSetting');
  34. goog.provide('goog.tweak.BaseSetting');
  35. goog.provide('goog.tweak.BooleanGroup');
  36. goog.provide('goog.tweak.BooleanInGroupSetting');
  37. goog.provide('goog.tweak.BooleanSetting');
  38. goog.provide('goog.tweak.ButtonAction');
  39. goog.provide('goog.tweak.NumericSetting');
  40. goog.provide('goog.tweak.StringSetting');
  41. goog.require('goog.array');
  42. goog.require('goog.asserts');
  43. goog.require('goog.log');
  44. goog.require('goog.object');
  45. /**
  46. * Base class for all Registry entries.
  47. * @param {string} id The ID for the entry. Must contain only letters,
  48. * numbers, underscores and periods.
  49. * @param {string} description A description of what the entry does.
  50. * @constructor
  51. */
  52. goog.tweak.BaseEntry = function(id, description) {
  53. /**
  54. * An ID to uniquely identify the entry.
  55. * @type {string}
  56. * @private
  57. */
  58. this.id_ = id;
  59. /**
  60. * A descriptive label for the entry.
  61. * @type {string}
  62. */
  63. this.label = id;
  64. /**
  65. * A description of what this entry does.
  66. * @type {string}
  67. */
  68. this.description = description;
  69. /**
  70. * Functions to be called whenever a setting is changed or a button is
  71. * clicked.
  72. * @type {!Array<!Function>}
  73. * @private
  74. */
  75. this.callbacks_ = [];
  76. };
  77. /**
  78. * The logger for this class.
  79. * @type {goog.log.Logger}
  80. * @protected
  81. */
  82. goog.tweak.BaseEntry.prototype.logger =
  83. goog.log.getLogger('goog.tweak.BaseEntry');
  84. /**
  85. * Whether a restart is required for changes to the setting to take effect.
  86. * @type {boolean}
  87. * @private
  88. */
  89. goog.tweak.BaseEntry.prototype.restartRequired_ = true;
  90. /**
  91. * @return {string} Returns the entry's ID.
  92. */
  93. goog.tweak.BaseEntry.prototype.getId = function() {
  94. return this.id_;
  95. };
  96. /**
  97. * Returns whether a restart is required for changes to the setting to take
  98. * effect.
  99. * @return {boolean} The value.
  100. */
  101. goog.tweak.BaseEntry.prototype.isRestartRequired = function() {
  102. return this.restartRequired_;
  103. };
  104. /**
  105. * Sets whether a restart is required for changes to the setting to take
  106. * effect.
  107. * @param {boolean} value The new value.
  108. */
  109. goog.tweak.BaseEntry.prototype.setRestartRequired = function(value) {
  110. this.restartRequired_ = value;
  111. };
  112. /**
  113. * Adds a callback that should be called when the setting has changed (or when
  114. * an action has been clicked).
  115. * @param {!Function} callback The callback to add.
  116. */
  117. goog.tweak.BaseEntry.prototype.addCallback = function(callback) {
  118. this.callbacks_.push(callback);
  119. };
  120. /**
  121. * Removes a callback that was added by addCallback.
  122. * @param {!Function} callback The callback to add.
  123. */
  124. goog.tweak.BaseEntry.prototype.removeCallback = function(callback) {
  125. goog.array.remove(this.callbacks_, callback);
  126. };
  127. /**
  128. * Calls all registered callbacks.
  129. */
  130. goog.tweak.BaseEntry.prototype.fireCallbacks = function() {
  131. for (var i = 0, callback; callback = this.callbacks_[i]; ++i) {
  132. callback(this);
  133. }
  134. };
  135. /**
  136. * Base class for all tweak entries that are settings. Settings are entries
  137. * that are associated with a query parameter.
  138. * @param {string} id The ID for the setting.
  139. * @param {string} description A description of what the setting does.
  140. * @constructor
  141. * @extends {goog.tweak.BaseEntry}
  142. */
  143. goog.tweak.BaseSetting = function(id, description) {
  144. goog.tweak.BaseEntry.call(this, id, description);
  145. // Apply this restriction for settings since they turn in to query
  146. // parameters. For buttons, it's not really important.
  147. goog.asserts.assert(
  148. !/[^A-Za-z0-9._]/.test(id), 'Tweak id contains illegal characters: ', id);
  149. /**
  150. * The value of this setting's query parameter.
  151. * @type {string|undefined}
  152. * @protected
  153. */
  154. this.initialQueryParamValue;
  155. /**
  156. * The query parameter that controls this setting.
  157. * @type {?string}
  158. * @private
  159. */
  160. this.paramName_ = this.getId().toLowerCase();
  161. };
  162. goog.inherits(goog.tweak.BaseSetting, goog.tweak.BaseEntry);
  163. /**
  164. * States of initialization. Entries are initialized lazily in order to allow
  165. * their initialization to happen in multiple statements.
  166. * @enum {number}
  167. * @private
  168. */
  169. goog.tweak.BaseSetting.InitializeState_ = {
  170. // The start state for all settings.
  171. NOT_INITIALIZED: 0,
  172. // This is used to allow concrete classes to call assertNotInitialized()
  173. // during their initialize() function.
  174. INITIALIZING: 1,
  175. // One a setting is initialized, it may no longer change its configuration
  176. // settings (associated query parameter, token, etc).
  177. INITIALIZED: 2
  178. };
  179. /**
  180. * The logger for this class.
  181. * @type {goog.log.Logger}
  182. * @protected
  183. * @override
  184. */
  185. goog.tweak.BaseSetting.prototype.logger =
  186. goog.log.getLogger('goog.tweak.BaseSetting');
  187. /**
  188. * Whether initialize() has been called (or is in the middle of being called).
  189. * @type {goog.tweak.BaseSetting.InitializeState_}
  190. * @private
  191. */
  192. goog.tweak.BaseSetting.prototype.initializeState_ =
  193. goog.tweak.BaseSetting.InitializeState_.NOT_INITIALIZED;
  194. /**
  195. * Sets the value of the entry based on the value of the query parameter. Once
  196. * this is called, configuration settings (associated query parameter, token,
  197. * etc) may not be changed.
  198. * @param {?string} value The part of the query param for this setting after
  199. * the '='. Null if it is not present.
  200. * @protected
  201. */
  202. goog.tweak.BaseSetting.prototype.initialize = goog.abstractMethod;
  203. /**
  204. * Returns the value to be used in the query parameter for this tweak.
  205. * @return {?string} The encoded value. Null if the value is set to its
  206. * default.
  207. */
  208. goog.tweak.BaseSetting.prototype.getNewValueEncoded = goog.abstractMethod;
  209. /**
  210. * Asserts that this tweak has not been initialized yet.
  211. * @param {string} funcName Function name to use in the assertion message.
  212. * @protected
  213. */
  214. goog.tweak.BaseSetting.prototype.assertNotInitialized = function(funcName) {
  215. goog.asserts.assert(
  216. this.initializeState_ !=
  217. goog.tweak.BaseSetting.InitializeState_.INITIALIZED,
  218. 'Cannot call ' + funcName + ' after the tweak as been initialized.');
  219. };
  220. /**
  221. * Returns whether the setting is currently being initialized.
  222. * @return {boolean} Whether the setting is currently being initialized.
  223. * @protected
  224. */
  225. goog.tweak.BaseSetting.prototype.isInitializing = function() {
  226. return this.initializeState_ ==
  227. goog.tweak.BaseSetting.InitializeState_.INITIALIZING;
  228. };
  229. /**
  230. * Sets the initial query parameter value for this setting. May not be called
  231. * after the setting has been initialized.
  232. * @param {string} value The initial query parameter value for this setting.
  233. */
  234. goog.tweak.BaseSetting.prototype.setInitialQueryParamValue = function(value) {
  235. this.assertNotInitialized('setInitialQueryParamValue');
  236. this.initialQueryParamValue = value;
  237. };
  238. /**
  239. * Returns the name of the query parameter used for this setting.
  240. * @return {?string} The param name. Null if no query parameter is directly
  241. * associated with the setting.
  242. */
  243. goog.tweak.BaseSetting.prototype.getParamName = function() {
  244. return this.paramName_;
  245. };
  246. /**
  247. * Sets the name of the query parameter used for this setting. If null is
  248. * passed the the setting will not appear in the top-level query string.
  249. * @param {?string} value The new value.
  250. */
  251. goog.tweak.BaseSetting.prototype.setParamName = function(value) {
  252. this.assertNotInitialized('setParamName');
  253. this.paramName_ = value;
  254. };
  255. /**
  256. * Applies the default value or query param value if this is the first time
  257. * that the function has been called.
  258. * @protected
  259. */
  260. goog.tweak.BaseSetting.prototype.ensureInitialized = function() {
  261. if (this.initializeState_ ==
  262. goog.tweak.BaseSetting.InitializeState_.NOT_INITIALIZED) {
  263. // Instead of having only initialized / not initialized, there is a
  264. // separate in-between state so that functions that call
  265. // assertNotInitialized() will not fail when called inside of the
  266. // initialize().
  267. this.initializeState_ =
  268. goog.tweak.BaseSetting.InitializeState_.INITIALIZING;
  269. var value = this.initialQueryParamValue == undefined ?
  270. null :
  271. this.initialQueryParamValue;
  272. this.initialize(value);
  273. this.initializeState_ = goog.tweak.BaseSetting.InitializeState_.INITIALIZED;
  274. }
  275. };
  276. /**
  277. * Base class for all settings that wrap primitive values.
  278. * @param {string} id The ID for the setting.
  279. * @param {string} description A description of what the setting does.
  280. * @param {*} defaultValue The default value for this setting.
  281. * @constructor
  282. * @extends {goog.tweak.BaseSetting}
  283. */
  284. goog.tweak.BasePrimitiveSetting = function(id, description, defaultValue) {
  285. goog.tweak.BaseSetting.call(this, id, description);
  286. /**
  287. * The default value of the setting.
  288. * @type {*}
  289. * @private
  290. */
  291. this.defaultValue_ = defaultValue;
  292. /**
  293. * The value of the tweak.
  294. * @type {*}
  295. * @private
  296. */
  297. this.value_;
  298. /**
  299. * The value of the tweak once "Apply Tweaks" is pressed.
  300. * @type {*}
  301. * @private
  302. */
  303. this.newValue_;
  304. };
  305. goog.inherits(goog.tweak.BasePrimitiveSetting, goog.tweak.BaseSetting);
  306. /**
  307. * The logger for this class.
  308. * @type {goog.log.Logger}
  309. * @protected
  310. * @override
  311. */
  312. goog.tweak.BasePrimitiveSetting.prototype.logger =
  313. goog.log.getLogger('goog.tweak.BasePrimitiveSetting');
  314. /**
  315. * Returns the query param encoded representation of the setting's value.
  316. * @return {string} The encoded value.
  317. * @protected
  318. */
  319. goog.tweak.BasePrimitiveSetting.prototype.encodeNewValue = goog.abstractMethod;
  320. /**
  321. * If the setting has the restartRequired option, then returns its initial
  322. * value. Otherwise, returns its current value.
  323. * @return {*} The value.
  324. */
  325. goog.tweak.BasePrimitiveSetting.prototype.getValue = function() {
  326. this.ensureInitialized();
  327. return this.value_;
  328. };
  329. /**
  330. * Returns the value of the setting to use once "Apply Tweaks" is clicked.
  331. * @return {*} The value.
  332. */
  333. goog.tweak.BasePrimitiveSetting.prototype.getNewValue = function() {
  334. this.ensureInitialized();
  335. return this.newValue_;
  336. };
  337. /**
  338. * Sets the value of the setting. If the setting has the restartRequired
  339. * option, then the value will not be changed until the "Apply Tweaks" button
  340. * is clicked. If it does not have the option, the value will be update
  341. * immediately and all registered callbacks will be called.
  342. * @param {*} value The value.
  343. */
  344. goog.tweak.BasePrimitiveSetting.prototype.setValue = function(value) {
  345. this.ensureInitialized();
  346. var changed = this.newValue_ != value;
  347. this.newValue_ = value;
  348. // Don't fire callbacks if we are currently in the initialize() method.
  349. if (this.isInitializing()) {
  350. this.value_ = value;
  351. } else {
  352. if (!this.isRestartRequired()) {
  353. // Update the current value only if the tweak has been marked as not
  354. // needing a restart.
  355. this.value_ = value;
  356. }
  357. if (changed) {
  358. this.fireCallbacks();
  359. }
  360. }
  361. };
  362. /**
  363. * Returns the default value for this setting.
  364. * @return {*} The default value.
  365. */
  366. goog.tweak.BasePrimitiveSetting.prototype.getDefaultValue = function() {
  367. return this.defaultValue_;
  368. };
  369. /**
  370. * Sets the default value for the tweak.
  371. * @param {*} value The new value.
  372. */
  373. goog.tweak.BasePrimitiveSetting.prototype.setDefaultValue = function(value) {
  374. this.assertNotInitialized('setDefaultValue');
  375. this.defaultValue_ = value;
  376. };
  377. /**
  378. * @override
  379. */
  380. goog.tweak.BasePrimitiveSetting.prototype.getNewValueEncoded = function() {
  381. this.ensureInitialized();
  382. return this.newValue_ == this.defaultValue_ ? null : this.encodeNewValue();
  383. };
  384. /**
  385. * A registry setting for string values.
  386. * @param {string} id The ID for the setting.
  387. * @param {string} description A description of what the setting does.
  388. * @constructor
  389. * @extends {goog.tweak.BasePrimitiveSetting}
  390. * @final
  391. */
  392. goog.tweak.StringSetting = function(id, description) {
  393. goog.tweak.BasePrimitiveSetting.call(this, id, description, '');
  394. /**
  395. * Valid values for the setting.
  396. * @type {Array<string>|undefined}
  397. */
  398. this.validValues_;
  399. };
  400. goog.inherits(goog.tweak.StringSetting, goog.tweak.BasePrimitiveSetting);
  401. /**
  402. * The logger for this class.
  403. * @type {goog.log.Logger}
  404. * @protected
  405. * @override
  406. */
  407. goog.tweak.StringSetting.prototype.logger =
  408. goog.log.getLogger('goog.tweak.StringSetting');
  409. /**
  410. * @override
  411. * @return {string} The tweaks's value.
  412. */
  413. goog.tweak.StringSetting.prototype.getValue;
  414. /**
  415. * @override
  416. * @return {string} The tweaks's new value.
  417. */
  418. goog.tweak.StringSetting.prototype.getNewValue;
  419. /**
  420. * @override
  421. * @param {string} value The tweaks's value.
  422. */
  423. goog.tweak.StringSetting.prototype.setValue;
  424. /**
  425. * @override
  426. * @param {string} value The default value.
  427. */
  428. goog.tweak.StringSetting.prototype.setDefaultValue;
  429. /**
  430. * @override
  431. * @return {string} The default value.
  432. */
  433. goog.tweak.StringSetting.prototype.getDefaultValue;
  434. /**
  435. * @override
  436. */
  437. goog.tweak.StringSetting.prototype.encodeNewValue = function() {
  438. return this.getNewValue();
  439. };
  440. /**
  441. * Sets the valid values for the setting.
  442. * @param {Array<string>|undefined} values Valid values.
  443. */
  444. goog.tweak.StringSetting.prototype.setValidValues = function(values) {
  445. this.assertNotInitialized('setValidValues');
  446. this.validValues_ = values;
  447. // Set the default value to the first value in the list if the current
  448. // default value is not within it.
  449. if (values && !goog.array.contains(values, this.getDefaultValue())) {
  450. this.setDefaultValue(values[0]);
  451. }
  452. };
  453. /**
  454. * Returns the valid values for the setting.
  455. * @return {Array<string>|undefined} Valid values.
  456. */
  457. goog.tweak.StringSetting.prototype.getValidValues = function() {
  458. return this.validValues_;
  459. };
  460. /**
  461. * @override
  462. */
  463. goog.tweak.StringSetting.prototype.initialize = function(value) {
  464. if (value == null) {
  465. this.setValue(this.getDefaultValue());
  466. } else {
  467. var validValues = this.validValues_;
  468. if (validValues) {
  469. // Make the query parameter values case-insensitive since users might
  470. // type them by hand. Make the capitalization that is actual used come
  471. // from the list of valid values.
  472. value = value.toLowerCase();
  473. for (var i = 0, il = validValues.length; i < il; ++i) {
  474. if (value == validValues[i].toLowerCase()) {
  475. this.setValue(validValues[i]);
  476. return;
  477. }
  478. }
  479. // Warn if the value is not in the list of allowed values.
  480. goog.log.warning(
  481. this.logger, 'Tweak ' + this.getId() +
  482. ' has value outside of expected range:' + value);
  483. }
  484. this.setValue(value);
  485. }
  486. };
  487. /**
  488. * A registry setting for numeric values.
  489. * @param {string} id The ID for the setting.
  490. * @param {string} description A description of what the setting does.
  491. * @constructor
  492. * @extends {goog.tweak.BasePrimitiveSetting}
  493. * @final
  494. */
  495. goog.tweak.NumericSetting = function(id, description) {
  496. goog.tweak.BasePrimitiveSetting.call(this, id, description, 0);
  497. /**
  498. * Valid values for the setting.
  499. * @type {Array<number>|undefined}
  500. */
  501. this.validValues_;
  502. };
  503. goog.inherits(goog.tweak.NumericSetting, goog.tweak.BasePrimitiveSetting);
  504. /**
  505. * The logger for this class.
  506. * @type {goog.log.Logger}
  507. * @protected
  508. * @override
  509. */
  510. goog.tweak.NumericSetting.prototype.logger =
  511. goog.log.getLogger('goog.tweak.NumericSetting');
  512. /**
  513. * @override
  514. * @return {number} The tweaks's value.
  515. */
  516. goog.tweak.NumericSetting.prototype.getValue;
  517. /**
  518. * @override
  519. * @return {number} The tweaks's new value.
  520. */
  521. goog.tweak.NumericSetting.prototype.getNewValue;
  522. /**
  523. * @override
  524. * @param {number} value The tweaks's value.
  525. */
  526. goog.tweak.NumericSetting.prototype.setValue;
  527. /**
  528. * @override
  529. * @param {number} value The default value.
  530. */
  531. goog.tweak.NumericSetting.prototype.setDefaultValue;
  532. /**
  533. * @override
  534. * @return {number} The default value.
  535. */
  536. goog.tweak.NumericSetting.prototype.getDefaultValue;
  537. /**
  538. * @override
  539. */
  540. goog.tweak.NumericSetting.prototype.encodeNewValue = function() {
  541. return '' + this.getNewValue();
  542. };
  543. /**
  544. * Sets the valid values for the setting.
  545. * @param {Array<number>|undefined} values Valid values.
  546. */
  547. goog.tweak.NumericSetting.prototype.setValidValues = function(values) {
  548. this.assertNotInitialized('setValidValues');
  549. this.validValues_ = values;
  550. // Set the default value to the first value in the list if the current
  551. // default value is not within it.
  552. if (values && !goog.array.contains(values, this.getDefaultValue())) {
  553. this.setDefaultValue(values[0]);
  554. }
  555. };
  556. /**
  557. * Returns the valid values for the setting.
  558. * @return {Array<number>|undefined} Valid values.
  559. */
  560. goog.tweak.NumericSetting.prototype.getValidValues = function() {
  561. return this.validValues_;
  562. };
  563. /**
  564. * @override
  565. */
  566. goog.tweak.NumericSetting.prototype.initialize = function(value) {
  567. if (value == null) {
  568. this.setValue(this.getDefaultValue());
  569. } else {
  570. var coercedValue = +value;
  571. // Warn if the value is not in the list of allowed values.
  572. if (this.validValues_ &&
  573. !goog.array.contains(this.validValues_, coercedValue)) {
  574. goog.log.warning(
  575. this.logger, 'Tweak ' + this.getId() +
  576. ' has value outside of expected range: ' + value);
  577. }
  578. if (isNaN(coercedValue)) {
  579. goog.log.warning(
  580. this.logger, 'Tweak ' + this.getId() +
  581. ' has value of NaN, resetting to ' + this.getDefaultValue());
  582. this.setValue(this.getDefaultValue());
  583. } else {
  584. this.setValue(coercedValue);
  585. }
  586. }
  587. };
  588. /**
  589. * A registry setting that can be either true of false.
  590. * @param {string} id The ID for the setting.
  591. * @param {string} description A description of what the setting does.
  592. * @constructor
  593. * @extends {goog.tweak.BasePrimitiveSetting}
  594. */
  595. goog.tweak.BooleanSetting = function(id, description) {
  596. goog.tweak.BasePrimitiveSetting.call(this, id, description, false);
  597. };
  598. goog.inherits(goog.tweak.BooleanSetting, goog.tweak.BasePrimitiveSetting);
  599. /**
  600. * The logger for this class.
  601. * @type {goog.log.Logger}
  602. * @protected
  603. * @override
  604. */
  605. goog.tweak.BooleanSetting.prototype.logger =
  606. goog.log.getLogger('goog.tweak.BooleanSetting');
  607. /**
  608. * @override
  609. * @return {boolean} The tweaks's value.
  610. */
  611. goog.tweak.BooleanSetting.prototype.getValue;
  612. /**
  613. * @override
  614. * @return {boolean} The tweaks's new value.
  615. */
  616. goog.tweak.BooleanSetting.prototype.getNewValue;
  617. /**
  618. * @override
  619. * @param {boolean} value The tweaks's value.
  620. */
  621. goog.tweak.BooleanSetting.prototype.setValue;
  622. /**
  623. * @override
  624. * @param {boolean} value The default value.
  625. */
  626. goog.tweak.BooleanSetting.prototype.setDefaultValue;
  627. /**
  628. * @override
  629. * @return {boolean} The default value.
  630. */
  631. goog.tweak.BooleanSetting.prototype.getDefaultValue;
  632. /**
  633. * @override
  634. */
  635. goog.tweak.BooleanSetting.prototype.encodeNewValue = function() {
  636. return this.getNewValue() ? '1' : '0';
  637. };
  638. /**
  639. * @override
  640. */
  641. goog.tweak.BooleanSetting.prototype.initialize = function(value) {
  642. if (value == null) {
  643. this.setValue(this.getDefaultValue());
  644. } else {
  645. value = value.toLowerCase();
  646. this.setValue(value == 'true' || value == '1');
  647. }
  648. };
  649. /**
  650. * An entry in a BooleanGroup.
  651. * @param {string} id The ID for the setting.
  652. * @param {string} description A description of what the setting does.
  653. * @param {!goog.tweak.BooleanGroup} group The group that this entry belongs
  654. * to.
  655. * @constructor
  656. * @extends {goog.tweak.BooleanSetting}
  657. * @final
  658. */
  659. goog.tweak.BooleanInGroupSetting = function(id, description, group) {
  660. goog.tweak.BooleanSetting.call(this, id, description);
  661. /**
  662. * The token to use in the query parameter.
  663. * @type {string}
  664. * @private
  665. */
  666. this.token_ = this.getId().toLowerCase();
  667. /**
  668. * The BooleanGroup that this setting belongs to.
  669. * @type {!goog.tweak.BooleanGroup}
  670. * @private
  671. */
  672. this.group_ = group;
  673. // Take setting out of top-level query parameter list.
  674. goog.tweak.BooleanInGroupSetting.superClass_.setParamName.call(this, null);
  675. };
  676. goog.inherits(goog.tweak.BooleanInGroupSetting, goog.tweak.BooleanSetting);
  677. /**
  678. * The logger for this class.
  679. * @type {goog.log.Logger}
  680. * @protected
  681. * @override
  682. */
  683. goog.tweak.BooleanInGroupSetting.prototype.logger =
  684. goog.log.getLogger('goog.tweak.BooleanInGroupSetting');
  685. /**
  686. * @override
  687. */
  688. goog.tweak.BooleanInGroupSetting.prototype.setParamName = function(value) {
  689. goog.asserts.fail('Use setToken() for BooleanInGroupSetting.');
  690. };
  691. /**
  692. * Sets the token to use in the query parameter.
  693. * @param {string} value The value.
  694. */
  695. goog.tweak.BooleanInGroupSetting.prototype.setToken = function(value) {
  696. this.token_ = value;
  697. };
  698. /**
  699. * Returns the token to use in the query parameter.
  700. * @return {string} The value.
  701. */
  702. goog.tweak.BooleanInGroupSetting.prototype.getToken = function() {
  703. return this.token_;
  704. };
  705. /**
  706. * Returns the BooleanGroup that this setting belongs to.
  707. * @return {!goog.tweak.BooleanGroup} The BooleanGroup that this setting
  708. * belongs to.
  709. */
  710. goog.tweak.BooleanInGroupSetting.prototype.getGroup = function() {
  711. return this.group_;
  712. };
  713. /**
  714. * A registry setting that contains a group of boolean subfield, where all
  715. * entries modify the same query parameter. For example:
  716. * ?foo=setting1,-setting2
  717. * @param {string} id The ID for the setting.
  718. * @param {string} description A description of what the setting does.
  719. * @constructor
  720. * @extends {goog.tweak.BaseSetting}
  721. * @final
  722. */
  723. goog.tweak.BooleanGroup = function(id, description) {
  724. goog.tweak.BaseSetting.call(this, id, description);
  725. /**
  726. * A map of token->child entry.
  727. * @type {!Object<!goog.tweak.BooleanSetting>}
  728. * @private
  729. */
  730. this.entriesByToken_ = {};
  731. /**
  732. * A map of token->true/false for all tokens that appeared in the query
  733. * parameter.
  734. * @type {!Object<boolean>}
  735. * @private
  736. */
  737. this.queryParamValues_ = {};
  738. };
  739. goog.inherits(goog.tweak.BooleanGroup, goog.tweak.BaseSetting);
  740. /**
  741. * The logger for this class.
  742. * @type {goog.log.Logger}
  743. * @protected
  744. * @override
  745. */
  746. goog.tweak.BooleanGroup.prototype.logger =
  747. goog.log.getLogger('goog.tweak.BooleanGroup');
  748. /**
  749. * Returns the map of token->boolean settings.
  750. * @return {!Object<!goog.tweak.BooleanSetting>} The child settings.
  751. */
  752. goog.tweak.BooleanGroup.prototype.getChildEntries = function() {
  753. return this.entriesByToken_;
  754. };
  755. /**
  756. * Adds the given BooleanSetting to the group.
  757. * @param {goog.tweak.BooleanInGroupSetting} boolEntry The entry.
  758. */
  759. goog.tweak.BooleanGroup.prototype.addChild = function(boolEntry) {
  760. this.ensureInitialized();
  761. var token = boolEntry.getToken();
  762. var lcToken = token.toLowerCase();
  763. goog.asserts.assert(
  764. !this.entriesByToken_[lcToken],
  765. 'Multiple bools registered with token "%s" in group: %s', token,
  766. this.getId());
  767. this.entriesByToken_[lcToken] = boolEntry;
  768. // Initialize from query param.
  769. var value = this.queryParamValues_[lcToken];
  770. if (value != undefined) {
  771. boolEntry.initialQueryParamValue = value ? '1' : '0';
  772. }
  773. };
  774. /**
  775. * @override
  776. */
  777. goog.tweak.BooleanGroup.prototype.initialize = function(value) {
  778. var queryParamValues = {};
  779. if (value) {
  780. var tokens = value.split(/\s*,\s*/);
  781. for (var i = 0; i < tokens.length; ++i) {
  782. var token = tokens[i].toLowerCase();
  783. var negative = token.charAt(0) == '-';
  784. if (negative) {
  785. token = token.substr(1);
  786. }
  787. queryParamValues[token] = !negative;
  788. }
  789. }
  790. this.queryParamValues_ = queryParamValues;
  791. };
  792. /**
  793. * @override
  794. */
  795. goog.tweak.BooleanGroup.prototype.getNewValueEncoded = function() {
  796. this.ensureInitialized();
  797. var nonDefaultValues = [];
  798. // Sort the keys so that the generate value is stable.
  799. var keys = goog.object.getKeys(this.entriesByToken_);
  800. keys.sort();
  801. for (var i = 0, entry; entry = this.entriesByToken_[keys[i]]; ++i) {
  802. var encodedValue = entry.getNewValueEncoded();
  803. if (encodedValue != null) {
  804. nonDefaultValues.push(
  805. (entry.getNewValue() ? '' : '-') + entry.getToken());
  806. }
  807. }
  808. return nonDefaultValues.length ? nonDefaultValues.join(',') : null;
  809. };
  810. /**
  811. * A registry action (a button).
  812. * @param {string} id The ID for the setting.
  813. * @param {string} description A description of what the setting does.
  814. * @param {!Function} callback Function to call when the button is clicked.
  815. * @constructor
  816. * @extends {goog.tweak.BaseEntry}
  817. * @final
  818. */
  819. goog.tweak.ButtonAction = function(id, description, callback) {
  820. goog.tweak.BaseEntry.call(this, id, description);
  821. this.addCallback(callback);
  822. this.setRestartRequired(false);
  823. };
  824. goog.inherits(goog.tweak.ButtonAction, goog.tweak.BaseEntry);