PageRenderTime 66ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 0ms

/wp-content/plugins/menu-icons/js/admin.js

https://bitbucket.org/ChendeyY/docklandsmedia
JavaScript | 1082 lines | 832 code | 203 blank | 47 comment | 51 complexity | 9fc584b2bd82b07e64af803a1357f205 MD5 | raw file
Possible License(s): GPL-2.0
  1. /* global jQuery, wp, window: false, Backbone: false, _: false */
  2. /**
  3. * Menu Icons
  4. *
  5. * @author Dzikri Aziz <kvcrvt@gmail.com>
  6. * @version 0.1.0
  7. *
  8. */
  9. ( function( $ ) {
  10. 'use strict';
  11. $.inputDependencies( {
  12. selector: 'select.hasdep',
  13. disable: false
  14. });
  15. /**
  16. * Settings box tabs
  17. *
  18. * We can't use core's tabs script here because it will clear the
  19. * checkboxes upon tab switching
  20. */
  21. $( '#menu-icons-settings-tabs' )
  22. .on( 'click', 'a.mi-settings-nav-tab', function( e ) {
  23. e.preventDefault();
  24. e.stopPropagation();
  25. var $el = $( this ).blur(),
  26. $target = $( '#' + $el.data( 'type' ) );
  27. $el.parent().addClass( 'tabs' ).siblings().removeClass( 'tabs' );
  28. $target
  29. .removeClass( 'tabs-panel-inactive' )
  30. .addClass( 'tabs-panel-active' )
  31. .show()
  32. .siblings( 'div.tabs-panel' )
  33. .hide()
  34. .addClass( 'tabs-panel-inactive' )
  35. .removeClass( 'tabs-panel-active' );
  36. })
  37. .find( 'a.mi-settings-nav-tab' ).first().click();
  38. if ( _.isUndefined( window.menuIcons ) ) {
  39. return;
  40. }
  41. if ( _.isUndefined( window.menuIcons.iconTypes ) ) {
  42. return;
  43. }
  44. window.menuIcons = _.defaults( {
  45. frame: '',
  46. currentItem: {},
  47. toggleSelect: function( e ) {
  48. var $type = $( e.currentTarget ),
  49. $wrapr = $type.closest( 'div.menu-icons-wrap' ),
  50. $select = $wrapr.find( 'a._select' ),
  51. $remove = $wrapr.find( 'a._remove' );
  52. if ( '' !== $type.val() ) {
  53. $remove.show();
  54. } else {
  55. $select.text( $select.data( 'text' ) );
  56. $remove.hide();
  57. }
  58. },
  59. selectIcon: function( e ) {
  60. e.preventDefault();
  61. e.stopPropagation();
  62. var $el = $( this ),
  63. id = media.view.settings.post.id = $el.data( 'id' ),
  64. attrs;
  65. attrs = {
  66. id: id,
  67. title: $( '#edit-menu-item-title-' + id ).val()
  68. };
  69. $el.closest( 'div.menu-icons-wrap' ).find( ':input' ).each( function( i, input ) {
  70. var key = $( input ).data( 'key' );
  71. attrs[ key ] = input.value;
  72. });
  73. window.menuIcons.currentItem = attrs;
  74. if ( ! ( window.menuIcons.frame instanceof media.view.MediaFrame.menuIcons ) ) {
  75. window.menuIcons.frame = new media.view.MediaFrame.menuIcons();
  76. }
  77. window.menuIcons.frame.open();
  78. },
  79. removeIcon: function( e ) {
  80. e.preventDefault();
  81. e.stopPropagation();
  82. var id = $( this ).data( 'id' );
  83. $( '#menu-icons-' + id + '-type' ).val( '' ).trigger( 'mi:update' );
  84. }
  85. }, window.menuIcons );
  86. // WP Media
  87. var media = wp.media,
  88. Attachment = media.model.Attachment;
  89. // Models
  90. media.model.mi = {};
  91. // Model: Menu Items
  92. media.model.mi.MenuItems = Backbone.Collection.extend({
  93. props: new Backbone.Model({ item: '' }),
  94. model: Backbone.Model.extend({
  95. defaults: {
  96. type: '',
  97. group: 'all',
  98. icon: ''
  99. }
  100. })
  101. });
  102. // Model: Settings fields
  103. media.model.mi.MenuItems.Settings = Backbone.Collection.extend({
  104. model: Backbone.Model.extend({
  105. defaults: {
  106. id: '',
  107. label: '',
  108. value: '',
  109. type: 'text'
  110. }
  111. })
  112. });
  113. // All: Sidebar
  114. media.view.miSidebar = media.view.Sidebar.extend({
  115. initialize: function() {
  116. var title = new media.View({
  117. tagName: 'h3',
  118. priority: -10
  119. });
  120. var info = new media.View({
  121. tagName: 'p',
  122. className: '_info',
  123. priority: 1000
  124. });
  125. media.view.Sidebar.prototype.initialize.apply( this, arguments );
  126. title.$el.text( window.menuIcons.text.preview );
  127. this.set( 'title', title );
  128. info.$el.html( window.menuIcons.text.settingsInfo );
  129. this.set( 'info', info );
  130. }
  131. });
  132. // View: Settings wrapper
  133. media.view.miSidebar.Settings = media.view.PriorityList.extend({
  134. className: 'mi-settings attachment-info',
  135. prepare: function() {
  136. _.each( this.collection.map( this.createField, this ), function( view ) {
  137. this.set( view.model.id, view );
  138. }, this );
  139. },
  140. createField: function( model ) {
  141. var field = new media.view.miSidebar.Settings.Field({
  142. item: this.model,
  143. model: model,
  144. collection: this.collection
  145. });
  146. return field;
  147. }
  148. });
  149. // View: Settings field
  150. media.view.miSidebar.Settings.Field = media.View.extend({
  151. tagName: 'label',
  152. className: 'setting',
  153. events: {
  154. 'change :input': '_update'
  155. },
  156. initialize: function() {
  157. media.View.prototype.initialize.apply( this, arguments );
  158. this.template = media.template( 'menu-icons-settings-field-' + this.model.get( 'type' ) );
  159. this.model.on( 'change', this.render, this );
  160. },
  161. prepare: function() {
  162. return this.model.toJSON();
  163. },
  164. _update: function( e ) {
  165. var item = this.options.item,
  166. $input = $( e.currentTarget ),
  167. value = $input.val(),
  168. $field = $( '#menu-icons-' + item.id + '-' + this.model.id + '._setting' );
  169. this.model.set( 'value', value );
  170. item.set( this.model.id, value );
  171. $field.val( value ).trigger( 'mi:update' );
  172. }
  173. });
  174. // View: Item preview on the sidebar
  175. media.view.miPreview = media.View.extend({
  176. tagName: 'p',
  177. className: 'mi-preview menu-item attachment-info',
  178. events: {
  179. 'click a': 'preventDefault'
  180. },
  181. initialize: function() {
  182. media.View.prototype.initialize.apply( this, arguments );
  183. this.model.on( 'change', this.render, this );
  184. },
  185. render: function() {
  186. var data = _.extend( this.model.toJSON(), this.options.data ),
  187. template = 'menu-icons-' + data.type + '-preview-';
  188. if ( data.hide_label ) {
  189. template += 'hide_label';
  190. } else {
  191. template += data.position;
  192. }
  193. this.template = media.template( template );
  194. this.$el.html( this.template( data ) );
  195. return this;
  196. },
  197. preventDefault: function( e ) {
  198. e.preventDefault();
  199. }
  200. });
  201. // Methods for the browser view
  202. media.view.miBrowser = {
  203. createSidebar: function() {
  204. var options = this.options;
  205. var selection = options.selection;
  206. var sidebar = this.sidebar = new media.view.miSidebar({
  207. controller: this.controller,
  208. type: options.type
  209. });
  210. this.views.add( sidebar );
  211. selection.on( 'selection:single', this.createSingle, this );
  212. selection.on( 'selection:unsingle', this.disposeSingle, this );
  213. if ( selection.single() ) {
  214. this.createSingle();
  215. }
  216. },
  217. createSingle: function() {
  218. this.createPreview();
  219. },
  220. createSettings: function() {
  221. var item = this.controller.miGetCurrentItem(),
  222. fields = this.model.get( 'settings' );
  223. if ( ! fields.length ) {
  224. return;
  225. }
  226. _.each( fields, function( field ) {
  227. field.value = item.get( field.id );
  228. } );
  229. this.sidebar.set( 'settings', new media.view.miSidebar.Settings({
  230. controller: this.controller,
  231. collection: new media.model.mi.MenuItems.Settings( fields ),
  232. model: item,
  233. type: this.options.type,
  234. priority: 120
  235. }) );
  236. }
  237. };
  238. // View: Font icon: Browser
  239. media.view.miFont = media.View.extend({
  240. className: 'attachments-browser mi-items-wrap',
  241. initialize: function() {
  242. this.createToolbar();
  243. this.createLibrary();
  244. this.createSidebar();
  245. },
  246. createLibrary: function() {
  247. this.items = new media.view.miFont.Library({
  248. controller: this.controller,
  249. collection: this.collection,
  250. selection: this.options.selection,
  251. type: this.options.type,
  252. data: this.options.data
  253. });
  254. this.views.add( this.items );
  255. },
  256. createToolbar: function() {
  257. this.toolbar = new media.view.Toolbar({
  258. controller: this.controller
  259. });
  260. this.views.add( this.toolbar );
  261. // Dropdown filter
  262. this.toolbar.set( 'filters', new media.view.miFont.Filters({
  263. controller: this.controller,
  264. model: this.collection.props,
  265. priority: -80
  266. }).render() );
  267. // Search field
  268. this.toolbar.set( 'search', new media.view.Search({
  269. controller: this.controller,
  270. model: this.collection.props,
  271. priority: 60
  272. }).render() );
  273. },
  274. createPreview: function() {
  275. var controller = this.controller,
  276. menuItem = controller.miGetCurrentItem(),
  277. selected = this.model.get( 'selection' ).single();
  278. this.createSettings();
  279. this.sidebar.set( 'preview', new media.view.miPreview({
  280. controller: controller,
  281. model: menuItem,
  282. priority: 80,
  283. data: {
  284. type: selected.get( 'type' ),
  285. icon: selected.id
  286. }
  287. }) );
  288. },
  289. disposeSingle: function() {
  290. var sidebar = this.sidebar;
  291. sidebar.unset( 'preview' );
  292. sidebar.unset( 'settings' );
  293. }
  294. });
  295. _.extend( media.view.miFont.prototype, media.view.miBrowser );
  296. // View: Font icon: Library
  297. media.view.miFont.Library = media.View.extend({
  298. tagName: 'ul',
  299. className: 'attachments mi-items clearfix',
  300. initialize: function() {
  301. this._viewsByCid = {};
  302. this.collection.on( 'reset', this.refresh, this );
  303. this.controller.on( 'open', this.scrollToSelected, this );
  304. },
  305. render: function() {
  306. this.collection.each( function( model ) {
  307. this.views.add( this.renderItem( model ), {
  308. at: this.collection.indexOf( model )
  309. } );
  310. }, this );
  311. return this;
  312. },
  313. renderItem: function( model ) {
  314. var view = new media.view.miFont.Icon({
  315. controller: this.controller,
  316. model: model,
  317. collection: this.collection,
  318. selection: this.options.selection,
  319. type: this.options.type,
  320. data: this.options.data
  321. });
  322. return this._viewsByCid[ view.cid ] = view;
  323. },
  324. clearItems: function() {
  325. _.each( this._viewsByCid, function( view ) {
  326. delete this._viewsByCid[ view.cid ];
  327. view.remove();
  328. }, this );
  329. },
  330. refresh: function() {
  331. this.clearItems();
  332. this.render();
  333. },
  334. ready: function() {
  335. this.scrollToSelected();
  336. },
  337. scrollToSelected: function() {
  338. var single = this.options.selection.single(),
  339. singleView;
  340. if ( ! single ) {
  341. return;
  342. }
  343. singleView = this.getView( single );
  344. if ( singleView && ! this.isInView( singleView.$el ) ) {
  345. this.$el.scrollTop( singleView.$el.offset().top - this.$el.offset().top + this.$el.scrollTop() - parseInt( this.$el.css( 'paddingTop' ), 10 ) );
  346. }
  347. },
  348. getView: function( model ) {
  349. return _.findWhere( this._viewsByCid, { model: model } );
  350. },
  351. isInView: function( $elem ) {
  352. var $window = $( window ),
  353. docViewTop = $window.scrollTop(),
  354. docViewBottom = docViewTop + $window.height(),
  355. elemTop = $elem.offset().top,
  356. elemBottom = elemTop + $elem.height();
  357. return ( ( elemBottom <= docViewBottom ) && ( elemTop >= docViewTop ) );
  358. }
  359. });
  360. // View: Font icon: Dropdown filter
  361. media.view.miFont.Filters = media.view.AttachmentFilters.extend({
  362. createFilters: function() {
  363. this.filters = {
  364. all: {
  365. text: window.menuIcons.text.all,
  366. props: {
  367. group: 'all'
  368. }
  369. }
  370. };
  371. var groups = this.controller.state().get( 'data' ).groups;
  372. _.each( groups, function( text, id ) {
  373. this.filters[ id ] = {
  374. text: text,
  375. props: {
  376. group: id
  377. }
  378. };
  379. }, this );
  380. },
  381. change: function() {
  382. var filter = this.filters[ this.el.value ];
  383. if ( filter ) {
  384. this.model.set( 'group', filter.props.group );
  385. }
  386. }
  387. });
  388. // View: Font icon: Item
  389. media.view.miFont.Icon = media.view.Attachment.extend({
  390. className: 'attachment mi-item',
  391. events: {
  392. 'click .attachment-preview': 'toggleSelectionHandler',
  393. 'click a': 'preventDefault'
  394. },
  395. initialize: function() {
  396. this.template = media.template( 'menu-icons-' + this.options.type + '-item' );
  397. media.view.Attachment.prototype.initialize.apply( this, arguments );
  398. },
  399. render: function() {
  400. this.$el.html( this.template( this.model.toJSON() ) );
  401. this.updateSelect();
  402. return this;
  403. }
  404. });
  405. // Font icon state
  406. media.controller.miFont = media.controller.State.extend({
  407. defaults: {
  408. id: 'mi-font',
  409. menu: 'default',
  410. toolbar: 'mi-select',
  411. type: '',
  412. settings: [ 'hide_label', 'position', 'font_size', 'vertical_align' ]
  413. },
  414. initialize: function() {
  415. var icons = this.get( 'data' ).items,
  416. library = this.get( 'library' ),
  417. selection = this.get( 'selection' ),
  418. fieldIds = this.get( 'settings' ),
  419. fields;
  420. if ( ! ( library instanceof media.controller.miFont.Library ) ) {
  421. library = new media.controller.miFont.Library( icons );
  422. library.props.on( 'change', this.miResetLibrary, this );
  423. this.set( 'library', library );
  424. }
  425. if ( ! ( selection instanceof media.model.Selection ) ) {
  426. this.set( 'selection', new media.model.Selection( selection, {
  427. multiple: false
  428. }) );
  429. }
  430. fields = _.filter( window.menuIcons.settingsFields, function( field ) {
  431. return ( -1 !== $.inArray( field.id, fieldIds ) );
  432. });
  433. this.set( 'settings', fields );
  434. },
  435. activate: function() {
  436. this.frame.on( 'open', this.refresh, this );
  437. this.miUpdateSelection();
  438. },
  439. deactivate: function() {
  440. media.controller.State.prototype.deactivate.apply( this, arguments );
  441. this.frame.off( 'open', this.refresh, this );
  442. },
  443. refresh: function() {
  444. this.miResetFilter();
  445. this.miUpdateSelection();
  446. },
  447. miGetContent: function() {
  448. this.miResetFilter();
  449. return new media.view.miFont({
  450. controller: this.frame,
  451. model: this,
  452. collection: this.get( 'library' ),
  453. selection: this.get( 'selection' ),
  454. type: this.get( 'type' )
  455. });
  456. },
  457. miResetLibrary: function() {
  458. var library = this.get( 'library' ),
  459. group = library.props.get( 'group' ),
  460. item = this.frame.miGetCurrentItem();
  461. item.set( 'group', group );
  462. library.reInitialize();
  463. this.set( 'library', library );
  464. this.miUpdateSelection();
  465. },
  466. miResetFilter: function() {
  467. var library = this.get( 'library' ),
  468. item = this.frame.miGetCurrentItem(),
  469. groups = this.get( 'data' ).groups,
  470. group = item.get( 'group' );
  471. if ( _.isUndefined( groups[ group ] ) ) {
  472. group = 'all';
  473. }
  474. library.props.set( 'group', group );
  475. },
  476. miUpdateSelection: function() {
  477. var selection = this.get( 'selection' ),
  478. type = this.get( 'type' ),
  479. key = type + '-icon',
  480. item = this.frame.miGetCurrentItem(),
  481. icon = item.get( key ),
  482. selected;
  483. if ( type === item.get( 'type' ) && icon ) {
  484. selected = this.get( 'library' ).findWhere({ id: icon });
  485. }
  486. selection.reset( selected ? selected : [] );
  487. }
  488. });
  489. // Font icon collection
  490. media.controller.miFont.Library = Backbone.Collection.extend({
  491. props: new Backbone.Model({
  492. group: 'all',
  493. search: ''
  494. }),
  495. initialize: function( models ) {
  496. this.icons = new Backbone.Collection( models );
  497. },
  498. reInitialize: function() {
  499. var library = this,
  500. icons = this.icons.toJSON(),
  501. props = this.props.toJSON();
  502. _.each( props, function( val, filter ) {
  503. if ( library.filters[ filter ] ) {
  504. icons = _.filter( icons, library.filters[ filter ], val );
  505. }
  506. }, this );
  507. this.reset( icons );
  508. },
  509. filters: {
  510. group: function( icon ) {
  511. var group = this;
  512. return ( 'all' === group || icon.group === group || '' === icon.group );
  513. },
  514. search: function( icon ) {
  515. var term = this,
  516. result;
  517. if ( '' === term ) {
  518. result = true;
  519. } else {
  520. result = _.any( [ 'id', 'label' ], function( key ) {
  521. var value = icon[ key ];
  522. return value && -1 !== value.search( this );
  523. }, term );
  524. }
  525. return result;
  526. }
  527. }
  528. });
  529. // Image icon state
  530. media.controller.miImage = media.controller.Library.extend({
  531. defaults: _.defaults({
  532. id: 'browse',
  533. menu: 'default',
  534. router: 'browse',
  535. toolbar: 'mi-select',
  536. filterable: 'uploaded',
  537. settings: [ 'hide_label', 'position', 'image_size', 'vertical_align' ],
  538. syncSelection: false
  539. }, media.controller.Library.prototype.defaults ),
  540. initialize: function( options ) {
  541. var selection = this.get( 'selection' ),
  542. fieldIds = this.get( 'settings' ),
  543. fields;
  544. if ( ! options.data.browserView ) {
  545. options.data.browserView = 'miImage';
  546. }
  547. this.options = options;
  548. this.set( 'library', media.query( options.data.library ) );
  549. this.routers = {
  550. upload: {
  551. text: media.view.l10n.uploadFilesTitle,
  552. priority: 20
  553. },
  554. browse: {
  555. text: media.view.l10n.mediaLibraryTitle,
  556. priority: 40
  557. }
  558. };
  559. if ( ! ( selection instanceof media.model.Selection ) ) {
  560. this.set( 'selection', new media.model.Selection( selection, {
  561. multiple: false
  562. }) );
  563. }
  564. fields = _.filter( window.menuIcons.settingsFields, function( field ) {
  565. return ( -1 !== $.inArray( field.id, fieldIds ) );
  566. });
  567. this.set( 'settings', fields );
  568. media.controller.Library.prototype.initialize.apply( this, arguments );
  569. },
  570. activate: function() {
  571. media.controller.Library.prototype.activate.apply( this, arguments );
  572. this.frame.on( 'open', this.miUpdateSelection, this );
  573. this.get( 'library' ).observe( wp.Uploader.queue );
  574. this.miUpdateSelection();
  575. },
  576. deactivate: function() {
  577. media.controller.Library.prototype.deactivate.apply( this, arguments );
  578. this.get( 'library' ).unobserve( wp.Uploader.queue );
  579. this.frame.off( 'open', this.miUpdateSelection, this );
  580. },
  581. miUpdateSelection: function() {
  582. var selection = this.get( 'selection' ),
  583. type = this.get( 'type' ),
  584. key = type + '-icon',
  585. item = this.frame.miGetCurrentItem(),
  586. icon = item.get( key ),
  587. attachment;
  588. if ( type === item.get( 'type' ) && icon ) {
  589. attachment = Attachment.get( icon );
  590. this.dfd = attachment.fetch();
  591. }
  592. selection.add( attachment ? attachment : [] );
  593. },
  594. miGetContent: function( mode ) {
  595. var content = ( 'upload' === mode ) ? this.uploadContent() : this.browseContent();
  596. this.frame.$el.removeClass( 'hide-toolbar' );
  597. return content;
  598. },
  599. browseContent: function() {
  600. var state = this,
  601. type = state.get( 'type' ),
  602. options;
  603. options = {
  604. type: type,
  605. controller: state.frame,
  606. collection: state.get( 'library' ),
  607. selection: state.get( 'selection' ),
  608. model: state,
  609. sortable: state.get( 'sortable' ),
  610. search: state.get( 'searchable' ),
  611. filters: state.get( 'filterable' ),
  612. display: state.get( 'displaySettings' ),
  613. dragInfo: state.get( 'dragInfo' ),
  614. idealColumnWidth: state.get( 'idealColumnWidth' ),
  615. suggestedWidth: state.get( 'suggestedWidth' ),
  616. suggestedHeight: state.get( 'suggestedHeight' ),
  617. AttachmentView: state.get( 'AttachmentView' )
  618. };
  619. if ( 'svg' === type ) {
  620. options.AttachmentView = media.view.Attachment.miSvg;
  621. }
  622. return new media.view.AttachmentsBrowser.miImage( options );
  623. },
  624. /**
  625. * Render callback for the content region in the `upload` mode.
  626. */
  627. uploadContent: function() {
  628. return new media.view.UploaderInline({
  629. controller: this.frame
  630. });
  631. }
  632. });
  633. // SVG icon state
  634. media.controller.miSvg = media.controller.miImage.extend({
  635. defaults: _.defaults({
  636. settings: [ 'hide_label', 'position', 'vertical_align', 'width' ]
  637. }, media.controller.miImage.prototype.defaults )
  638. });
  639. // View: Image Icon: Browser
  640. media.view.AttachmentsBrowser.miImage = media.view.AttachmentsBrowser.extend({
  641. disposeSingle: function() {
  642. media.view.AttachmentsBrowser.prototype.disposeSingle.apply( this, arguments );
  643. this.sidebar.unset( 'preview' );
  644. this.sidebar.unset( 'settings' );
  645. },
  646. createPreview: function() {
  647. var self = this,
  648. state = this.model,
  649. selected, controller, menuItem;
  650. if ( state.dfd && 'pending' === state.dfd.state() ) {
  651. state.dfd.done( function() {
  652. self.createPreview();
  653. } );
  654. return;
  655. }
  656. selected = state.get( 'selection' ).single();
  657. // Disallow anything but image
  658. if ( 'image' !== selected.get( 'type' ) ) {
  659. state.get( 'selection' ).reset();
  660. return;
  661. }
  662. // Wait for the upload process to finish
  663. if ( selected.get( 'uploading' ) ) {
  664. selected.on( 'change:uploading', self.createPreview, this );
  665. return;
  666. }
  667. controller = this.controller;
  668. menuItem = controller.miGetCurrentItem();
  669. this.createSettings();
  670. this.sidebar.set( 'preview', new media.view.miPreview.miImage({
  671. controller: controller,
  672. settings: this.sidebar.get( 'settings' ),
  673. model: menuItem,
  674. priority: 80,
  675. data: {
  676. type: state.get( 'type' ),
  677. alt: selected.get( 'alt' ),
  678. sizes: selected.get( 'sizes' ),
  679. url: selected.get( 'url' )
  680. }
  681. }) );
  682. }
  683. });
  684. _.extend( media.view.AttachmentsBrowser.miImage.prototype, media.view.miBrowser );
  685. // View: SVG item
  686. media.view.Attachment.miSvg = media.view.Attachment.Library.extend({
  687. template: wp.template( 'menu-icons-svg-item' )
  688. });
  689. // View: Image Icon: Preview on the sidebar
  690. media.view.miPreview.miImage = media.view.miPreview.extend({
  691. render: function() {
  692. var size = this.options.model.get( 'image_size' ),
  693. imageSizes = this.options.data.sizes,
  694. sizeField = this.options.settings.get( 'image_size' ),
  695. newChoices = [];
  696. if ( ! _.isUndefined( imageSizes ) && ! _.isUndefined( sizeField ) ) {
  697. if ( ! imageSizes.hasOwnProperty( size ) ) {
  698. size = 'full';
  699. }
  700. _.each( sizeField.model.get( 'choices' ), function( choice ) {
  701. if ( imageSizes.hasOwnProperty( choice.value ) ) {
  702. newChoices.push( choice );
  703. }
  704. } );
  705. this.options.data.url = imageSizes[ size ].url;
  706. sizeField.model.set( 'choices', newChoices );
  707. this.options.model.set( 'image_size', size, { silent: true } );
  708. }
  709. return media.view.miPreview.prototype.render.apply( this, arguments );
  710. }
  711. });
  712. // Frame
  713. media.view.MediaFrame.menuIcons = media.view.MediaFrame.extend({
  714. defaults: _.defaults({
  715. selection: [],
  716. multiple: false,
  717. editing: false,
  718. toolbar: 'mi-select'
  719. }, media.view.MediaFrame.prototype.defaults ),
  720. initialize: function() {
  721. media.view.MediaFrame.prototype.initialize.apply( this, arguments );
  722. this.miMenuItems = new media.model.mi.MenuItems();
  723. this.createStates();
  724. this.bindHandlers();
  725. },
  726. createStates: function() {
  727. var options = this.options,
  728. Controller;
  729. if ( options.states ) {
  730. return;
  731. }
  732. _.each( window.menuIcons.iconTypes, function( props, type ) {
  733. if ( ! media.controller.hasOwnProperty( props.data.controller ) ) {
  734. delete window.menuIcons.iconTypes[ type ];
  735. return;
  736. }
  737. Controller = media.controller[ props.data.controller ];
  738. _.defaults( props, {
  739. content: props.id,
  740. selection: options.selection
  741. });
  742. // States
  743. this.states.add( new Controller( props ) );
  744. }, this );
  745. },
  746. bindHandlers: function() {
  747. this.on( 'router:create:browse', this.createRouter, this );
  748. this.on( 'router:render:browse', this.browseRouter, this );
  749. this.on( 'content:render', this.miRenderContent, this );
  750. this.on( 'toolbar:create:mi-select', this.createToolbar, this );
  751. this.on( 'toolbar:render:mi-select', this.miSelectToolbar, this );
  752. this.on( 'open', this.miInitialize, this );
  753. },
  754. browseRouter: function( routerView ) {
  755. var routers = this.state().routers;
  756. if ( routers ) {
  757. routerView.set( routers );
  758. }
  759. },
  760. miRenderContent: function() {
  761. var state = this.state(),
  762. mode = this.content.mode(),
  763. content = state.miGetContent( mode );
  764. this.content.set( content );
  765. },
  766. // Toolbars
  767. miSelectToolbar: function( view ) {
  768. var frame = this,
  769. state = frame.state();
  770. view.set( state.id, {
  771. style: 'primary',
  772. priority: 80,
  773. text: window.menuIcons.text.select,
  774. requires: {
  775. selection: true
  776. },
  777. click: function() {
  778. frame.close();
  779. frame.miUpdateItemProps();
  780. frame.miUpdateItem();
  781. }
  782. });
  783. },
  784. // Content
  785. miContentRender: function() {
  786. var state = this.state(),
  787. content = state.miGetContent();
  788. this.content.set( content );
  789. },
  790. miGetState: function() {
  791. var item = window.menuIcons.currentItem,
  792. type;
  793. if ( ! _.isUndefined( item.type ) && '' !== item.type && window.menuIcons.iconTypes.hasOwnProperty( item.type ) ) {
  794. type = item.type;
  795. } else {
  796. type = window.menuIcons.typeNames[0];
  797. }
  798. return 'mi-' + type;
  799. },
  800. miGetCurrentItem: function() {
  801. return this.miMenuItems.get( window.menuIcons.currentItem.id );
  802. },
  803. miUpdateMenuItems: function() {
  804. var item = this.miGetCurrentItem();
  805. if ( _.isUndefined( item ) ) {
  806. this.miMenuItems.add( window.menuIcons.currentItem );
  807. } else {
  808. item.set( window.menuIcons.currentItem );
  809. }
  810. this.miMenuItems.props.set( 'item', window.menuIcons.currentItem.id );
  811. },
  812. miInitialize: function() {
  813. this.miUpdateMenuItems();
  814. this.setState( this.miGetState() );
  815. },
  816. miUpdateItemProps: function() {
  817. var state = this.state(),
  818. type = state.get( 'type' ),
  819. selection = state.get( 'selection' ),
  820. single = selection.single(),
  821. icon = single ? single.id : '',
  822. item = this.miGetCurrentItem();
  823. item.set( 'type', type );
  824. item.set( type + '-icon', icon );
  825. item.set( 'icon', icon );
  826. },
  827. miUpdateItem: function() {
  828. var attrs = this.miGetCurrentItem().toJSON(),
  829. id = attrs.id,
  830. state = this.state(),
  831. selected = state.get( 'selection' ).single(),
  832. template = media.template( 'menu-icons-' + attrs.type + '-field' ),
  833. data = selected.toJSON(),
  834. $el;
  835. data._settings = attrs;
  836. delete attrs.id;
  837. delete attrs.title;
  838. _.each( attrs, function( value, key ) {
  839. $el = $( '#menu-icons-' + id + '-' + key ).not( '._setting' );
  840. if ( $el.length ) {
  841. $el.val( value ).trigger( 'mi:update' );
  842. }
  843. });
  844. $( '#menu-icons-' + id + '-select' ).html( template( data ) );
  845. }
  846. });
  847. $( 'body' )
  848. .on( 'click', 'div.menu-icons-wrap a._select', window.menuIcons.selectIcon )
  849. .on( 'click', 'div.menu-icons-wrap a._remove', window.menuIcons.removeIcon )
  850. .on( 'mi:update', 'div.menu-icons-wrap select._type', window.menuIcons.toggleSelect );
  851. $( 'div.menu-icons-wrap select._type' ).trigger( 'mi:update' );
  852. // Settings meta box
  853. $( '#menu-item-settings-save' ).on( 'click', function( e ) {
  854. var $button = $( this ).prop( 'disabled', true ),
  855. $spinner = $button.siblings( 'span.spinner' );
  856. e.preventDefault();
  857. $spinner.css( 'display', 'inline-block' );
  858. $.ajax({
  859. type: 'POST',
  860. url: window.menuIcons.ajaxUrls.update,
  861. data: $( '#menu-icons-settings :input' ).serialize(),
  862. success: function( response ) {
  863. if ( true === response.success && response.data.redirectUrl ) {
  864. window.location = response.data.redirectUrl;
  865. } else {
  866. $button.prop( 'disabled', false );
  867. }
  868. },
  869. always: function() {
  870. $spinner.hide();
  871. }
  872. });
  873. });
  874. // A hack to prevent error because of the click callback set by wp-admin/js/nav-menu.js#811
  875. $( '#update-nav-menu svg' ).bind( 'click', function() {
  876. $( this ).closest( 'a' ).trigger( 'click' );
  877. return false;
  878. } );
  879. }( jQuery ) );