PageRenderTime 53ms CodeModel.GetById 10ms RepoModel.GetById 0ms app.codeStats 1ms

/t/upfront/elements/upfront-gallery/js/ugallery.js

https://bitbucket.org/matthewselby/wpdev
JavaScript | 1844 lines | 1476 code | 295 blank | 73 comment | 138 complexity | a3beffddf1955e3f729179a2060ae4c2 MD5 | raw file
Possible License(s): Apache-2.0, GPL-2.0, LGPL-3.0, LGPL-2.1, AGPL-1.0, BSD-3-Clause, MIT, GPL-3.0, MPL-2.0-no-copyleft-exception

Large files files are truncated, but you can click here to view the full file

  1. /*global ugalleries */
  2. (function ($) {
  3. define([
  4. 'text!elements/upfront-gallery/tpl/ugallery.html', // Front
  5. 'text!elements/upfront-gallery/tpl/sorting-style.html',
  6. 'text!elements/upfront-gallery/tpl/ugallery_editor.html',
  7. 'text!elements/upfront-gallery/tpl/lightbox_settings.html',
  8. 'elements/upfront-gallery/js/settings',
  9. 'elements/upfront-gallery/js/model',
  10. 'elements/upfront-gallery/js/label-editor',
  11. 'elements/upfront-gallery/js/element',
  12. 'text!elements/upfront-gallery/tpl/preset-style.html',
  13. 'scripts/upfront/preset-settings/util',
  14. "scripts/upfront/link-model"
  15. ], function(galleryTpl, sortingStyleTpl, editorTpl, lightboxTpl, UgallerySettings, UgalleryModel, LabelEditor, UgalleryElement, settingsStyleTpl, PresetUtil, LinkModel) {
  16. var l10n = Upfront.Settings.l10n.gallery_element;
  17. var globalL10n = Upfront.Settings && Upfront.Settings.l10n
  18. ? Upfront.Settings.l10n.global.views
  19. : Upfront.mainData.l10n.global.views;
  20. var UgalleryImage = Backbone.Model.extend({
  21. defaults: Upfront.data.ugallery.imageDefaults,
  22. is_theme_image: function () {
  23. return this.get('srcFull') && this.get('srcFull').match(Upfront.mainData.currentThemePath);
  24. }
  25. });
  26. var UgalleryImages = Backbone.Collection.extend({
  27. model: UgalleryImage
  28. });
  29. /* View */
  30. var UgalleryView = Upfront.Views.ObjectView.extend({
  31. model: UgalleryModel,
  32. tpl: Upfront.Util.template(galleryTpl), //PHP compatible templates
  33. selectorTpl: _.template($(editorTpl).find('#selector-tpl').html()),
  34. progressTpl: _.template($(editorTpl).find('#progress-tpl').html()),
  35. editorTpl: _.template($(editorTpl).find('#editor-tpl').html()),
  36. formTpl: _.template($(editorTpl).find('#upload-form-tpl').html()),
  37. detailsTpl: _.template($(editorTpl).find('#details-tpl').html()),
  38. sortMode: false,
  39. lastThumbnailSize: false,
  40. imageLabels: {},
  41. reopenSettings: false,
  42. initialize: function(options){
  43. var me = this,
  44. elementId = this.property('element_id'),
  45. raw_labels,
  46. images;
  47. if (this.property('thumbPadding') !== this.property('thumbPaddingNumber')) {
  48. this.property('thumbPaddingNumber', this.property('thumbPadding'), true);
  49. this.property('thumbSidePaddingNumber', this.property('thumbPadding'), true);
  50. this.property('sidePadding', this.property('thumbPadding'), true);
  51. this.property('bottomPadding', this.property('thumbPadding'), true);
  52. this.property('thumbSidePadding', this.property('thumbPadding'), true);
  53. this.property('thumbBottomPaddingNumber', this.property('thumbPadding'), true);
  54. }
  55. if (_.isArray(this.property('labelFilters')) && this.property('labelFilters')[0] === 'true') {
  56. this.property('labelFilters', 'true', true);
  57. }
  58. if(! (this.model instanceof UgalleryModel)){
  59. this.model = new UgalleryModel({properties: this.model.get('properties')});
  60. }
  61. this.constructor.__super__.initialize.call(this, [options]);
  62. this.events = _.extend({}, this.events, {
  63. 'click a.upfront-image-select': 'openImageSelector',
  64. 'click .add-item': 'openImageSelector',
  65. 'click .toggle-sorting': 'toggleSorting',
  66. 'click .ugallery_op_link': 'imageEditLink',
  67. 'click .ugallery_op_mask': 'imageEditMask',
  68. 'click .remove-image': 'removeImage',
  69. 'click .ugallery_item': 'selectItem',
  70. 'click .upfront-quick-swap': 'openImageSelector',
  71. 'click': 'preventNavigation',
  72. 'dblclick .ugallery-thumb-title': 'startCaptionEditor',
  73. 'click .ugallery_item_lightbox': 'openLightbox'
  74. });
  75. images = this.property('images');
  76. // Ensure images are using new linking
  77. _.each(images, function(image, index) {
  78. if (image.imageLink === false || typeof image.imageLink === 'undefined') {
  79. // Create imageLink from properties, backward compat
  80. images[index]['imageLink'] = {
  81. type: image.urlType,
  82. url: image.url,
  83. target: image.linkTarget
  84. };
  85. }
  86. });
  87. this.images = new UgalleryImages(images);
  88. this.listenTo(this.images, 'add remove reset change', this.imagesChanged);
  89. this.property('images', this.images.toJSON()); // Hack to add image defaults;
  90. if (typeof this.property('thumbPadding') === 'undefined') {
  91. this.property('thumbPadding', 15);
  92. }
  93. $('body').on('click', this.closeTooltip);
  94. this.listenTo(Upfront.Events, 'entity:settings:activate', this.closeTooltip);
  95. this.listenTo(Upfront.Events, 'entity:activated', this.closeTooltip);
  96. this.listenTo(Upfront.Events, 'entity:deactivated', this.closeTooltip);
  97. this.listenTo(Upfront.Events, 'entity:region:activated', this.closeTooltip);
  98. this.listenTo(Upfront.Events, 'upfront:layout_size:change_breakpoint', this.rebindShuffle);
  99. this.listenTo(Upfront.Events, "theme_colors:update", this.update_colors, this);
  100. this.listenTo(this.model, "preset:updated", this.preset_updated);
  101. this.listenTo(Upfront.Events, "preset:gallery:updated", this.caption_updated, this);
  102. this.listenTo(Upfront.Events, 'upfront:import_image:populate_theme_images', this.populate_theme_images);
  103. this.listenTo(Upfront.Events, 'upfront:import_image:imported', this.imported_theme_image);
  104. this.lastThumbnailSize = {width: this.property('thumbWidth'), height: this.property('thumbHeight')};
  105. if (typeof ugalleries !== 'undefined' && ugalleries[elementId]) {
  106. if(ugalleries[elementId].labels) {
  107. this.labels = ugalleries[elementId].labels;
  108. }
  109. if(ugalleries[elementId].image_labels) {
  110. this.imageLabels = ugalleries[elementId].image_labels;
  111. }
  112. } else {
  113. if ('undefined' === typeof ugalleries || !ugalleries) {
  114. ugalleries = {};
  115. }
  116. ugalleries[elementId] = {};
  117. raw_labels = ['All'];
  118. _.each(this.images.models, function(image) {
  119. raw_labels = _.union(raw_labels, image.get('tags'));
  120. });
  121. this.labels = [];
  122. _.each(raw_labels, function(label, index) {
  123. this.labels[index] = {
  124. id: index,
  125. text: label
  126. };
  127. }, this);
  128. this.imageLabels = {};
  129. _.each(this.images.models, function(image) {
  130. var imageLabels = [];
  131. _.each(this.labels, function(label) {
  132. if (_.indexOf(image.get('tags'), label.text) > -1) {
  133. imageLabels.push('label_' + label.id);
  134. }
  135. });
  136. this.imageLabels[image.get('id')] = 'label_0,' + imageLabels.join(',');
  137. }, this);
  138. ugalleries[elementId].labels = this.labels;
  139. ugalleries[elementId].imageLabels = this.imageLabels;
  140. }
  141. this.on('deactivated', this.sortCancel, this);
  142. this.listenTo(this.model, 'settings:closed', function(e){
  143. me.checkRegenerateThumbs(e);
  144. if (this.property('labelFilters') === 'true') {
  145. Upfront.frontFunctions.galleryBindShuffle();
  146. }
  147. });
  148. this.listenTo(this.model, 'change:thumbProportions', function() {
  149. me.onThumbChangeProportions();
  150. });
  151. this.listenTo(this.model, 'change:thumbWidth', function() {
  152. me.onThumbChangeSize();
  153. me.render();
  154. });
  155. this.listenTo(this.model, 'change:thumbPadding', function() {
  156. me.updateThumbPadding();
  157. });
  158. this.listenTo(this.model, 'change:even_padding', function() {
  159. me.updateEvenPadding();
  160. });
  161. this.listenTo(this.model, 'change:labelFilters', function() {
  162. me.updateShowFilters();
  163. });
  164. this.listenTo(this.model, 'change:showCaptionOnHover', function() {
  165. me.updateShowCaptionOnHover();
  166. });
  167. this.listenTo(this.model, 'change:captionType', function() {
  168. me.updateCaptionType();
  169. });
  170. this.listenTo(this.model, 'change:fitThumbCaptions', function() {
  171. me.updateFitThumbCaptions();
  172. });
  173. this.listenTo(this.model, 'change:thumbCaptionsHeight', function() {
  174. me.updateThumbCaptionsHeight();
  175. });
  176. if (this.property('status') !== 'ok' || !this.images.length) {
  177. this.property('has_settings', 0);
  178. }
  179. Upfront.Events.on('upfront:layout_size:change_breakpoint', function() {
  180. setTimeout(function() {
  181. me.render();
  182. }, 100);
  183. });
  184. this. debouncedRender = _.debounce(this.render, 300);
  185. this.debouncedRebindShuffle = _.debounce(this.rebindShuffleForDebouncing, 500);
  186. this.delegateEvents();
  187. },
  188. onThumbChangeProportions: function(e) {
  189. var factor = this.property('thumbProportions'),
  190. width = this.property('thumbWidth');
  191. if(factor === 'theme') {
  192. factor = 1;
  193. }
  194. this.property('thumbProportions', factor);
  195. this.onThumbChangeSize();
  196. this.render();
  197. },
  198. onThumbChangeSize: function(){
  199. var factor = this.property('thumbProportions'),
  200. width = this.property('thumbWidth'),
  201. height = Math.round(width / factor);
  202. if(factor === 'theme') {
  203. factor = 1;
  204. }
  205. this.property('thumbWidth', width, false);
  206. this.property('thumbHeight', height);
  207. this.checkRegenerateThumbs();
  208. },
  209. get_preset_properties: function() {
  210. var preset = this.model.get_property_value_by_name("preset") || 'default',
  211. props = PresetUtil.getPresetProperties('gallery', preset) || {};
  212. return props;
  213. },
  214. preset_updated: function(preset) {
  215. this.debouncedRender();
  216. Upfront.Events.trigger('preset:gallery:updated', preset);
  217. },
  218. caption_updated: function(preset) {
  219. var currentPreset = this.model.get_property_value_by_name("preset");
  220. //If element use updated preset re-render
  221. if(currentPreset === preset) this.debouncedRender();
  222. },
  223. update_colors: function () {
  224. var props = this.get_preset_properties();
  225. if (_.size(props) <= 0) return false; // No properties, carry on
  226. PresetUtil.updatePresetStyle('gallery', props, settingsStyleTpl);
  227. },
  228. preventClose: function(event) {
  229. event.stopPropagation();
  230. },
  231. populate_theme_images: function (image_list) {
  232. this.images.each(function(each){
  233. if ( each.is_theme_image() ) image_list.push(each.get('srcFull'));
  234. });
  235. },
  236. imported_theme_image: function (image) {
  237. var me = this;
  238. this.images.each(function(each){
  239. var id = each.get('id'),
  240. src = each.get('srcFull')
  241. ;
  242. if ( each.is_theme_image() && image.filepath === src ) {
  243. each.set('id', image.id);
  244. each.set('srcFull', image.src);
  245. me.$el.find('.ugallery_item[rel=' + id + ']').attr('rel', image.id);
  246. }
  247. });
  248. },
  249. // Remove default dblclick behavior because it messes up things
  250. on_edit: function() {},
  251. /****************************************************/
  252. /* Settings change live callbacks */
  253. /****************************************************/
  254. updateThumbPadding: function() {
  255. this.$el.find('.ugallery').data('thumb-padding', this.property('thumbPadding'));
  256. this.$el.find('.ugallery').data('thumb-bottom-padding', this.property('bottomPadding'));
  257. this.$el.find('.ugallery').data('thumb-side-padding', this.property('sidePadding'));
  258. this.debouncedRender();
  259. },
  260. updateCaptionType: function() {
  261. var classes,
  262. suffix;
  263. this.$el.find('.ugallery-thumb-title')
  264. .removeClass('ugallery-caption-over ugallery-caption-below ugallery-caption-none')
  265. .addClass('ugallery-caption-' + this.property('captionType'));
  266. if (this.property('captionType') !== 'over') {
  267. classes = 'ugallery_caption_on_hover_1 ugallery_caption_on_hover_0 ugallery-caption-on-hover-1 ugallery-caption-on-hover-0';
  268. this.$el.find('.ugallery_item, .ugallery-thumb-title').removeClass(classes);
  269. } else {
  270. suffix = this.property('showCaptionOnHover').length;
  271. this.$el.find('.ugallery_item').addClass('ugallery_caption_on_hover_' + suffix);
  272. this.$el.find('.ugallery-thumb-title').addClass('ugallery-caption-on-hover-' + suffix);
  273. }
  274. },
  275. updateFitThumbCaptions: function() {
  276. this.debouncedRender();
  277. },
  278. updateThumbCaptionsHeight: function() {
  279. this.debouncedRender();
  280. },
  281. updateShowCaptionOnHover: function() {
  282. var classes = 'ugallery_caption_on_hover_1 ugallery_caption_on_hover_0 ugallery-caption-on-hover-1 ugallery-caption-on-hover-0',
  283. suffix = this.property('showCaptionOnHover').length;
  284. this.$el.find('.ugallery_item, .ugallery-thumb-title').removeClass(classes);
  285. this.$el.find('.ugallery_item').addClass('ugallery_caption_on_hover_' + suffix);
  286. this.$el.find('.ugallery-thumb-title').addClass('ugallery-caption-on-hover-' + suffix);
  287. },
  288. updateEvenPadding: function() {
  289. this.render();
  290. },
  291. updateShowFilters: function() {
  292. if (this.property('labelFilters') === 'true') {
  293. this.$el.find('.ugallery_labels').show();
  294. this.$el.find('.ugallery-magnific-labels').parents('.upfront-inline-panel-item').show();
  295. Upfront.frontFunctions.galleryBindShuffle();
  296. } else {
  297. this.$el.find('.ugallery_labels').hide();
  298. this.$el.find('.ugallery-magnific-labels').parents('.upfront-inline-panel-item').hide();
  299. }
  300. },
  301. /****************************************************/
  302. /* End settings change live callbacks */
  303. /****************************************************/
  304. selectItem: function(e) {
  305. var item = $(e.target).hasClass('gallery_item') ? $(e.target) : $(e.target).closest('.ugallery_item');
  306. if (!item.length) return;
  307. item.siblings().removeClass('ugallery_selected');
  308. if (!($(e.target).closest('.ugallery-controls') || {}).length) {
  309. item.toggleClass('ugallery_selected');
  310. }
  311. e.gallerySelected = true;
  312. },
  313. createControlsEach: function(image, $item) {
  314. var panel = new Upfront.Views.Editor.InlinePanels.ControlPanel(),
  315. moreOptions = new Upfront.Views.Editor.InlinePanels.SubControl()
  316. ;
  317. moreOptions.icon = 'more';
  318. moreOptions.inline = true;
  319. moreOptions.tooltip = l10n.ctrl.thumbnail_options;
  320. moreOptions.sub_items = {};
  321. if (Upfront.Application.user_can_modify_layout()) {
  322. moreOptions.sub_items['crop'] = this.createControl('crop', l10n.ctrl.edit_image, 'imageEditMask', 28, 28);
  323. }
  324. if (Upfront.Application.user_can_modify_layout()) {
  325. if (this.property('labelFilters') === 'true') {
  326. moreOptions.sub_items['label'] = this.createLabelControl(image);
  327. }
  328. if (image.get('imageLink').type === 'image' || image.get('imageLink').type === 'lightbox' || -1 !== ['image', 'lightbox'].indexOf( this.property( "linkTo" ) ) ) {
  329. moreOptions.sub_items['fullscreen'] = this.createControl('fullscreen', l10n.ctrl.show_image, 'openImageLightbox', 28, 28);
  330. } else {
  331. moreOptions.sub_items['link'] = this.createLinkControl(image);
  332. }
  333. moreOptions.sub_items['remove'] = this.createControl('remove', l10n.ctrl.rm_image, 'removeImage', 28, 28);
  334. }
  335. panel.items.push(moreOptions);
  336. this.listenTo(moreOptions, 'panel:close', function(){
  337. $item.removeClass('stayOpen controls-visible');
  338. });
  339. this.listenTo(moreOptions, 'panel:open', function() {
  340. $item.addClass('stayOpen controls-visible');
  341. });
  342. return panel;
  343. },
  344. createControl: function(icon, tooltip, click_callback, width, height) {
  345. var me = this,
  346. item = new Upfront.Views.Editor.InlinePanels.Control();
  347. item.icon = icon;
  348. item.tooltip = tooltip;
  349. //Set icon width & height
  350. item.width = width;
  351. item.height = height;
  352. if(click_callback) {
  353. this.listenTo(item, 'click', function(e){
  354. me[click_callback](e);
  355. });
  356. }
  357. return item;
  358. },
  359. createLabelControl: function(image){
  360. var control = new Upfront.Views.Editor.InlinePanels.DialogControl(),
  361. me = this;
  362. control.hideOkButton = true;
  363. control.hideOnClick = false;
  364. control.view = this.createLabelEditor(image);
  365. control.image = image;
  366. if (control.view.options.labels.length) {
  367. control.icon = 'edit-labels';
  368. } else {
  369. control.icon = 'edit-labels-no-labels';
  370. }
  371. control.tooltip = l10n.ctrl.edit_labels;
  372. control.id = 'edit_labels';
  373. //Set icon width & height
  374. control.width = 28;
  375. control.height = 28;
  376. me.listenTo(control, 'panel:open', function(){
  377. me.lastOpenedControl = control;
  378. setTimeout(function() {
  379. // this is fine because gallery will re-render once panel is closed
  380. me.$el.find('.ugallery_item').css('overflow', 'visible');
  381. }, 10);
  382. control.$el
  383. .closest('.ugallery-controls')
  384. .addClass('upfront-control-visible');
  385. });
  386. me.listenTo(control, 'panel:close', function(){
  387. control.$el
  388. .closest('.ugallery-controls')
  389. .removeClass('upfront-control-visible');
  390. if (control === me.lastOpenedControl) {
  391. me.render();
  392. }
  393. });
  394. return control;
  395. },
  396. createLinkControl: function(image){
  397. var me = this,
  398. linkControl = new Upfront.Views.Editor.InlinePanels.LinkControl(),
  399. imageLink = new LinkModel(image.get('imageLink'));
  400. linkControl.view = linkPanel = new Upfront.Views.Editor.LinkPanel({
  401. model: imageLink,
  402. linkTypes: { image: true },
  403. imageUrl: image.get('srcFull')
  404. });
  405. // Update wrapper size
  406. this.listenTo(linkPanel, 'linkpanel:update:wrapper', function() {
  407. linkControl.updateWrapperSize();
  408. });
  409. this.listenTo(linkPanel.model, "change", function( model ){
  410. /**
  411. * Response properly when selected link type is a post or page ( entry )
  412. */
  413. if( 'entry' === model.get("type") ){
  414. setTimeout(function() {
  415. var $item = linkControl.$el.closest(".ugallery_item");
  416. me.add_controls_to_item( image, $item );
  417. }, 50);
  418. }
  419. });
  420. this.listenTo(imageLink, 'change', function(){
  421. image.set({'imageLink': imageLink.toJSON()});
  422. });
  423. this.listenTo(linkControl, 'panel:ok', function(){
  424. linkControl.close();
  425. });
  426. me.listenTo(linkControl, 'panel:open', function(){
  427. linkControl.$el
  428. .parents('.ugallery_item')
  429. .addClass('upfront-control-visible').end()
  430. .closest('.ugallery_link')
  431. .removeAttr('href') //Deactivate link when the panel is open
  432. ;
  433. me.$el.closest('.ui-draggable').draggable('disable');
  434. });
  435. me.listenTo(linkControl, 'panel:ok', function(){
  436. linkControl.$el
  437. .parents('.ugallery_item')
  438. .removeClass('upfront-control-visible');
  439. setTimeout(function() {
  440. linkControl.$el.closest('.ugallery-controls').siblings('.ugallery_link')
  441. .attr('href', imageLink.get('url'))
  442. .attr('target', imageLink.get('target'))
  443. .attr('class', 'ugallery_link ugallery_link' + imageLink.get('type'));
  444. var $item = linkControl.$el.closest(".ugallery_item");
  445. /**
  446. * Refresh the controlls when Ok is clicked
  447. */
  448. me.add_controls_to_item( image, $item );
  449. }, 50);
  450. me.$el.closest('.ui-draggable').draggable('enable');
  451. });
  452. linkControl.icon = 'link';
  453. linkControl.tooltip = l10n.ctrl.image_link;
  454. linkControl.id = 'link';
  455. //Set icon width & height
  456. linkControl.width = 28;
  457. linkControl.height = 28;
  458. return linkControl;
  459. },
  460. openLightbox: function(event) {
  461. var gallery, magOptions;
  462. gallery = false;
  463. magOptions = ugalleries[galleryId].magnific;
  464. },
  465. openImageLightbox: function(e) {
  466. var me = this,
  467. lightboxName,
  468. item = $(e.target).closest('.ugallery_item'),
  469. image = me.images.get(item.attr('rel')),
  470. titleUpdated = false,
  471. resizeWithText = function() {
  472. var caption = this.content.find('figcaption'),
  473. maxHeight = this.wH - 120 - caption.outerHeight(),
  474. maxWidth = $(window).width() - 200
  475. ;
  476. this.content.find('img').css({
  477. 'max-width': maxWidth,
  478. 'max-height': maxHeight
  479. });
  480. // Resize lightbox on window resize
  481. me.resizeLightboxContainer();
  482. }
  483. ;
  484. if (image.get('imageLink').type === 'lightbox') {
  485. lightboxName = image.get('imageLink').url.substring(1);
  486. Upfront.Application.LayoutEditor.openLightboxRegion(lightboxName);
  487. return;
  488. }
  489. $.magnificPopup.open({
  490. closeOnBgClick: _.isTrue( this.model.get_property_value_by_name('lightbox_click_out_close')[0] ),
  491. items: {
  492. src: image.get("srcFull")
  493. },
  494. type: 'image',
  495. image: {
  496. titleSrc: function() {
  497. return image.get('caption');
  498. },
  499. markup: Upfront.data.ugallery.lightboxTpl
  500. },
  501. callbacks: {
  502. open: function() {
  503. me.setupLightbox();
  504. me.createLightboxSettings();
  505. // Prevent lightbox from closing when clicking on image or caption
  506. $('.glb-content-container').click(me.preventClose);
  507. $('.glb-image-container').click(me.preventClose);
  508. $('.glb-caption-container').click(me.preventClose);
  509. // Prevent magnific from capturing focus
  510. setTimeout(function() {
  511. $(document).off('focusin');
  512. }, 500);
  513. },
  514. imageLoadComplete: function() {
  515. var title = $(this.container).find('.mfp-title');
  516. if(title.length){
  517. title.ueditor({
  518. linebreaks: false,
  519. autostart: false,
  520. upfrontMedia: false,
  521. upfrontImages: false
  522. })
  523. .on('start', function(){
  524. titleUpdated = true;
  525. })
  526. .on('syncAfter', function(){
  527. image.set('caption', title.html());
  528. })
  529. ;
  530. }
  531. },
  532. beforeClose: function() {
  533. if (titleUpdated) {
  534. Upfront.Views.Editor.notify(l10n.desc_update_success);
  535. }
  536. },
  537. resize: resizeWithText,
  538. afterChange: resizeWithText
  539. }
  540. });
  541. },
  542. setupLightbox: function() {
  543. var containerClass ='gallery-' + this.property('element_id') + '-lightbox',
  544. currentLightbox;
  545. $('.mfp-bg, .mfp-wrap').addClass(containerClass);
  546. currentLightbox = $('.' + containerClass);
  547. currentLightbox.find('.mfp-counter').html('1 of 2');
  548. if (this.property('lightbox_show_close')[0] === 'true') {
  549. currentLightbox.find('.mfp-close').show();
  550. } else {
  551. currentLightbox.find('.mfp-close').hide();
  552. }
  553. if (this.property('lightbox_show_image_count')[0] === 'true') {
  554. currentLightbox.find('.mfp-counter').show();
  555. } else {
  556. currentLightbox.find('.mfp-counter').hide();
  557. }
  558. $('.glb-content-container').css({
  559. 'background': this.property('lightbox_active_area_bg')
  560. });
  561. $('.mfp-bg').css('background', this.property('lightbox_overlay_bg'));
  562. if( $('.mfp-container').find('.mfp-arrow.mfp-arrow-left.mfp-prevent-close').length === 0 )
  563. $('.mfp-container').append('<button title="Previous (Left arrow key)" type="button" class="mfp-arrow mfp-arrow-left mfp-prevent-close"></button>');
  564. if( $('.mfp-container').find('.mfp-arrow.mfp-arrow-right.mfp-prevent-close').length === 0 )
  565. $('.mfp-container').append('<button title="Next (Right arrow key)" type="button" class="mfp-arrow mfp-arrow-right mfp-prevent-close"></button>');
  566. if ($('style#' + containerClass).length === 0) {
  567. $('body').append('<style id="' + containerClass + '"></style>');
  568. }
  569. $('style#' + containerClass).html(this.property('styles'));
  570. //Resize lightbox to fit editor container
  571. this.resizeLightboxContainer();
  572. },
  573. resizeLightboxContainer: function() {
  574. var currentLightbox = $( '.mfp-bg, .mfp-wrap' ),
  575. sidebar_ui = $( '#sidebar-ui' ),
  576. sidebar_ui_width = sidebar_ui.width(),
  577. lightbox_content = currentLightbox.find( '.mfp-container' )
  578. ;
  579. currentLightbox.css( 'left', sidebar_ui_width );
  580. lightbox_content.css( 'width', currentLightbox.width() - sidebar_ui_width );
  581. },
  582. createLightboxSettings: function () {
  583. $('.mfp-container').append(_.template(lightboxTpl, {
  584. edit_lightbox_css: l10n.lightbox.edit_css,
  585. lightbox_title: l10n.lightbox.title
  586. }));
  587. var $lightbox = $('.mfp-container').find('.upfront-region-bg-setting-lightbox-region');
  588. var me = this,
  589. fields;
  590. fields = {
  591. lightbox_click_out_close: new Upfront.Views.Editor.Field.Checkboxes({
  592. model: this.model,
  593. property: 'lightbox_click_out_close',
  594. label: "",
  595. values: [
  596. {
  597. label: globalL10n.click_close_ltbox,
  598. value: 'true',
  599. checked: this.model.get_property_value_by_name('lightbox_click_out_close')[0] === 'true' ? 'checked' : false
  600. }
  601. ],
  602. change: function(value) {
  603. me.property('lightbox_click_out_close', value);
  604. this.model.set('lightbox_click_out_close', value, true);
  605. me.setupLightbox();
  606. }
  607. }),
  608. lightbox_show_close: new Upfront.Views.Editor.Field.Checkboxes({
  609. model: this.model,
  610. className: 'gallery-lb-show_close upfront-field-wrap upfront-field-wrap-multiple upfront-field-wrap-checkboxes',
  611. property: 'lightbox_show_close',
  612. label: "",
  613. values: [
  614. {
  615. label: globalL10n.show_close_icon,
  616. value: 'true',
  617. checked: this.model.get_property_value_by_name('lightbox_show_close')[0] === 'true' ? 'checked' : false
  618. }
  619. ],
  620. change: function(value) {
  621. me.property('lightbox_show_close', value);
  622. me.setupLightbox();
  623. }
  624. }),
  625. lightbox_show_image_count: new Upfront.Views.Editor.Field.Checkboxes({
  626. model: this.model,
  627. className: 'gallery-lb-show_image_count upfront-field-wrap upfront-field-wrap-multiple upfront-field-wrap-checkboxes',
  628. property: 'lightbox_show_image_count',
  629. label: "",
  630. values: [
  631. {
  632. label: l10n.lightbox.show_image_count,
  633. value: 'true',
  634. checked: this.model.get_property_value_by_name('lightbox_show_image_count')[0] === 'true' ? 'checked' : false
  635. }
  636. ],
  637. change: function(value) {
  638. me.property('lightbox_show_image_count', value);
  639. me.setupLightbox();
  640. }
  641. })
  642. };
  643. fields.lightbox_active_area_bg = new Upfront.Views.Editor.Field.Color({
  644. model: this.model,
  645. property: 'lightbox_active_area_bg',
  646. className: 'upfront-field-wrap upfront-field-wrap-color sp-cf overlay_color',
  647. label: l10n.lightbox.active_area_bg + ":",
  648. spectrum: {
  649. move: function(color) {
  650. me.property('lightbox_active_area_bg', color.toRgbString());
  651. me.setupLightbox();
  652. },
  653. change: function(color) {
  654. me.property('lightbox_active_area_bg', color.toRgbString());
  655. me.setupLightbox();
  656. }
  657. }
  658. });
  659. fields.lightbox_overlay_bg = new Upfront.Views.Editor.Field.Color({
  660. model: this.model,
  661. property: 'lightbox_overlay_bg',
  662. label: l10n.lightbox.overlay_bg + ":",
  663. change: me.updateProperty,
  664. spectrum: {
  665. move: function(color) {
  666. me.property('lightbox_overlay_bg', color.toRgbString());
  667. me.setupLightbox();
  668. },
  669. change: function(color) {
  670. me.property('lightbox_overlay_bg', color.toRgbString());
  671. me.setupLightbox();
  672. }
  673. }
  674. });
  675. _.each(fields, function(field){
  676. field.render();
  677. field.delegateEvents();
  678. if( $lightbox.find( field.$el).length === 0 )
  679. $lightbox.append(field.$el);
  680. });
  681. $('#gallery-lb-settings-button').toggle(
  682. function() {
  683. $('#gallery-lb-settings').show();
  684. },
  685. function() {
  686. $('#gallery-lb-settings').hide();
  687. }
  688. );
  689. $('#gallery-lb-settings .upfront-inline-modal-save').click( function() {
  690. $('#gallery-lb-settings-button').click();
  691. if (me.galleryLightboxCssEditor) {
  692. me.galleryLightboxCssEditor.close();
  693. }
  694. });
  695. $('#gallery-lb-settings').click( function(event) {
  696. event.stopPropagation();
  697. });
  698. $('#gallery-lb-settings').find('.edit-lightbox-css').click( function(event) {
  699. me.galleryLightboxCssEditor = new Upfront.Views.Editor.GeneralCSSEditor({
  700. model: me.model,
  701. page_class: 'gallery-' + me.property('element_id') + '-lightbox',
  702. type: "GalleryLightbox",
  703. sidebar: true,
  704. global: false,
  705. toolbar: true,
  706. cssSelectors: {
  707. '.mfp-close': {label: l10n.css.lightbox_close, info: l10n.css.lightbox_close},
  708. '.glb-content-container': {label: l10n.css.lightbox_content_wrapper, info: l10n.css.lightbox_content_wrapper_info},
  709. '.glb-image-container': {label: l10n.css.lightbox_image_wrapper, info: l10n.css.lightbox_image_wrapper},
  710. '.glb-caption-container': {label: l10n.css.lightbox_caption_wrapper, info: l10n.css.lightbox_caption_wrapper},
  711. '.mfp-title': {label: l10n.css.lightbox_caption, info: l10n.css.lightbox_caption},
  712. '.mfp-arrow-left:before': {label: l10n.css.lightbox_arrow_left, info: l10n.css.lightbox_arrow_left},
  713. '.mfp-arrow-right:before': {label: l10n.css.lightbox_arrow_right, info: l10n.css.lightbox_arrow_right},
  714. '.mfp-counter': {label: l10n.css.lightbox_image_count, info: l10n.css.lightbox_image_count}
  715. },
  716. change: function(content) {
  717. me.property('styles', content);
  718. me.setupLightbox();
  719. },
  720. onClose: function() {
  721. $('.mfp-content').css({
  722. 'margin-bottom': 0,
  723. 'margin-top': 0
  724. });
  725. }
  726. });
  727. $('.mfp-content').css({
  728. 'margin-bottom': 250,
  729. 'margin-top': 50
  730. });
  731. });
  732. },
  733. createLabelEditor: function(image) {
  734. var labelEditor = new LabelEditor({
  735. gallery: this,
  736. labels: this.extractImageLabels(image.id),
  737. imageId: image.id
  738. });
  739. return labelEditor;
  740. },
  741. openLightboxLabels: function(e){
  742. this.openImageLightbox(e, true);
  743. },
  744. getPropertiesForTemplate: function() {
  745. var props = this.extract_properties();
  746. props.properties = this.get_preset_properties();
  747. props.imagesLength = props.images.length;
  748. props.editing = true;
  749. props.cap = Upfront.Application.user_can_modify_layout();
  750. props.labels = this.labels;
  751. props.labels_length = this.labels.length;
  752. props.image_labels = this.imageLabels;
  753. // In case the image doesn't have the `imageLink` populated, use the element-wide fallback as default
  754. var fallback_type = this.property('linkTo');
  755. _.each(props.images, function(image, index) {
  756. props.images[index]['imageLinkType'] = image.imageLink.type || fallback_type;
  757. props.images[index]['imageLinkUrl'] = image.imageLink.url;
  758. props.images[index]['imageLinkTarget'] = image.imageLink.target;
  759. });
  760. props.usingNewAppearance = props.usingNewAppearance || false;
  761. props.l10n = l10n.template;
  762. props.in_editor = true;
  763. if (!props.even_padding) {
  764. props.even_padding = ['false'];
  765. }
  766. if (_.isArray(props.labelFilters) && props.labelFilters[0] === 'true') {
  767. props.labelFilters = 'true';
  768. }
  769. return props;
  770. },
  771. get_content_markup: function() {
  772. return this.tpl(this.getPropertiesForTemplate());
  773. },
  774. on_render: function() {
  775. var me = this,
  776. resizingFunction;
  777. //Bind resizing events
  778. if ( me.parent_module_view && !me.parent_module_view.$el.data('resizeHandling') ) {
  779. resizingFunction = $.proxy(me.onElementResizing, me);
  780. me.parent_module_view.$el
  781. .on('resize', resizingFunction)
  782. .on('resizestop', $.proxy(me.onElementResizeStop, me))
  783. .data('resizeHandling', true)
  784. ;
  785. }
  786. /**
  787. The following is being done so that the gallery
  788. items inside a lightbox can shuffle after
  789. the lightbox shows up, in order to expand
  790. around in the available space
  791. **/
  792. Upfront.Events.on('upfront:lightbox:show', function(e) {
  793. setTimeout(function(){
  794. $(window).trigger('resize');
  795. }, 300);
  796. });
  797. this.images.each(function(image) {
  798. if(image.get('loading') && 0 === me.$('.ugallery_item[rel="' + image.id + '"]').find( '.ugallery-image-loading').length ){
  799. me.$('.ugallery_item[rel="' + image.id + '"]')
  800. .append('<p class="ugallery-image-loading">' + l10n.loading + '</p>');
  801. }
  802. });
  803. if(_.indexOf(['ok', 'starting'], me.property('status')) === -1 && 0 === me.$('.upfront-gallery').find( '.upfront-quick-swap').length ) {
  804. me.$('.upfront-gallery').append('<div class="upfront-quick-swap"><p>' + l10n.personalize + '</p></div>');
  805. }
  806. // if (this.images && this.images.length) {
  807. // var $upfrontObjectContent = this.$el.find('.upfront-object-content');
  808. // if (this.$el.find('a.toggle-sorting').length < 1) {
  809. // $('<b class="upfront-entity_meta upfront-ui toggle_sorting" title="Toggle drag\'n\'drop sorting of images"><a href="" class="upfront-icon-button toggle-sorting"></a></b>').insertBefore($upfrontObjectContent);
  810. // }
  811. // if (this.$el.find('a.add-item').length < 1) {
  812. // $('<b class="upfront-entity_meta upfront-ui add_item"><a href="" class="upfront-icon-button add-item"></a></b>').insertBefore($upfrontObjectContent);
  813. // }
  814. // }
  815. setTimeout(function() {
  816. me.rebindShuffle();
  817. var items = me.$('.ugallery_item');
  818. _.each(items, function(item) {
  819. var $item = $(item),
  820. image = me.images.get($item.attr('rel')),
  821. title = $item.find('.ugallery-thumb-title'),
  822. controls = me.add_controls_to_item( image, $item)
  823. .setWidth( $item.width() );
  824. me.ensureCaptionEditorExists(title, image);
  825. if(image.controls) {
  826. image.controls.remove();
  827. }
  828. image.controls = controls;
  829. });
  830. }, 300);
  831. if (this.isSortingActive === true) {
  832. this.activateSortable();
  833. } else {
  834. this.cleanupSortable();
  835. }
  836. if (this.property('linkTo') === false) {
  837. this.showSelectType();
  838. }
  839. },
  840. ensureCaptionEditorExists: function(title, image) {
  841. var me = this;
  842. if (!title.data('ueditor')) {
  843. title.ueditor({
  844. linebreaks: false,
  845. autostart: false,
  846. upfrontMedia: false,
  847. upfrontImages: false
  848. })
  849. .on('start', function() {
  850. me.$el.addClass('upfront-editing');
  851. })
  852. .on('stop', function() {
  853. setTimeout(function() {
  854. // Prevent on hover caption shows constantly
  855. title.removeAttr('style');
  856. }, 10);
  857. me.$el.removeClass('upfront-editing');
  858. })
  859. .on('syncAfter', function() {
  860. image.set('title', title.html());
  861. image.set('caption', title.html());
  862. })
  863. ;
  864. }
  865. },
  866. onElementResizing: function(){
  867. this.$('.ugallery_items').width($('html').find('.upfront-resize').width() - 30);
  868. },
  869. onElementResizeStop: function(){
  870. // Not gonna do this because render will be triggered by parent class model changing
  871. // 'row' property on resize.
  872. // this.render(); <-- this is redundant and creates misscalculation of padding
  873. },
  874. on_module_update: function (attr) {
  875. this.render();
  876. },
  877. toggleSorting: function(event) {
  878. if (event) {
  879. event.preventDefault();
  880. }
  881. this.isSortingActive = !this.isSortingActive;
  882. this.itemsInRow = this.$el.find('.ugallery_item').filter(function(){ return $(this).css('top') === '0px'; }).length;
  883. this.render();
  884. if(this.isSortingActive) {
  885. this.controls.$el.find('.upfront-icon-region-toggle-sorting').addClass('upfront-icon-region-sorting-active');
  886. }
  887. else {
  888. this.controls.$el.find('.upfront-icon-region-toggle-sorting').removeClass('upfront-icon-region-sorting-active');
  889. }
  890. },
  891. rebindShuffleForDebouncing: function() {
  892. if (!this.isSortingActive) {
  893. Upfront.frontFunctions.galleryBindShuffle(this.$el.find('.ugallery_grid'), true);
  894. }
  895. },
  896. rebindShuffle: function() {
  897. this.debouncedRebindShuffle();
  898. },
  899. preventNavigation: function(e){
  900. this.constructor.__super__.constructor.__super__.on_click.call(this, e);
  901. if(e.target.tagName.toUpperCase() === 'INPUT') {
  902. return;
  903. }
  904. if(e.target.tagName.toUpperCase() === 'A' || $(e.target).closest('a').length) {
  905. e.preventDefault();
  906. }
  907. },
  908. getLabelSelector: function(imageId){
  909. var tpl = $($.trim(this.labelsTpl({labels: this.extractImageLabels(imageId), l10n: l10n.template})));
  910. return tpl;
  911. },
  912. extractImageLabels: function(imageId){
  913. var ids = !_.isUndefined( this.imageLabels[imageId] ) ? this.imageLabels[imageId].match(/-?\d+/g) : false,
  914. labels = []
  915. ;
  916. if(ids){
  917. _.each(this.labels, function(label){
  918. if(ids.indexOf(label.id.toString()) !== -1 && label.id !== '0') {
  919. labels.push(label);
  920. }
  921. });
  922. }
  923. return labels;
  924. },
  925. openImageSelector: function(event, replaceId){
  926. var me = this,
  927. selectorOptions = {
  928. multiple: true,
  929. preparingText: l10n.preparing,
  930. customImageSize: {width: this.property('thumbWidth'), height: this.property('thumbHeight')},
  931. element_id: this.model.get_property_value_by_name('element_id')
  932. }
  933. ;
  934. if (event) {
  935. event.preventDefault();
  936. }
  937. Upfront.Views.Editor.ImageSelector.open(selectorOptions).done(function(images, response){
  938. me.addImages(images, replaceId);
  939. if (response.given !== response.returned) {
  940. Upfront.Views.Editor.notify(l10n.not_all_added, 'warning');
  941. }
  942. Upfront.Views.Editor.ImageSelector.close();
  943. });
  944. },
  945. addImages: function(images, replaceId){
  946. var me = this,
  947. models = [],
  948. element_id = this.model.get_property_value_by_name('element_id');
  949. this.getNewLabels(_.keys(images));
  950. _.each(images, function(image, id) {
  951. var model = new UgalleryImage({
  952. id: id,
  953. srcFull: image.full[0],
  954. sizes: image,
  955. size: image.custom.editdata.resize,
  956. cropSize: image.custom.crop,
  957. cropOffset: image.custom.editdata.crop,
  958. src: image.custom.url,
  959. loading: false,
  960. status: 'ok',
  961. element_id: element_id,
  962. urlType: me.property('linkTo'),
  963. url: image.full[0]
  964. });
  965. // Also initialize image link defaults here
  966. model.set('imageLink', {
  967. type: me.property('linkTo'),
  968. url: model.get("url"),
  969. target: model.get("linkTarget")
  970. });
  971. models.push(model);
  972. });
  973. if (me.property('status') !== 'ok') {
  974. me.property('status', 'ok');
  975. me.property('has_settings', 1);
  976. me.images.reset(models);
  977. } else if (replaceId) {
  978. var item = me.images.get(replaceId),
  979. idx = me.images.indexOf(item);
  980. me.images.remove(replaceId);
  981. me.images.add(models, {at: idx});
  982. } else {
  983. me.images.add(models);
  984. }
  985. me.render();
  986. },
  987. showSelectType: function() {
  988. if (!Upfront.Application.user_can_modify_layout()) return false;
  989. var me = this,
  990. selector = $('<div class="upfront-ui ugallery-onclick"><div class="ugallery-onclick-dialog"><span>' + l10n.thumbnail_clicked +
  991. '</span><div class="ugallery-onclick-options"><a href="#" class="ugallery-lager_image" rel="image">' + l10n.show_larger +
  992. '</a><a href="#" class="ugallery-linked_page" rel="external">' + l10n.go_to_linked + '</a></div></div></div>');
  993. selector.on('click', 'a', function(e){
  994. e.preventDefault();
  995. var value = $(e.target).attr('rel');
  996. me.property('linkTo', value, false);
  997. _.each(me.images.models, function(image) {
  998. image.set({'urlType': value}, {silent:true});
  999. });
  1000. me.property('images', me.images.toJSON());
  1001. setTimeout(function(){
  1002. selector.fadeOut('fast', function(){
  1003. selector.remove();
  1004. me.render();
  1005. });
  1006. }, 100);
  1007. });
  1008. if( 0 === this.$( '.ugallery').find( ".upfront-ui.ugallery-onclick").length )
  1009. this.$('.ugallery').append(selector.hide());
  1010. selector.fadeIn();
  1011. },
  1012. getNewLabels: function(ids){
  1013. var data = {
  1014. action: 'upfront-media_get_image_labels',
  1015. post_ids: ids
  1016. },
  1017. me = this
  1018. ;
  1019. Upfront.Util.post(data).done(function(results){
  1020. var images = results.data;
  1021. _.each(images, function(labels, imageId){
  1022. var imageLabels = [];
  1023. imageLabels.push('"label_0"');
  1024. _.each(labels, function(label){
  1025. var globals = Upfront.data.ugallery,
  1026. newLabel = {id: label.term_id, text: label.name}
  1027. ;
  1028. if(!globals.label_names[label.name]) {
  1029. globals.label_names[label.name] = newLabel;
  1030. }
  1031. if(!globals.label_ids[label.term_id]) {
  1032. globals.label_ids[label.term_id] = newLabel;
  1033. }
  1034. if(!me.isLabelInGallery(newLabel)) {
  1035. me.labels.push(newLabel);
  1036. }
  1037. imageLabels.push('"label_' + label.term_id + '"');
  1038. });
  1039. me.imageLabels[imageId] = imageLabels.join(', ');
  1040. });
  1041. });
  1042. },
  1043. isLabelInGallery: function(label){
  1044. var me = this,
  1045. labelInGallery = false,
  1046. i = 0
  1047. ;
  1048. while(i<me.labels.length && !labelInGallery){
  1049. labelInGallery = me.labels[i].id === label.id;
  1050. i++;
  1051. }
  1052. return labelInGallery;
  1053. },
  1054. getCropOffset: function(size, fullSize){
  1055. var pivot = fullSize.width / size.width > fullSize.height / size.height ? 'height' : 'width',
  1056. factor = fullSize[pivot] / size[pivot],
  1057. reducedSize, offset
  1058. ;
  1059. if(factor > 0){
  1060. reducedSize = {width: Math.floor(fullSize.width / factor), height: Math.floor(fullSize.height / factor)};
  1061. offset = {left: (reducedSize.width - size.width) / 2, top: (reducedSize.height - size.height) / 2};
  1062. }
  1063. else{
  1064. reducedSize = size;
  1065. offset = {left:0, top:0};
  1066. }
  1067. return {size: reducedSize, offset: offset};
  1068. },
  1069. centeredPosition: function(imgSize){
  1070. var wrapperSize = {
  1071. width: this.property('thumbWidth'),
  1072. height: this.property('thumbHeight')
  1073. };
  1074. return {
  1075. top: ((wrapperSize.height - imgSize.height) / 2) / wrapperSize.height * 100,
  1076. left: ((wrapperSize.width - imgSize.width) / 2) / wrapperSize.width * 100
  1077. };
  1078. },
  1079. checkRegenerateThumbs: function(e, imageIds){
  1080. var me = this;
  1081. if (!(
  1082. imageIds
  1083. ||
  1084. this.lastThumbnailSize.width !== this.property('thumbWidth')
  1085. ||
  1086. this.lastThumbnailSize.height !== this.property('thumbHeight')
  1087. )) return false;
  1088. var editOptions = {
  1089. images: this.getRegenerateData(imageIds),
  1090. action: 'upfront-media-image-create-size'
  1091. },
  1092. loading = new Upfront.Views.Editor.Loading({
  1093. loading: l10n.regenerating,
  1094. done: l10n.regenerating_done,
  1095. fixed: false
  1096. })
  1097. ;
  1098. loading.render();
  1099. if (!this.parent_module_view.$el.find( loading.$el).length) {
  1100. this.parent_module_view.$el.append(loading.$el);
  1101. }
  1102. Upfront.Util.post(editOptions).done(function(response) {
  1103. loading.done();
  1104. var images = response.data.images,
  1105. models = []
  1106. ;
  1107. _.each(editOptions.images, function(image){
  1108. var model = me.images.get(image.id),
  1109. changes = images[image.id]
  1110. ;
  1111. if(!changes.error){
  1112. model.set({
  1113. src: changes.url,
  1114. srcFull: changes.urlOriginal,
  1115. size: image.resize,
  1116. cropPosition: {top: image.crop.top, left: image.crop.left}
  1117. }, {silent: true});
  1118. }
  1119. models.push(model);
  1120. });
  1121. me.images.set(models, {remove: false});
  1122. me.imagesChanged();
  1123. me.render();
  1124. me.lastThumbnailSize = {width: me.property('thumbWidth'), height: me.property('thumbHeight')};
  1125. });
  1126. },
  1127. getRegenerateData: function(imageIds){
  1128. var me = this,
  1129. widthFactor = this.property('thumbWidth') / this.lastThumbnailSize.width,
  1130. heightFactor = this.property('thumbHeight') / this.lastThumbnailSize.height,
  1131. factor = widthFactor > heightFactor ? widthFactor : heightFactor,
  1132. imageData = [],
  1133. images = this.images,
  1134. element_id = this.model.get_property_value_by_name('element_id')
  1135. ;
  1136. if(imageIds){
  1137. images = [];
  1138. _.each(imageIds, function(id){
  1139. images.push(me.images.get(id));
  1140. });
  1141. images = new UgalleryImages(images);
  1142. }
  1143. images.each(function(image){
  1144. var size = image.get('size'),
  1145. offset = image.get('cropOffset'),
  1146. offsetTop = Math.round((me.property('thumbHeight') / me.lastThumbnailSize.height) * offset.top),
  1147. offsetLeft = Math.round((me.property('thumbWidth') / me.lastThumbnailSize.width) * offset.left),
  1148. editorOpts = {
  1149. id: image.id,
  1150. rotate:image.get('rotation'),
  1151. resize: {width: size.width * factor, height: size.height * factor},
  1152. crop: {
  1153. top: Math.round(offset.top * factor),
  1154. left: Math.round(offset.left * factor),
  1155. width: me.property('thumbWidth'),
  1156. height: me.property('thumbHeight')
  1157. },
  1158. element_id: element_id
  1159. }
  1160. ;
  1161. //Scale cropOffset for new image size
  1162. image.set('cropOffset', { left: offsetLeft, top: offsetTop });
  1163. imageData.push(editorOpts);
  1164. });
  1165. return imageData;
  1166. },
  1167. imageEditMask: function(e) {
  1168. var me = this,
  1169. item = $(e.target).closest('.ugallery_item'),
  1170. image = this.images.get(item.attr('rel')),
  1171. editorOpts;
  1172. if(image.get('status') !== 'ok'){
  1173. var selectorOptions = {
  1174. multiple: false,
  1175. preparingText: l10n.preparing,
  1176. element_id: this.model.get_property_value_by_name('element_id')
  1177. };
  1178. return Upfront.Views.Editor.ImageSelector.open(selectorOptions).done(function(images){
  1179. me.addImages(images);
  1180. var index = me.images.indexOf(image);
  1181. me.images.remove(image, {silent:true});
  1182. var newImage = me.images.at(me.images.length -1);
  1183. me.images.remove(newImage, {silent:true});
  1184. me.images.add(newImage, {at: index});
  1185. Upfront.Views.Editor.ImageSelector.close();
  1186. });
  1187. }
  1188. editorOpts = this.getEditorOptions(image);
  1189. e.preventDefault();
  1190. Upfront.Views.Editor.ImageEditor.open(editorOpts)
  1191. .done(function(result){
  1192. image.set({
  1193. src: result.src,
  1194. srcFull: result.src,
  1195. cropSize: result.cropSize,
  1196. size: result.imageSize,
  1197. cropOffset: result.imageOffset,
  1198. margin: {left: Math.max(0-result.imageOffset.left, 0), top: Math.max(0-result.imageOffset.top, 0)},
  1199. rotation: result.rotation
  1200. });
  1201. me.render();
  1202. }).fail(function(data){
  1203. if(data && data.reason === 'changeImage') {
  1204. me.openImageSelector(false, data.id);
  1205. } else {
  1206. me.render();
  1207. }
  1208. });
  1209. },
  1210. getEditorOptions: function(image){
  1211. var $img = this.$('.ugallery_item[rel=' + image.id + '] img'),
  1212. full = image.get('sizes').full;
  1213. return {
  1214. id: image.id,
  1215. maskSize: {width: $img.width(), height: $img.height()},
  1216. maskOffset: $img.offset(),
  1217. position: image.get('cropOffset'),
  1218. size: image.get('size'),
  1219. fullSize: {width: full[1], height: full[2]},
  1220. src: image.get('src'),
  1221. srcOriginal: full[0],
  1222. rotation: image.get('rotation'),
  1223. element_id: this.model.get_property_value_by_name('element_id'),
  1224. element_cols: Upfront.Util.grid.width_to_col($img.width(), true)
  1225. };
  1226. },
  1227. imagesChanged: function() {
  1228. this.property('images', this.images.toJSON());
  1229. this.rebindShuffle();
  1230. },
  1231. /**
  1232. * Delete a label from the gallery if no other image has the label
  1233. * @param {int} labelId Label id
  1234. * @param {int} imageId Image id
  1235. * @return {null}
  1236. */
  1237. deleteLabel: function(labelId, imageId) {
  1238. var me = this,
  1239. deleteLabel = true;
  1240. var labelString = '"label_' + labelId + '"';
  1241. this.imageLabels[imageId] = this.imageLabels[imageId].replace(new RegExp(labelString + ',*', 'g'), '');
  1242. this.images.each(function(image){
  1243. if(image.id !== imageId && me.imageLabels[image.id].indexOf('"label_' + labelId + '"') !== -1){
  1244. deleteLabel = false;
  1245. }
  1246. });
  1247. if(deleteLabel){
  1248. for(var idx in this.labels){
  1249. if(this.labels[idx] && this.labels[idx].id === labelId) {
  1250. this.labels.splice(idx, 1);
  1251. }
  1252. }
  1253. }
  1254. },
  1255. addLabel: function(text, imageId){
  1256. var label = Upfront.data.ugallery.label_names[text],
  1257. labelId;
  1258. if (typeof label === 'undefined' || !label) {
  1259. return this.createLabel(text, imageId);
  1260. }
  1261. labelId = '"label_' + label.id + '"';
  1262. this.addToGalleryLabels(label);
  1263. this.associateLabelWithImage(imageId, labelId, label);
  1264. return label;
  1265. },
  1266. associateLabelWithImage: function(imageId, labelId, label) {
  1267. var data,
  1268. added = false;
  1269. if (!this.imageLabels[imageId]) {
  1270. this.imageLabels[imageId] = labelId;
  1271. added = true;
  1272. } else if (this.imageLabels[imageId].indexOf(labelId) === -1) {
  1273. this.imageLabels[imageId] += ', ' + labelId;
  1274. added = true;
  1275. }
  1276. if (!added) return;
  1277. data = {
  1278. 'action': 'upfront-media-associate_label',
  1279. 'term': label.id,
  1280. 'post_id': imageId
  1281. };
  1282. Upfront.Util.post(data);
  1283. },
  1284. addToGalleryLabels: function(label) {
  1285. var labelInGallery = false,
  1286. i = 0,
  1287. labelIdAsInt = parseInt(label.id, 10); // if not done labels will be duplicated
  1288. while (i < this.labels.length && !labelInGallery) {
  1289. savedLabelId = parseInt(this.labels[i].id, 10);
  1290. labelInGallery = savedLabelId === labelIdAsInt;
  1291. i++;
  1292. }
  1293. if (!labelInGallery) {
  1294. this.labels.push({
  1295. id: labelIdAsInt.toString(),
  1296. text: label.text
  1297. });
  1298. }
  1299. },
  1300. createLabel: function(text, imageId) {
  1301. //Push a label with a temp id
  1302. var me = this,
  1303. tempId = -parseInt(Math.random() * 100, 10),
  1304. label,
  1305. data;
  1306. label = {
  1307. id: tempId,
  1308. term_id: tempId,
  1309. text: text
  1310. };
  1311. data = {
  1312. 'action': 'upfront-media-add_label',
  1313. 'term': text,
  1314. 'post_id': imageId
  1315. };
  1316. Upfront.data.ugallery.label_names[text] = label;
  1317. Upfront.data.ugallery.label_ids[tempId] = label;
  1318. this.labels.push(label);
  1319. this.imageLabels[imageId] = this.imageLabels[imageId] ? this.imageLabels[imageId] + ', "label_' + tempId + '"' : '"label_' + tempId + '"';
  1320. var deferred = $.Deferred();
  1321. Upfront.Util.post(data)
  1322. .success(function (response) {
  1323. //Replace the temp label
  1324. var thisLabels = response.data[imageId],
  1325. imageLabels = [],
  1326. newId = 0,
  1327. newLabel = {}
  1328. ;
  1329. _.each(thisLabels, function(label){
  1330. imageLabels.push('"label_' + label + '"');
  1331. if(!Upfront.data.ugallery.label_ids[label]) {
  1332. newId = label;
  1333. }
  1334. });
  1335. imageLabels = imageLabels.join(', ');
  1336. newLabel = {
  1337. id: newId,
  1338. text: text
  1339. };
  1340. deferred.resolve(newLabel);
  1341. Upfront.data.ugallery.label_names[text] = newLabel;
  1342. Upfront.data.ugallery.label_ids[newLabel.id] = newLabel;
  1343. delete(Upfront.data.ugallery.label_ids[tempId]);
  1344. me.imageLabels[imageId] = imageLabels;
  1345. _.each(me.labels, function(label){
  1346. if(label.text === text) {
  1347. label.id = newLabel.id;
  1348. }
  1349. });
  1350. me.render();
  1351. });
  1352. return deferred.promise();
  1353. },
  1354. postTypes: function(){
  1355. var types = [];
  1356. _.each(Upfront.data.ugallery.postTypes, function(type){
  1357. if(type.name !== 'attachment') {
  1358. types.push({name: type.name, label: type.label});
  1359. }
  1360. });
  1361. return types;
  1362. },
  1363. getItemElement: function(e){
  1364. return $(e.target).closest('.ugallery_item');
  1365. },
  1366. removeImage: function(e){
  1367. if (!Upfront.Application.user_can_modify_layout()) return false;
  1368. var me = this,
  1369. item = this.getItemElement(e);
  1370. e.preventDefault();
  1371. item.fadeOut('fast', function() {
  1372. var imageId = item.attr('rel');
  1373. me.images.remove(imageId);
  1374. me.imagesChanged();
  1375. if (!me.images.length) {
  1376. me.property('has_settings', 0);
  1377. me.property('status', 'starting');
  1378. }
  1379. //Remove labels
  1380. var labels = me.imageLabels[imageId].split(',');
  1381. _.each(labels, function(label){
  1382. var labelId = $.trim(label.replace('"label_', '').replace('"', ''));
  1383. me.deleteLabel(labelId, imageId);
  1384. });
  1385. me.imageLabels[imageId] = '';
  1386. me.render();
  1387. });
  1388. },
  1389. activateSortable: function(){
  1390. var me = this;
  1391. this.$('.ugallery').sortable({
  1392. items: 'div.ugallery_item:not(.ugallery_addmore)',
  1393. start: function(){
  1394. me.$el.addClass('ugallery_sorting');
  1395. },
  1396. stop: function (){
  1397. me.$el.removeClass('ugallery_sorting');
  1398. },
  1399. update: function() {
  1400. me.sortOk();
  1401. },
  1402. change: function(){
  1403. },
  1404. delay: 500,
  1405. cancel: '.ugallery-thumb-title'
  1406. });
  1407. this.$('.ugallery_item_removing').removeClass('ugallery_item_removing');
  1408. this.$el.addClass('image-sorting-active');
  1409. this.$el.find('.toggle_sorting').addClass('sorting-active');
  1410. $('body').append(_.template(sortingStyleTpl, {
  1411. element_id: this.model.get_property_value_by_name('element_id'),
  1412. thumbPadding: this.model.get_property_value_by_name('thumbPadding'),
  1413. even_padding: this.model.get_property_value_by_name('even_padding'),
  1414. itemsInRow: this.itemsInRow
  1415. }));
  1416. },
  1417. cleanupSortable: function() {
  1418. this.$el.removeClass('image-sorting-active');
  1419. this.$el.find('.toggle_sorting').removeClass('sorting-active');
  1420. if ($('#sorting-style').length > 0) {
  1421. $('#sorting-style').remove();
  1422. }
  1423. },
  1424. sortOk: function() {
  1425. var items = this.$('.ugallery_item'),
  1426. newOrder = [],
  1427. me = this
  1428. ;
  1429. _.each(items, function(item){
  1430. var id = $(item).attr('rel');
  1431. if(id) {
  1432. newOrder.push(me.images.get(id));
  1433. }
  1434. });
  1435. this.images.reset(newOrder);
  1436. },
  1437. activateLightbox: function(){
  1438. var items = [];
  1439. this.$('.ugallery_item').each(function(i, item){
  1440. items.push({
  1441. el: $(item),
  1442. src: $(

Large files files are truncated, but you can click here to view the full file