customize-controls.js 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938
  1. /* global JSON, wp */
  2. wp.customize.settingConstructor.abbreviation = wp.customize.Setting.extend({
  3. validate: function( value ) {
  4. return value.toUpperCase();
  5. }
  6. });
  7. jQuery( 'body' ).on( 'load', function() {
  8. 'use strict';
  9. var controlId, controlLabel, controlType, controlContent, controlDescription, controlData, mockControl,
  10. mockControlInstance, controlExpectedValues, sectionId, sectionContent, sectionData, mockSection,
  11. sectionInstance, sectionExpectedValues, panelId, panelTitle, panelDescription, panelContent, panelData,
  12. mockPanel, panelExpectedValues, testCustomizerModel, settingId, settingValue, mockSetting;
  13. testCustomizerModel = function( model, expectedValues ) {
  14. if ( ! expectedValues.type || ! wp.customize[ expectedValues.type ] ) {
  15. throw new Error( 'Must pass value type in expectedValues.' );
  16. }
  17. var type = expectedValues.type;
  18. QUnit.test( 'Model extends proper type', function( assert ) {
  19. assert.ok( model.extended( wp.customize[ type ] ) );
  20. } );
  21. if ( expectedValues.hasOwnProperty( 'id' ) ) {
  22. QUnit.test( type + ' instance has the right id', function( assert ) {
  23. assert.equal( model.id, expectedValues.id );
  24. });
  25. }
  26. if ( expectedValues.hasOwnProperty( 'title') ) {
  27. QUnit.test( type + ' instance has the right title.', function( assert ) {
  28. assert.equal( model.params.title, expectedValues.title );
  29. });
  30. }
  31. if ( expectedValues.hasOwnProperty( 'description' ) ) {
  32. QUnit.test( type + ' instance has the right description.', function( assert ) {
  33. assert.equal( model.params.description, expectedValues.description );
  34. });
  35. }
  36. if ( expectedValues.hasOwnProperty( 'content' ) ) {
  37. QUnit.test( type + ' instance has the right content.', function( assert ) {
  38. assert.equal( model.params.content, expectedValues.content );
  39. });
  40. }
  41. if ( expectedValues.hasOwnProperty( 'priority' ) ) {
  42. QUnit.test( type + ' instance has the right priority.', function( assert ) {
  43. assert.equal( model.priority(), expectedValues.priority );
  44. });
  45. }
  46. if ( expectedValues.hasOwnProperty( 'active' ) ) {
  47. QUnit.test( type + ' instance has the right active state.', function( assert ) {
  48. assert.equal( model.active(), expectedValues.active );
  49. });
  50. }
  51. QUnit.test( type + ' can be deactivated', function( assert ) {
  52. model.activate();
  53. model.deactivate();
  54. assert.equal( model.active(), false );
  55. model.activate();
  56. assert.equal( model.active(), true );
  57. assert.ok(true);
  58. });
  59. if ( type === 'Panel' || type === 'Section' ) {
  60. if ( expectedValues.hasOwnProperty( 'expanded' ) ) {
  61. QUnit.test( type + ' instance has the right expanded state.', function( assert ) {
  62. assert.equal( model.expanded(), expectedValues.expanded );
  63. } );
  64. }
  65. QUnit.test( type + ' instance is collapsed after calling .collapse()', function( assert ) {
  66. model.collapse();
  67. assert.ok( ! model.expanded() );
  68. });
  69. QUnit.test( type + ' instance is expanded after calling .expand()', function( assert ) {
  70. model.expand();
  71. assert.ok( model.expanded() );
  72. });
  73. }
  74. };
  75. QUnit.module( 'Customizer notifications collection' );
  76. QUnit.test( 'Notifications collection exists', function( assert ) {
  77. assert.ok( wp.customize.notifications );
  78. assert.equal( wp.customize.notifications.defaultConstructor, wp.customize.Notification );
  79. } );
  80. QUnit.test( 'Notification objects are rendered as part of notifications collection', function( assert ) {
  81. var container = jQuery( '#customize-notifications-test' ), items, collection;
  82. collection = new wp.customize.Notifications({
  83. container: container
  84. });
  85. collection.add( 'mycode-1', new wp.customize.Notification( 'mycode-1', { message: 'My message 1' } ) );
  86. collection.render();
  87. items = collection.container.find( 'li' );
  88. assert.equal( items.length, 1 );
  89. assert.equal( items.first().data( 'code' ), 'mycode-1' );
  90. collection.add( 'mycode-2', new wp.customize.Notification( 'mycode-2', {
  91. message: 'My message 2',
  92. dismissible: true
  93. } ) );
  94. collection.render();
  95. items = collection.container.find( 'li' );
  96. assert.equal( items.length, 2 );
  97. assert.equal( items.first().data( 'code' ), 'mycode-2' );
  98. assert.equal( items.last().data( 'code' ), 'mycode-1' );
  99. assert.equal( items.first().find( '.notice-dismiss' ).length, 1 );
  100. assert.equal( items.last().find( '.notice-dismiss' ).length, 0 );
  101. collection.remove( 'mycode-2' );
  102. collection.render();
  103. items = collection.container.find( 'li' );
  104. assert.equal( items.length, 1 );
  105. assert.equal( items.first().data( 'code' ), 'mycode-1' );
  106. collection.remove( 'mycode-1' );
  107. collection.render();
  108. assert.ok( collection.container.is( ':hidden' ), 'Notifications area is hidden.' );
  109. } );
  110. QUnit.module( 'Customizer Previewed Device' );
  111. QUnit.test( 'Previewed device defaults to desktop.', function( assert ) {
  112. assert.equal( wp.customize.previewedDevice.get(), 'desktop' );
  113. } );
  114. QUnit.module( 'Customizer Setting in Fixture' );
  115. QUnit.test( 'Setting has fixture value', function( assert ) {
  116. assert.equal( wp.customize( 'fixture-setting' )(), 'Lorem Ipsum' );
  117. } );
  118. QUnit.test( 'Setting has notifications', function( assert ) {
  119. var setting = wp.customize( 'fixture-setting' );
  120. assert.ok( setting.notifications.extended( wp.customize.Values ) );
  121. assert.equal( wp.customize.Notification, setting.notifications.prototype.constructor.defaultConstructor );
  122. } );
  123. QUnit.test( 'Setting has findControls method', function( assert ) {
  124. var controls, setting = wp.customize( 'fixture-setting' );
  125. assert.equal( 'function', typeof setting.findControls );
  126. controls = setting.findControls();
  127. assert.equal( 1, controls.length );
  128. assert.equal( 'fixture-control', controls[0].id );
  129. } );
  130. QUnit.test( 'Setting constructor object exists', function( assert ) {
  131. assert.ok( _.isObject( wp.customize.settingConstructor ) );
  132. } );
  133. QUnit.test( 'Custom setting constructor is used', function( assert ) {
  134. var setting = wp.customize( 'fixture-setting-abbr' );
  135. assert.ok( setting.extended( wp.customize.settingConstructor.abbreviation ) );
  136. setting.set( 'usa' );
  137. assert.equal( 'USA', setting.get() );
  138. } );
  139. QUnit.module( 'Customizer Control in Fixture' );
  140. QUnit.test( 'Control exists', function( assert ) {
  141. assert.ok( wp.customize.control.has( 'fixture-control' ) );
  142. } );
  143. QUnit.test( 'Control has the fixture setting', function( assert ) {
  144. var control = wp.customize.control( 'fixture-control' );
  145. assert.equal( control.setting(), 'Lorem Ipsum' );
  146. assert.equal( control.setting.id, 'fixture-setting' );
  147. } );
  148. QUnit.test( 'Control has the section fixture section ID', function( assert ) {
  149. var control = wp.customize.control( 'fixture-control' );
  150. assert.equal( control.section(), 'fixture-section' );
  151. } );
  152. QUnit.test( 'Control has notifications', function ( assert ) {
  153. var control = wp.customize.control( 'fixture-control' ), settingNotification, controlOnlyNotification, doneEmbedded;
  154. assert.ok( control.notifications.extended( wp.customize.Values ) );
  155. assert.equal( wp.customize.Notification, control.notifications.prototype.constructor.defaultConstructor );
  156. assert.ok( _.isFunction( control.getNotificationsContainerElement ) );
  157. assert.ok( _.isFunction( control.renderNotifications ) );
  158. doneEmbedded = assert.async();
  159. control.deferred.embedded.done( function() {
  160. var notificationContainerElement;
  161. assert.equal( 0, _.size( control.notifications._value ) );
  162. assert.equal( 0, _.size( control.settings['default'].notifications._value ) );
  163. notificationContainerElement = control.getNotificationsContainerElement();
  164. assert.equal( 1, notificationContainerElement.length );
  165. assert.ok( notificationContainerElement.is( '.customize-control-notifications-container' ) );
  166. assert.equal( 0, notificationContainerElement.find( '> ul > li' ).length );
  167. assert.equal( 0, notificationContainerElement.height() );
  168. settingNotification = new wp.customize.Notification( 'setting_invalidity', { message: 'Invalid setting' } );
  169. controlOnlyNotification = new wp.customize.Notification( 'control_invalidity', { message: 'Invalid control' } );
  170. control.settings['default'].notifications.add( settingNotification.code, settingNotification );
  171. control.notifications.add( controlOnlyNotification.code, controlOnlyNotification );
  172. // Note that renderNotifications is being called manually here since rendering normally happens asynchronously.
  173. control.notifications.render();
  174. assert.equal( 2, notificationContainerElement.find( '> ul > li' ).length );
  175. assert.notEqual( 'none', notificationContainerElement.css( 'display' ) );
  176. assert.equal( 2, _.size( control.notifications._value ) );
  177. assert.equal( 1, _.size( control.settings['default'].notifications._value ) );
  178. control.notifications.remove( controlOnlyNotification.code );
  179. control.notifications.render();
  180. assert.equal( 1, notificationContainerElement.find( '> ul > li' ).length );
  181. assert.notEqual( 'none', notificationContainerElement.css( 'display' ) );
  182. control.settings['default'].notifications.remove( settingNotification.code );
  183. control.notifications.render();
  184. assert.equal( 0, notificationContainerElement.find( '> ul > li' ).length );
  185. notificationContainerElement.stop().hide(); // Clean up.
  186. doneEmbedded();
  187. } );
  188. } );
  189. QUnit.module( 'Customizer control without associated settings' );
  190. QUnit.test( 'Control can be created without settings', function( assert ) {
  191. var control = new wp.customize.Control( 'settingless', {
  192. params: {
  193. content: jQuery( '<li class="settingless">Hello World</li>' ),
  194. section: 'fixture-section'
  195. }
  196. } );
  197. wp.customize.control.add( control.id, control );
  198. assert.equal( control.deferred.embedded.state(), 'resolved' );
  199. assert.ok( null === control.setting );
  200. assert.ok( jQuery.isEmptyObject( control.settings ) );
  201. } );
  202. // Begin sections.
  203. QUnit.module( 'Customizer Section in Fixture' );
  204. QUnit.test( 'Fixture section exists', function( assert ) {
  205. assert.ok( wp.customize.section.has( 'fixture-section' ) );
  206. } );
  207. QUnit.test( 'Fixture section has control among controls()', function( assert ) {
  208. var section = wp.customize.section( 'fixture-section' );
  209. assert.ok( -1 !== _.pluck( section.controls(), 'id' ).indexOf( 'fixture-control' ) );
  210. } );
  211. QUnit.test( 'Fixture section has has expected panel', function( assert ) {
  212. var section = wp.customize.section( 'fixture-section' );
  213. assert.equal( section.panel(), 'fixture-panel' );
  214. } );
  215. QUnit.module( 'Customizer Default Section with Template in Fixture' );
  216. QUnit.test( 'Fixture section exists', function( assert ) {
  217. assert.ok( wp.customize.section.has( 'fixture-section-default-templated' ) );
  218. } );
  219. QUnit.test( 'Fixture section has expected content', function( assert ) {
  220. var id = 'fixture-section-default-templated', section;
  221. section = wp.customize.section( id );
  222. assert.ok( ! section.params.content );
  223. assert.ok( !! section.container );
  224. assert.ok( !! section.headContainer );
  225. assert.ok( !! section.contentContainer );
  226. assert.ok( section.container.has( section.headContainer ) );
  227. assert.ok( section.container.has( section.contentContainer ) );
  228. assert.ok( section.headContainer.is( '.control-section.control-section-default' ) );
  229. assert.ok( 1 === section.headContainer.find( '> .accordion-section-title' ).length );
  230. assert.ok( section.contentContainer.is( '.accordion-section-content' ) );
  231. assert.equal( section.headContainer.attr( 'aria-owns' ), section.contentContainer.attr( 'id' ) );
  232. } );
  233. QUnit.module( 'Customizer Custom Type (titleless) Section with Template in Fixture' );
  234. QUnit.test( 'Fixture section exists', function( assert ) {
  235. assert.ok( wp.customize.section.has( 'fixture-section-titleless-templated' ) );
  236. } );
  237. QUnit.test( 'Fixture section has expected content', function( assert ) {
  238. var id = 'fixture-section-titleless-templated', section;
  239. section = wp.customize.section( id );
  240. assert.ok( ! section.params.content );
  241. assert.ok( !! section.container );
  242. assert.ok( !! section.headContainer );
  243. assert.ok( !! section.contentContainer );
  244. assert.ok( section.container.has( section.headContainer ) );
  245. assert.ok( section.container.has( section.contentContainer ) );
  246. assert.ok( section.container.is( '.control-section.control-section-titleless' ) );
  247. assert.ok( 0 === section.headContainer.find( '> .accordion-section-title' ).length );
  248. assert.ok( section.contentContainer.is( '.accordion-section-content' ) );
  249. assert.equal( section.headContainer.attr( 'aria-owns' ), section.contentContainer.attr( 'id' ) );
  250. } );
  251. QUnit.module( 'Customizer Custom Type Section Lacking Specific Template' );
  252. QUnit.test( 'Fixture section has expected content', function( assert ) {
  253. var id = 'fixture-section-reusing-default-template', section;
  254. section = wp.customize.section( id );
  255. assert.ok( ! section.params.content );
  256. assert.ok( !! section.container );
  257. assert.ok( !! section.headContainer );
  258. assert.ok( !! section.contentContainer );
  259. assert.ok( section.container.has( section.headContainer ) );
  260. assert.ok( section.container.has( section.contentContainer ) );
  261. assert.ok( section.headContainer.is( '.control-section.control-section-' + section.params.type ) );
  262. assert.ok( 1 === section.headContainer.find( '> .accordion-section-title' ).length );
  263. assert.ok( section.contentContainer.is( '.accordion-section-content' ) );
  264. assert.equal( section.headContainer.attr( 'aria-owns' ), section.contentContainer.attr( 'id' ) );
  265. } );
  266. QUnit.module( 'Customizer Section lacking any params' );
  267. QUnit.test( 'Fixture section has default params supplied', function( assert ) {
  268. var id = 'fixture-section-without-params', section, defaultParams;
  269. section = wp.customize.section( id );
  270. defaultParams = {
  271. title: '',
  272. description: '',
  273. priority: 100,
  274. panel: null,
  275. type: 'default',
  276. content: null,
  277. active: true,
  278. customizeAction: ''
  279. };
  280. jQuery.each( defaultParams, function ( key, value ) {
  281. assert.ok( 'undefined' !== typeof section.params[ key ] );
  282. assert.equal( value, section.params[ key ] );
  283. } );
  284. assert.ok( _.isNumber( section.params.instanceNumber ) );
  285. } );
  286. // Begin panels.
  287. QUnit.module( 'Customizer Panel in Fixture' );
  288. QUnit.test( 'Fixture panel exists', function( assert ) {
  289. assert.ok( wp.customize.panel.has( 'fixture-panel' ) );
  290. } );
  291. QUnit.test( 'Fixture panel has content', function( assert ) {
  292. var panel = wp.customize.panel( 'fixture-panel' );
  293. assert.ok( !! panel.params.content );
  294. assert.ok( !! panel.container );
  295. assert.ok( !! panel.headContainer );
  296. assert.ok( !! panel.contentContainer );
  297. assert.ok( panel.container.has( panel.headContainer ) );
  298. assert.ok( panel.container.has( panel.contentContainer ) );
  299. } );
  300. QUnit.test( 'Fixture panel has section among its sections()', function( assert ) {
  301. var panel = wp.customize.panel( 'fixture-panel' );
  302. assert.ok( -1 !== _.pluck( panel.sections(), 'id' ).indexOf( 'fixture-section' ) );
  303. } );
  304. QUnit.test( 'Panel is not expanded by default', function( assert ) {
  305. var panel = wp.customize.panel( 'fixture-panel' );
  306. assert.ok( ! panel.expanded() );
  307. } );
  308. QUnit.test( 'Panel is not expanded by default', function( assert ) {
  309. var panel = wp.customize.panel( 'fixture-panel' );
  310. assert.ok( ! panel.expanded() );
  311. } );
  312. QUnit.test( 'Focusing on a control will expand the panel and section', function( assert ) {
  313. var panel, section, control;
  314. panel = wp.customize.panel( 'fixture-panel' );
  315. section = wp.customize.section( 'fixture-section' );
  316. control = wp.customize.control( 'fixture-control' );
  317. assert.ok( ! panel.expanded() );
  318. assert.ok( ! section.expanded() );
  319. control.focus();
  320. assert.ok( section.expanded() );
  321. assert.ok( panel.expanded() );
  322. } );
  323. QUnit.module( 'Customizer Default Panel with Template in Fixture' );
  324. QUnit.test( 'Fixture section exists', function( assert ) {
  325. assert.ok( wp.customize.panel.has( 'fixture-panel-default-templated' ) );
  326. } );
  327. QUnit.test( 'Fixture panel has expected content', function( assert ) {
  328. var id = 'fixture-panel-default-templated', panel;
  329. panel = wp.customize.panel( id );
  330. assert.ok( ! panel.params.content );
  331. assert.ok( !! panel.container );
  332. assert.ok( !! panel.headContainer );
  333. assert.ok( !! panel.contentContainer );
  334. assert.ok( panel.container.has( panel.headContainer ) );
  335. assert.ok( panel.container.has( panel.contentContainer ) );
  336. assert.ok( panel.headContainer.is( '.control-panel.control-panel-default' ) );
  337. assert.ok( 1 === panel.headContainer.find( '> .accordion-section-title' ).length );
  338. assert.ok( panel.contentContainer.is( '.control-panel-content' ) );
  339. assert.equal( panel.headContainer.attr( 'aria-owns' ), panel.contentContainer.attr( 'id' ) );
  340. } );
  341. QUnit.module( 'Customizer Custom Type Panel (titleless) with Template in Fixture' );
  342. QUnit.test( 'Fixture panel exists', function( assert ) {
  343. assert.ok( wp.customize.panel.has( 'fixture-panel-titleless-templated' ) );
  344. } );
  345. QUnit.test( 'Fixture panel has expected content', function( assert ) {
  346. var id = 'fixture-panel-titleless-templated', panel;
  347. panel = wp.customize.panel( id );
  348. assert.ok( ! panel.params.content );
  349. assert.ok( !! panel.container );
  350. assert.ok( !! panel.headContainer );
  351. assert.ok( !! panel.contentContainer );
  352. assert.ok( panel.container.has( panel.headContainer ) );
  353. assert.ok( panel.container.has( panel.contentContainer ) );
  354. assert.ok( panel.headContainer.is( '.control-panel.control-panel-titleless' ) );
  355. assert.ok( 0 === panel.headContainer.find( '> .accordion-section-title' ).length );
  356. assert.ok( panel.contentContainer.is( '.control-panel-content' ) );
  357. assert.equal( panel.headContainer.attr( 'aria-owns' ), panel.contentContainer.attr( 'id' ) );
  358. } );
  359. QUnit.module( 'Customizer Custom Type Panel Lacking Specific Template' );
  360. QUnit.test( 'Fixture panel has expected content', function( assert ) {
  361. var id = 'fixture-panel-reusing-default-template', panel;
  362. panel = wp.customize.panel( id );
  363. assert.ok( ! panel.params.content );
  364. assert.ok( !! panel.container );
  365. assert.ok( !! panel.headContainer );
  366. assert.ok( !! panel.contentContainer );
  367. assert.ok( panel.container.has( panel.headContainer ) );
  368. assert.ok( panel.container.has( panel.contentContainer ) );
  369. assert.ok( panel.headContainer.is( '.control-panel.control-panel-' + panel.params.type ) );
  370. assert.ok( 1 === panel.headContainer.find( '> .accordion-section-title' ).length );
  371. assert.ok( panel.contentContainer.is( '.control-panel-content' ) );
  372. assert.equal( panel.headContainer.attr( 'aria-owns' ), panel.contentContainer.attr( 'id' ) );
  373. } );
  374. QUnit.module( 'Customizer Panel lacking any params' );
  375. QUnit.test( 'Fixture panel has default params supplied', function( assert ) {
  376. var id = 'fixture-panel-without-params', panel, defaultParams;
  377. panel = wp.customize.panel( id );
  378. defaultParams = {
  379. title: '',
  380. description: '',
  381. priority: 100,
  382. type: 'default',
  383. content: null,
  384. active: true
  385. };
  386. jQuery.each( defaultParams, function ( key, value ) {
  387. assert.ok( 'undefined' !== typeof panel.params[ key ] );
  388. assert.equal( value, panel.params[ key ] );
  389. } );
  390. assert.ok( _.isNumber( panel.params.instanceNumber ) );
  391. } );
  392. QUnit.module( 'Dynamically-created Customizer Setting Model' );
  393. settingId = 'new_blogname';
  394. settingValue = 'Hello World';
  395. QUnit.test( 'Create a new setting', function( assert ) {
  396. mockSetting = wp.customize.create(
  397. settingId,
  398. settingId,
  399. settingValue,
  400. {
  401. transport: 'refresh',
  402. previewer: wp.customize.previewer
  403. }
  404. );
  405. assert.equal( mockSetting(), settingValue );
  406. assert.equal( mockSetting.id, settingId );
  407. } );
  408. QUnit.module( 'Dynamically-created Customizer Section Model' );
  409. sectionId = 'mock_title_tagline';
  410. sectionContent = '<li id="accordion-section-mock_title_tagline" class="accordion-section control-section control-section-default"> <h3 class="accordion-section-title" tabindex="0"> Section Fixture <span class="screen-reader-text">Press return or enter to open</span> </h3> <ul class="accordion-section-content"> <li class="customize-section-description-container"> <div class="customize-section-title"> <button class="customize-section-back" tabindex="-1"> <span class="screen-reader-text">Back</span> </button> <h3> <span class="customize-action">Customizing &#9656; Fixture Panel</span> Section Fixture </h3> </div> </li> </ul> </li>';
  411. sectionData = {
  412. content: sectionContent,
  413. active: true,
  414. type: 'default'
  415. };
  416. mockSection = new wp.customize.Section( sectionId, { params: sectionData } );
  417. sectionExpectedValues = {
  418. type: 'Section',
  419. id: sectionId,
  420. content: sectionContent,
  421. priority: 100,
  422. active: true // @todo This should default to true.
  423. };
  424. testCustomizerModel( mockSection, sectionExpectedValues );
  425. QUnit.test( 'Section has been embedded', function( assert ) {
  426. assert.equal( mockSection.deferred.embedded.state(), 'resolved' );
  427. } );
  428. wp.customize.section.add( sectionId, mockSection );
  429. QUnit.test( 'Section instance added to the wp.customize.section object', function( assert ) {
  430. assert.ok( wp.customize.section.has( sectionId ) );
  431. });
  432. sectionInstance = wp.customize.section( sectionId );
  433. QUnit.test( 'Section instance has right content when accessed from wp.customize.section()', function( assert ) {
  434. assert.equal( sectionInstance.params.content, sectionContent );
  435. });
  436. QUnit.test( 'Section instance has no children yet', function( assert ) {
  437. assert.equal( sectionInstance.controls().length, 0 );
  438. });
  439. QUnit.module( 'Dynamically-created Customizer Control Model' );
  440. controlId = 'new_blogname';
  441. controlLabel = 'Site Title';
  442. controlType = 'text';
  443. controlContent = '<li id="customize-control-blogname" class="customize-control customize-control-text"></li>';
  444. controlDescription = 'Test control description';
  445. controlData = {
  446. content: controlContent,
  447. description: controlDescription,
  448. label: controlLabel,
  449. settings: { 'default': 'new_blogname' },
  450. type: controlType,
  451. active: true // @todo This should default to true.
  452. };
  453. mockControl = new wp.customize.Control( controlId, {
  454. params: controlData,
  455. previewer: wp.customize.previewer
  456. });
  457. controlExpectedValues = {
  458. type: 'Control',
  459. content: controlContent,
  460. description: controlDescription,
  461. label: controlLabel,
  462. id: controlId,
  463. priority: 10
  464. };
  465. testCustomizerModel( mockControl, controlExpectedValues );
  466. QUnit.test( 'Control instance does not yet belong to a section.', function( assert ) {
  467. assert.equal( mockControl.section(), undefined );
  468. });
  469. QUnit.test( 'Control has not been embedded yet', function( assert ) {
  470. assert.equal( mockControl.deferred.embedded.state(), 'pending' );
  471. } );
  472. QUnit.test( 'Control instance has the right selector.', function( assert ) {
  473. assert.equal( mockControl.selector, '#customize-control-new_blogname' );
  474. });
  475. wp.customize.control.add( controlId, mockControl );
  476. QUnit.test( 'Control instance was added to the control class.', function( assert ) {
  477. assert.ok( wp.customize.control.has( controlId ) );
  478. });
  479. mockControlInstance = wp.customize.control( controlId );
  480. QUnit.test( 'Control instance has the right id when accessed from api.control().', function( assert ) {
  481. assert.equal( mockControlInstance.id, controlId );
  482. });
  483. QUnit.test( 'Control section can be set as expected', function( assert ) {
  484. mockControl.section( mockSection.id );
  485. assert.equal( mockControl.section(), mockSection.id );
  486. });
  487. QUnit.test( 'Associating a control with a section allows it to be embedded', function( assert ) {
  488. assert.equal( mockControl.deferred.embedded.state(), 'resolved' );
  489. });
  490. QUnit.test( 'Control is now available on section.controls()', function( assert ) {
  491. assert.equal( sectionInstance.controls().length, 1 );
  492. assert.equal( sectionInstance.controls()[0], mockControl );
  493. });
  494. QUnit.module( 'Dynamically-created Customizer Panel Model' );
  495. panelId = 'mockPanelId';
  496. panelTitle = 'Mock Panel Title';
  497. panelDescription = 'Mock panel description';
  498. panelContent = '<li id="accordion-panel-mockPanelId" class="accordion-section control-section control-panel control-panel-default"> <h3 class="accordion-section-title" tabindex="0"> Fixture Panel <span class="screen-reader-text">Press return or enter to open this panel</span> </h3> <ul class="accordion-sub-container control-panel-content"> <li class="panel-meta customize-info accordion-section cannot-expand"> <button class="customize-panel-back" tabindex="-1"><span class="screen-reader-text">Back</span></button> <div class="accordion-section-title"> <span class="preview-notice">You are customizing <strong class="panel-title">Fixture Panel</strong></span> <button class="customize-help-toggle dashicons dashicons-editor-help" tabindex="0" aria-expanded="false"><span class="screen-reader-text">Help</span></button> </div> </li> </ul> </li>';
  499. panelData = {
  500. content: panelContent,
  501. title: panelTitle,
  502. description: panelDescription,
  503. active: true, // @todo This should default to true.
  504. type: 'default'
  505. };
  506. mockPanel = new wp.customize.Panel( panelId, { params: panelData } );
  507. panelExpectedValues = {
  508. type: 'Panel',
  509. id: panelId,
  510. title: panelTitle,
  511. description: panelDescription,
  512. content: panelContent,
  513. priority: 100,
  514. active: true
  515. };
  516. testCustomizerModel( mockPanel, panelExpectedValues );
  517. QUnit.test( 'Panel instance is not contextuallyActive', function( assert ) {
  518. assert.equal( mockPanel.isContextuallyActive(), false );
  519. });
  520. QUnit.module( 'Test wp.customize.findControlsForSettings' );
  521. QUnit.test( 'findControlsForSettings(blogname)', function( assert ) {
  522. var controlsForSettings, settingId = 'fixture-setting', controlId = 'fixture-control';
  523. assert.ok( wp.customize.control.has( controlId ) );
  524. assert.ok( wp.customize.has( settingId ) );
  525. controlsForSettings = wp.customize.findControlsForSettings( [ settingId ] );
  526. assert.ok( _.isObject( controlsForSettings ), 'Response is object' );
  527. assert.ok( _.isArray( controlsForSettings['fixture-setting'] ), 'Response has a fixture-setting array' );
  528. assert.equal( 1, controlsForSettings['fixture-setting'].length );
  529. assert.equal( wp.customize.control( controlId ), controlsForSettings['fixture-setting'][0] );
  530. } );
  531. QUnit.module( 'Customize Controls wp.customize.dirtyValues' );
  532. QUnit.test( 'dirtyValues() returns expected values', function( assert ) {
  533. wp.customize.state( 'changesetStatus' ).set( 'auto-draft' );
  534. wp.customize.each( function( setting ) {
  535. setting._dirty = false;
  536. } );
  537. assert.ok( _.isEmpty( wp.customize.dirtyValues() ) );
  538. assert.ok( _.isEmpty( wp.customize.dirtyValues( { unsaved: false } ) ) );
  539. wp.customize( 'fixture-setting' )._dirty = true;
  540. assert.ok( ! _.isEmpty( wp.customize.dirtyValues() ) );
  541. assert.ok( _.isEmpty( wp.customize.dirtyValues( { unsaved: true } ) ) );
  542. wp.customize( 'fixture-setting' ).set( 'Modified' );
  543. assert.ok( ! _.isEmpty( wp.customize.dirtyValues() ) );
  544. assert.ok( ! _.isEmpty( wp.customize.dirtyValues( { unsaved: true } ) ) );
  545. assert.equal( 'Modified', wp.customize.dirtyValues()['fixture-setting'] );
  546. // When the changeset does not exist, all dirty settings are necessarily unsaved.
  547. wp.customize.state( 'changesetStatus' ).set( '' );
  548. wp.customize( 'fixture-setting' )._dirty = true;
  549. assert.ok( ! _.isEmpty( wp.customize.dirtyValues() ) );
  550. assert.ok( ! _.isEmpty( wp.customize.dirtyValues( { unsaved: true } ) ) );
  551. } );
  552. QUnit.module( 'Customize Controls: wp.customize.requestChangesetUpdate()' );
  553. QUnit.test( 'requestChangesetUpdate makes request and returns promise', function( assert ) {
  554. var request, originalBeforeSetup = jQuery.ajaxSettings.beforeSend;
  555. jQuery.ajaxSetup( {
  556. beforeSend: function( e, data ) {
  557. var queryParams, changesetData;
  558. queryParams = wp.customize.utils.parseQueryString( data.data );
  559. assert.equal( 'customize_save', queryParams.action );
  560. assert.ok( ! _.isUndefined( queryParams.customize_changeset_data ) );
  561. assert.ok( ! _.isUndefined( queryParams.nonce ) );
  562. assert.ok( ! _.isUndefined( queryParams.customize_theme ) );
  563. assert.equal( wp.customize.settings.changeset.uuid, queryParams.customize_changeset_uuid );
  564. assert.equal( 'on', queryParams.wp_customize );
  565. changesetData = JSON.parse( queryParams.customize_changeset_data );
  566. assert.ok( ! _.isUndefined( changesetData.additionalSetting ) );
  567. assert.ok( ! _.isUndefined( changesetData['fixture-setting'] ) );
  568. assert.equal( 'additionalValue', changesetData.additionalSetting.value );
  569. assert.equal( 'requestChangesetUpdate', changesetData['fixture-setting'].value );
  570. // Prevent Ajax request from completing.
  571. return false;
  572. }
  573. } );
  574. wp.customize.each( function( setting ) {
  575. setting._dirty = false;
  576. } );
  577. request = wp.customize.requestChangesetUpdate();
  578. assert.equal( 'resolved', request.state());
  579. request.done( function( data ) {
  580. assert.ok( _.isEqual( {}, data ) );
  581. } );
  582. wp.customize( 'fixture-setting' ).set( 'requestChangesetUpdate' );
  583. request = wp.customize.requestChangesetUpdate( {
  584. additionalSetting: {
  585. value: 'additionalValue'
  586. }
  587. } );
  588. request.always( function( data ) {
  589. assert.equal( 'canceled', data.statusText );
  590. jQuery.ajaxSetup( { beforeSend: originalBeforeSetup } );
  591. } );
  592. } );
  593. QUnit.module( 'Customize Utils: wp.customize.utils.getRemainingTime()' );
  594. QUnit.test( 'utils.getRemainingTime calculates time correctly', function( assert ) {
  595. var datetime = '2599-08-06 12:12:13', timeRemaining, timeRemainingWithDateInstance, timeRemaingingWithTimestamp;
  596. timeRemaining = wp.customize.utils.getRemainingTime( datetime );
  597. timeRemainingWithDateInstance = wp.customize.utils.getRemainingTime( new Date( datetime.replace( /-/g, '/' ) ) );
  598. timeRemaingingWithTimestamp = wp.customize.utils.getRemainingTime( ( new Date( datetime.replace( /-/g, '/' ) ) ).getTime() );
  599. assert.equal( typeof timeRemaining, 'number', timeRemaining );
  600. assert.equal( typeof timeRemainingWithDateInstance, 'number', timeRemaining );
  601. assert.equal( typeof timeRemaingingWithTimestamp, 'number', timeRemaining );
  602. assert.deepEqual( timeRemaining, timeRemainingWithDateInstance );
  603. assert.deepEqual( timeRemaining, timeRemaingingWithTimestamp );
  604. });
  605. QUnit.module( 'Customize Utils: wp.customize.utils.getCurrentTimestamp()' );
  606. QUnit.test( 'utils.getCurrentTimestamp returns timestamp', function( assert ) {
  607. var currentTimeStamp;
  608. currentTimeStamp = wp.customize.utils.getCurrentTimestamp();
  609. assert.equal( typeof currentTimeStamp, 'number' );
  610. });
  611. QUnit.module( 'Customize Controls: wp.customize.DateTimeControl' );
  612. QUnit.test( 'Test DateTimeControl creation and its methods', function( assert ) {
  613. var control, controlId = 'date_time', section, sectionId = 'fixture-section',
  614. datetime = '2599-08-06 18:12:13', dateTimeArray, dateTimeArrayInampm, timeString,
  615. day, year, month, minute, meridian, hour;
  616. section = wp.customize.section( sectionId );
  617. control = new wp.customize.DateTimeControl( controlId, {
  618. params: {
  619. section: section.id,
  620. type: 'date_time',
  621. setting: new wp.customize.Value( datetime ),
  622. includeTime: true,
  623. content: '<li id="customize-control-' + controlId + '" class="customize-control"></li>'
  624. }
  625. } );
  626. wp.customize.control.add( controlId, control );
  627. // Test control creations.
  628. assert.ok( control.templateSelector, '#customize-control-date_time-content' );
  629. assert.ok( control.section(), sectionId );
  630. assert.equal( _.size( control.inputElements ), control.elements.length );
  631. assert.ok( control.setting(), datetime );
  632. day = control.inputElements.day;
  633. month = control.inputElements.month;
  634. year = control.inputElements.year;
  635. minute = control.inputElements.minute;
  636. hour = control.inputElements.hour;
  637. meridian = control.inputElements.meridian;
  638. year( '23' );
  639. assert.ok( control.invalidDate );
  640. year( '2100' );
  641. month( '8' );
  642. assert.ok( ! control.invalidDate );
  643. day( 'test' );
  644. assert.ok( control.invalidDate );
  645. day( '3' );
  646. assert.ok( ! control.invalidDate );
  647. // Test control.parseDateTime().
  648. control.params.twelveHourFormat = false;
  649. dateTimeArray = control.parseDateTime( datetime );
  650. assert.deepEqual( dateTimeArray, {
  651. year: '2599',
  652. month: '08',
  653. hour: '18',
  654. minute: '12',
  655. second: '13',
  656. day: '06'
  657. } );
  658. control.params.twelveHourFormat = true;
  659. dateTimeArrayInampm = control.parseDateTime( datetime );
  660. assert.deepEqual( dateTimeArrayInampm, {
  661. year: '2599',
  662. month: '08',
  663. hour: '6',
  664. minute: '12',
  665. meridian: 'pm',
  666. day: '06'
  667. } );
  668. year( '2010' );
  669. month( '12' );
  670. day( '18' );
  671. hour( '3' );
  672. minute( '44' );
  673. meridian( 'am' );
  674. // Test control.convertInputDateToString().
  675. timeString = control.convertInputDateToString();
  676. assert.equal( timeString, '2010-12-18 03:44:00' );
  677. meridian( 'pm' );
  678. timeString = control.convertInputDateToString();
  679. assert.equal( timeString, '2010-12-18 15:44:00' );
  680. control.params.includeTime = false;
  681. timeString = control.convertInputDateToString();
  682. assert.equal( timeString, '2010-12-18' );
  683. control.params.includeTime = true;
  684. // Test control.updateDaysForMonth().
  685. year( 2017 );
  686. month( 2 );
  687. day( 28 );
  688. assert.ok( ! control.invalidDate );
  689. day( 31 );
  690. assert.ok( control.invalidDate );
  691. day( 20 );
  692. assert.equal( day(), 20, 'Should not update if its less the correct number of days' );
  693. // Test control.convertHourToTwentyFourHourFormat().
  694. assert.equal( control.convertHourToTwentyFourHourFormat( 11, 'pm' ), 23 );
  695. assert.equal( control.convertHourToTwentyFourHourFormat( 12, 'pm' ), 12 );
  696. assert.equal( control.convertHourToTwentyFourHourFormat( 12, 'am' ), 0 );
  697. assert.equal( control.convertHourToTwentyFourHourFormat( 11, 'am' ), 11 );
  698. // Test control.toggleFutureDateNotification().
  699. assert.deepEqual( control.toggleFutureDateNotification(), control );
  700. control.toggleFutureDateNotification( true );
  701. assert.ok( control.notifications.has( 'not_future_date' ) );
  702. control.toggleFutureDateNotification( false );
  703. assert.notOk( control.notifications.has( 'not_future_date' ) );
  704. // Test control.populateDateInputs().
  705. control.setting._value = '2000-12-30 12:34:56';
  706. control.populateDateInputs();
  707. assert.equal( '2000', control.inputElements.year.get() );
  708. assert.equal( '12', control.inputElements.month.get() );
  709. assert.equal( '30', control.inputElements.day.get() );
  710. assert.equal( '12', control.inputElements.hour.get() );
  711. assert.equal( '34', control.inputElements.minute.get() );
  712. assert.equal( 'pm', control.inputElements.meridian.get() );
  713. // Test control.validateInputs().
  714. hour( 33 );
  715. assert.ok( control.validateInputs() );
  716. hour( 10 );
  717. assert.notOk( control.validateInputs() );
  718. minute( 123 );
  719. assert.ok( control.validateInputs() );
  720. minute( 20 );
  721. assert.notOk( control.validateInputs() );
  722. // Test control.populateSetting().
  723. day( 2 );
  724. month( 11 );
  725. year( 2018 );
  726. hour( 4 );
  727. minute( 20 );
  728. meridian( 'pm' );
  729. control.populateSetting();
  730. assert.equal( control.setting(), '2018-11-02 16:20:00' );
  731. hour( 123 );
  732. control.populateSetting();
  733. assert.equal( control.setting(), '2018-11-02 16:20:00' ); // Should not update if invalid hour.
  734. hour( 5 );
  735. control.populateSetting();
  736. assert.equal( control.setting(), '2018-11-02 17:20:00' );
  737. // Test control.isFutureDate().
  738. day( 2 );
  739. month( 11 );
  740. year( 2318 );
  741. hour( 4 );
  742. minute( 20 );
  743. meridian( 'pm' );
  744. assert.ok( control.isFutureDate() );
  745. year( 2016 );
  746. assert.notOk( control.isFutureDate() );
  747. // Tear down.
  748. wp.customize.control.remove( controlId );
  749. });
  750. QUnit.module( 'Customize Sections: wp.customize.OuterSection' );
  751. QUnit.test( 'Test OuterSection', function( assert ) {
  752. var section, sectionId = 'test_outer_section', body = jQuery( 'body' ),
  753. defaultSection, defaultSectionId = 'fixture-section';
  754. defaultSection = wp.customize.section( defaultSectionId );
  755. section = new wp.customize.OuterSection( sectionId, {
  756. params: {
  757. content: defaultSection.params.content,
  758. type: 'outer'
  759. }
  760. } );
  761. wp.customize.section.add( sectionId, section );
  762. wp.customize.section.add( defaultSectionId, section );
  763. assert.equal( section.containerPaneParent, '.customize-outer-pane-parent' );
  764. assert.equal( section.containerParent.selector, '#customize-outer-theme-controls' );
  765. defaultSection.expand();
  766. section.expand();
  767. assert.ok( body.hasClass( 'outer-section-open' ) );
  768. assert.ok( section.container.hasClass( 'open' ) );
  769. assert.ok( defaultSection.expanded() ); // Ensure it does not affect other sections state.
  770. section.collapse();
  771. assert.notOk( body.hasClass( 'outer-section-open' ) );
  772. assert.notOk( section.container.hasClass( 'open' ) ); // Ensure it does not affect other sections state.
  773. assert.ok( defaultSection.expanded() );
  774. // Tear down.
  775. wp.customize.section.remove( sectionId );
  776. });
  777. QUnit.module( 'Customize Controls: PreviewLinkControl' );
  778. QUnit.test( 'Test PreviewLinkControl creation and its methods', function( assert ) {
  779. var section, sectionId = 'publish_settings', newLink;
  780. section = wp.customize.section( sectionId );
  781. section.deferred.embedded.resolve();
  782. assert.expect( 9 );
  783. section.deferred.embedded.done( function() {
  784. _.each( section.controls(), function( control ) {
  785. if ( 'changeset_preview_link' === control.id ) {
  786. assert.equal( control.templateSelector, 'customize-preview-link-control' );
  787. assert.equal( _.size( control.previewElements ), control.elements.length );
  788. // Test control.ready().
  789. newLink = 'http://example.org?' + wp.customize.settings.changeset.uuid;
  790. control.setting.set( newLink );
  791. assert.equal( control.previewElements.input(), newLink );
  792. assert.equal( control.previewElements.url(), newLink );
  793. assert.equal( control.previewElements.url.element.parent().attr( 'href' ), newLink );
  794. assert.equal( control.previewElements.url.element.parent().attr( 'target' ), wp.customize.settings.changeset.uuid );
  795. // Test control.toggleSaveNotification().
  796. control.toggleSaveNotification( true );
  797. assert.ok( control.notifications.has( 'changes_not_saved' ) );
  798. control.toggleSaveNotification( false );
  799. assert.notOk( control.notifications.has( 'changes_not_saved' ) );
  800. // Test control.updatePreviewLink().
  801. control.updatePreviewLink();
  802. assert.equal( control.setting.get(), wp.customize.previewer.getFrontendPreviewUrl() );
  803. }
  804. } );
  805. } );
  806. });
  807. });