EntityToolbarView.js 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313
  1. /**
  2. * DO NOT EDIT THIS FILE.
  3. * See the following change record for more information,
  4. * https://www.drupal.org/node/2815083
  5. * @preserve
  6. **/
  7. (function ($, _, Backbone, Drupal, debounce, Popper) {
  8. Drupal.quickedit.EntityToolbarView = Backbone.View.extend({
  9. _fieldToolbarRoot: null,
  10. events: function events() {
  11. var map = {
  12. 'click button.action-save': 'onClickSave',
  13. 'click button.action-cancel': 'onClickCancel',
  14. mouseenter: 'onMouseenter'
  15. };
  16. return map;
  17. },
  18. initialize: function initialize(options) {
  19. var that = this;
  20. this.appModel = options.appModel;
  21. this.$entity = $(this.model.get('el'));
  22. this.listenTo(this.model, 'change:isActive change:isDirty change:state', this.render);
  23. this.listenTo(this.appModel, 'change:highlightedField change:activeField', this.render);
  24. this.listenTo(this.model.get('fields'), 'change:state', this.fieldStateChange);
  25. $(window).on('resize.quickedit scroll.quickedit drupalViewportOffsetChange.quickedit', debounce($.proxy(this.windowChangeHandler, this), 150));
  26. $(document).on('drupalViewportOffsetChange.quickedit', function (event, offsets) {
  27. if (that.$fence) {
  28. that.$fence.css(offsets);
  29. }
  30. });
  31. var $toolbar = this.buildToolbarEl();
  32. this.setElement($toolbar);
  33. this._fieldToolbarRoot = $toolbar.find('.quickedit-toolbar-field').get(0);
  34. this.render();
  35. },
  36. render: function render() {
  37. if (this.model.get('isActive')) {
  38. var $body = $('body');
  39. if ($body.children('#quickedit-entity-toolbar').length === 0) {
  40. $body.append(this.$el);
  41. }
  42. if ($body.children('#quickedit-toolbar-fence').length === 0) {
  43. this.$fence = $(Drupal.theme('quickeditEntityToolbarFence')).css(Drupal.displace()).appendTo($body);
  44. }
  45. this.label();
  46. this.show('ops');
  47. this.position();
  48. }
  49. var $button = this.$el.find('.quickedit-button.action-save');
  50. var isDirty = this.model.get('isDirty');
  51. switch (this.model.get('state')) {
  52. case 'opened':
  53. $button.removeClass('action-saving icon-throbber icon-end').text(Drupal.t('Save')).removeAttr('disabled').attr('aria-hidden', !isDirty);
  54. break;
  55. case 'committing':
  56. $button.addClass('action-saving icon-throbber icon-end').text(Drupal.t('Saving')).attr('disabled', 'disabled');
  57. break;
  58. default:
  59. $button.attr('aria-hidden', true);
  60. break;
  61. }
  62. return this;
  63. },
  64. remove: function remove() {
  65. this.$fence.remove();
  66. $(window).off('resize.quickedit scroll.quickedit drupalViewportOffsetChange.quickedit');
  67. $(document).off('drupalViewportOffsetChange.quickedit');
  68. Backbone.View.prototype.remove.call(this);
  69. },
  70. windowChangeHandler: function windowChangeHandler(event) {
  71. this.position();
  72. },
  73. fieldStateChange: function fieldStateChange(model, state) {
  74. switch (state) {
  75. case 'active':
  76. this.render();
  77. break;
  78. case 'invalid':
  79. this.render();
  80. break;
  81. }
  82. },
  83. position: function position(element) {
  84. clearTimeout(this.timer);
  85. var that = this;
  86. var edge = document.documentElement.dir === 'rtl' ? 'right' : 'left';
  87. var delay = 0;
  88. var check = 0;
  89. var horizontalPadding = 0;
  90. var of = void 0;
  91. var activeField = void 0;
  92. var highlightedField = void 0;
  93. do {
  94. switch (check) {
  95. case 0:
  96. of = element;
  97. break;
  98. case 1:
  99. activeField = Drupal.quickedit.app.model.get('activeField');
  100. of = activeField && activeField.editorView && activeField.editorView.$formContainer && activeField.editorView.$formContainer.find('.quickedit-form');
  101. break;
  102. case 2:
  103. of = activeField && activeField.editorView && activeField.editorView.getEditedElement();
  104. if (activeField && activeField.editorView && activeField.editorView.getQuickEditUISettings().padding) {
  105. horizontalPadding = 5;
  106. }
  107. break;
  108. case 3:
  109. highlightedField = Drupal.quickedit.app.model.get('highlightedField');
  110. of = highlightedField && highlightedField.editorView && highlightedField.editorView.getEditedElement();
  111. delay = 250;
  112. break;
  113. default:
  114. {
  115. var fieldModels = this.model.get('fields').models;
  116. var topMostPosition = 1000000;
  117. var topMostField = null;
  118. for (var i = 0; i < fieldModels.length; i++) {
  119. var pos = fieldModels[i].get('el').getBoundingClientRect().top;
  120. if (pos < topMostPosition) {
  121. topMostPosition = pos;
  122. topMostField = fieldModels[i];
  123. }
  124. }
  125. of = topMostField.get('el');
  126. delay = 50;
  127. break;
  128. }
  129. }
  130. check++;
  131. } while (!of);
  132. function refinePopper(data) {
  133. var isBelow = data.offsets.popper.top > data.offsets.reference.top;
  134. var classListMethod = isBelow ? 'add' : 'remove';
  135. data.instance.popper.classList[classListMethod]('quickedit-toolbar-pointer-top');
  136. if (that.$entity[0] === data.instance.reference) {
  137. var $field = that.$entity.find('.quickedit-editable').eq(isBelow ? -1 : 0);
  138. if ($field.length > 0) {
  139. data.offsets.popper.top = isBelow ? $field.offset().top + $field.outerHeight(true) : $field.offset().top - $(data.instance.reference).outerHeight(true);
  140. }
  141. }
  142. var fenceTop = that.$fence.offset().top;
  143. var fenceHeight = that.$fence.height();
  144. var toolbarHeight = $(data.instance.popper).outerHeight(true);
  145. if (data.offsets.popper.top < fenceTop) {
  146. data.offsets.popper.top = fenceTop;
  147. } else if (data.offsets.popper.top + toolbarHeight > fenceTop + fenceHeight) {
  148. data.offsets.popper.top = fenceTop + fenceHeight - toolbarHeight;
  149. }
  150. }
  151. function positionToolbar() {
  152. var popperElement = that.el;
  153. var referenceElement = of;
  154. var boundariesElement = that.$fence[0];
  155. var popperedge = edge === 'left' ? 'start' : 'end';
  156. if (referenceElement !== undefined) {
  157. if (!popperElement.classList.contains('js-popper-processed')) {
  158. that.popper = new Popper(referenceElement, popperElement, {
  159. placement: 'top-' + popperedge,
  160. modifiers: {
  161. flip: {
  162. behavior: ['top', 'bottom']
  163. },
  164. computeStyle: {
  165. gpuAcceleration: false
  166. },
  167. preventOverflow: {
  168. boundariesElement: boundariesElement
  169. }
  170. },
  171. onCreate: refinePopper,
  172. onUpdate: refinePopper
  173. });
  174. popperElement.classList.add('js-popper-processed');
  175. } else {
  176. that.popper.options.placement = 'top-' + popperedge;
  177. that.popper.reference = referenceElement[0] ? referenceElement[0] : referenceElement;
  178. that.popper.update();
  179. }
  180. }
  181. that.$el.css({
  182. 'max-width': document.documentElement.clientWidth < 450 ? document.documentElement.clientWidth : 450,
  183. 'min-width': document.documentElement.clientWidth < 240 ? document.documentElement.clientWidth : 240,
  184. width: '100%'
  185. });
  186. }
  187. this.timer = setTimeout(function () {
  188. _.defer(positionToolbar);
  189. }, delay);
  190. },
  191. onClickSave: function onClickSave(event) {
  192. event.stopPropagation();
  193. event.preventDefault();
  194. this.model.set('state', 'committing');
  195. },
  196. onClickCancel: function onClickCancel(event) {
  197. event.preventDefault();
  198. this.model.set('state', 'deactivating');
  199. },
  200. onMouseenter: function onMouseenter(event) {
  201. clearTimeout(this.timer);
  202. },
  203. buildToolbarEl: function buildToolbarEl() {
  204. var $toolbar = $(Drupal.theme('quickeditEntityToolbar', {
  205. id: 'quickedit-entity-toolbar'
  206. }));
  207. $toolbar.find('.quickedit-toolbar-entity').prepend(Drupal.theme('quickeditToolgroup', {
  208. classes: ['ops'],
  209. buttons: [{
  210. label: Drupal.t('Save'),
  211. type: 'submit',
  212. classes: 'action-save quickedit-button icon',
  213. attributes: {
  214. 'aria-hidden': true
  215. }
  216. }, {
  217. label: Drupal.t('Close'),
  218. classes: 'action-cancel quickedit-button icon icon-close icon-only'
  219. }]
  220. }));
  221. $toolbar.css({
  222. left: this.$entity.offset().left,
  223. top: this.$entity.offset().top
  224. });
  225. return $toolbar;
  226. },
  227. getToolbarRoot: function getToolbarRoot() {
  228. return this._fieldToolbarRoot;
  229. },
  230. label: function label() {
  231. var label = '';
  232. var entityLabel = this.model.get('label');
  233. var activeField = Drupal.quickedit.app.model.get('activeField');
  234. var activeFieldLabel = activeField && activeField.get('metadata').label;
  235. var highlightedField = Drupal.quickedit.app.model.get('highlightedField');
  236. var highlightedFieldLabel = highlightedField && highlightedField.get('metadata').label;
  237. if (activeFieldLabel) {
  238. label = Drupal.theme('quickeditEntityToolbarLabel', {
  239. entityLabel: entityLabel,
  240. fieldLabel: activeFieldLabel
  241. });
  242. } else if (highlightedFieldLabel) {
  243. label = Drupal.theme('quickeditEntityToolbarLabel', {
  244. entityLabel: entityLabel,
  245. fieldLabel: highlightedFieldLabel
  246. });
  247. } else {
  248. label = Drupal.checkPlain(entityLabel);
  249. }
  250. this.$el.find('.quickedit-toolbar-label').html(label);
  251. },
  252. addClass: function addClass(toolgroup, classes) {
  253. this._find(toolgroup).addClass(classes);
  254. },
  255. removeClass: function removeClass(toolgroup, classes) {
  256. this._find(toolgroup).removeClass(classes);
  257. },
  258. _find: function _find(toolgroup) {
  259. return this.$el.find('.quickedit-toolbar .quickedit-toolgroup.' + toolgroup);
  260. },
  261. show: function show(toolgroup) {
  262. this.$el.removeClass('quickedit-animate-invisible');
  263. }
  264. });
  265. })(jQuery, _, Backbone, Drupal, Drupal.debounce, Popper);