From c343893d004fd8596b6c31b7437b97f59e14a3e6 Mon Sep 17 00:00:00 2001 From: Paul Chavard Date: Tue, 9 Oct 2018 11:32:27 +0200 Subject: [PATCH 1/8] Expose all utils function as @utils --- app/javascript/shared/utils.js | 44 ++++++++++++++++++++++++++++++++++ config/webpack/environment.js | 9 +++++++ 2 files changed, 53 insertions(+) diff --git a/app/javascript/shared/utils.js b/app/javascript/shared/utils.js index 9339dd07f..8270f4d70 100644 --- a/app/javascript/shared/utils.js +++ b/app/javascript/shared/utils.js @@ -1,3 +1,10 @@ +import Rails from 'rails-ujs'; +import $ from 'jquery'; +import debounce from 'debounce'; + +export { debounce }; +export const { fire } = Rails; + export function show({ classList }) { classList.remove('hidden'); } @@ -9,3 +16,40 @@ export function hide({ classList }) { export function toggle({ classList }) { classList.toggle('hidden'); } + +export function delegate(eventNames, selector, callback) { + eventNames + .split(' ') + .forEach(eventName => + Rails.delegate(document, selector, eventName, callback) + ); +} + +export function getJSON(url, data, method = 'get') { + data = method !== 'get' ? JSON.stringify(data) : data; + return $.ajax({ + method, + url, + data, + contentType: 'application/json', + dataType: 'json' + }); +} + +export function scrollTo(container, scrollTo) { + $(container).scrollTop( + $(scrollTo).offset().top - + $(container).offset().top + + $(container).scrollTop() + ); +} + +export function scrollToBottom(container) { + $(container).scrollTop(container.scrollHeight); +} + +export function on(selector, eventName, fn) { + [...document.querySelectorAll(selector)].forEach(element => + element.addEventListener(eventName, event => fn(event, event.detail)) + ); +} diff --git a/config/webpack/environment.js b/config/webpack/environment.js index d261e8336..6016319bc 100644 --- a/config/webpack/environment.js +++ b/config/webpack/environment.js @@ -1,3 +1,4 @@ +const path = require('path'); const { environment } = require('@rails/webpacker'); // By default don't transpile JS files in ./node_modules – except for some specific modules. @@ -14,4 +15,12 @@ babelLoader.exclude = function(modulePath) { ); }; +const resolve = { + alias: { + '@utils': path.resolve(__dirname, '..', '..', 'app/javascript/shared/utils') + } +}; + +environment.config.merge({ resolve }); + module.exports = environment; From 8c16eb4cd0b895c47cbe733ff5d3e3725063a1f1 Mon Sep 17 00:00:00 2001 From: Paul Chavard Date: Tue, 9 Oct 2018 11:35:22 +0200 Subject: [PATCH 2/8] Use @utils instead of jQuery --- app/javascript/new_design/carto.js | 6 +++--- app/javascript/new_design/dropdown.js | 8 +++----- app/javascript/new_design/spinner.js | 11 ++++------- app/javascript/shared/autocomplete.js | 6 +++--- app/javascript/shared/rails-ujs-fix.js | 3 ++- app/javascript/shared/remote-input.js | 7 ++----- 6 files changed, 17 insertions(+), 24 deletions(-) diff --git a/app/javascript/new_design/carto.js b/app/javascript/new_design/carto.js index 11fbbe75d..895a613ba 100644 --- a/app/javascript/new_design/carto.js +++ b/app/javascript/new_design/carto.js @@ -1,5 +1,5 @@ -import $ from 'jquery'; import L from 'leaflet'; +import { getJSON } from '@utils'; import { getData } from '../shared/data'; import { DEFAULT_POSITION } from '../shared/carto'; @@ -11,8 +11,8 @@ import { } from './carto/draw'; function initialize() { - if ($('#map').length > 0) { - $.getJSON(getData('carto').getPositionUrl).then( + if (document.getElementById('map')) { + getJSON(getData('carto').getPositionUrl).then( position => initializeWithPosition(position), () => initializeWithPosition(DEFAULT_POSITION) ); diff --git a/app/javascript/new_design/dropdown.js b/app/javascript/new_design/dropdown.js index 2829b98d8..13d8965c2 100644 --- a/app/javascript/new_design/dropdown.js +++ b/app/javascript/new_design/dropdown.js @@ -1,8 +1,6 @@ -import Rails from 'rails-ujs'; +import { delegate } from '@utils'; -const { delegate } = Rails; - -delegate(document, 'body', 'click', event => { +delegate('click', 'body', event => { if (!event.target.closest('.dropdown')) { [...document.querySelectorAll('.dropdown')].forEach(element => element.classList.remove('open', 'fade-in-down') @@ -10,7 +8,7 @@ delegate(document, 'body', 'click', event => { } }); -delegate(document, '.dropdown-button', 'click', event => { +delegate('click', '.dropdown-button', event => { event.stopPropagation(); const parent = event.target.closest('.dropdown-button').parentElement; if (parent.classList.contains('dropdown')) { diff --git a/app/javascript/new_design/spinner.js b/app/javascript/new_design/spinner.js index 7c92ca53b..8b1fbac3e 100644 --- a/app/javascript/new_design/spinner.js +++ b/app/javascript/new_design/spinner.js @@ -1,7 +1,4 @@ -import Rails from 'rails-ujs'; -import { show, hide } from '../shared/utils'; - -const { delegate } = Rails; +import { show, hide, delegate } from '@utils'; function showSpinner() { [...document.querySelectorAll('.spinner')].forEach(show); @@ -11,6 +8,6 @@ function hideSpinner() { [...document.querySelectorAll('.spinner')].forEach(hide); } -delegate(document, '[data-spinner]', 'ajax:complete', hideSpinner); -delegate(document, '[data-spinner]', 'ajax:stopped', hideSpinner); -delegate(document, '[data-spinner]', 'ajax:send', showSpinner); +delegate('ajax:complete', '[data-spinner]', hideSpinner); +delegate('ajax:stopped', '[data-spinner]', hideSpinner); +delegate('ajax:send', '[data-spinner]', showSpinner); diff --git a/app/javascript/shared/autocomplete.js b/app/javascript/shared/autocomplete.js index 727ae172a..809373bf1 100644 --- a/app/javascript/shared/autocomplete.js +++ b/app/javascript/shared/autocomplete.js @@ -1,5 +1,5 @@ -import $ from 'jquery'; import autocomplete from 'autocomplete.js'; +import { getJSON, fire } from '@utils'; const sources = [ { @@ -24,7 +24,7 @@ function selector(type) { function source(url) { return { source(query, callback) { - $.getJSON(url, { request: query }).then(callback); + getJSON(url, { request: query }).then(callback); }, templates: { suggestion({ label, mine }) { @@ -41,7 +41,7 @@ addEventListener('turbolinks:load', function() { for (let target of document.querySelectorAll(selector(type))) { let select = autocomplete(target, options, [source(url)]); select.on('autocomplete:selected', ({ target }, suggestion) => { - $(target).trigger('autocomplete:select', suggestion); + fire(target, 'autocomplete:select', suggestion); select.autocomplete.setVal(suggestion.label); }); } diff --git a/app/javascript/shared/rails-ujs-fix.js b/app/javascript/shared/rails-ujs-fix.js index a7cc7eb5e..f36330901 100644 --- a/app/javascript/shared/rails-ujs-fix.js +++ b/app/javascript/shared/rails-ujs-fix.js @@ -1,12 +1,13 @@ import Rails from 'rails-ujs'; import jQuery from 'jquery'; +import { delegate } from '@utils'; // We use `jQuery.active` in our capybara suit to wait for ajax requests. // Newer jQuery-less version of rails-ujs is breaking it. // We have to set `ajax:complete` listener on the same element as the one // we catch ajax:send on as by the end of the request // the old element may be removed from DOM. -Rails.delegate(document, '[data-remote]', 'ajax:send', ({ target }) => { +delegate('ajax:send', '[data-remote]', ({ target }) => { let callback = () => { jQuery.active--; target.removeEventListener('ajax:complete', callback); diff --git a/app/javascript/shared/remote-input.js b/app/javascript/shared/remote-input.js index d03e69640..e265a1835 100644 --- a/app/javascript/shared/remote-input.js +++ b/app/javascript/shared/remote-input.js @@ -1,7 +1,4 @@ -import Rails from 'rails-ujs'; -import debounce from 'debounce'; - -const { delegate, fire } = Rails; +import { delegate, fire, debounce } from '@utils'; const remote = 'data-remote'; const inputChangeSelector = `input[${remote}], textarea[${remote}]`; @@ -21,4 +18,4 @@ function isRemote(element) { return value && value !== 'false'; } -delegate(document, inputChangeSelector, 'input', debounce(handleRemote, 200)); +delegate('input', inputChangeSelector, debounce(handleRemote, 200)); From d18b1c8ddc0f5ba84e2ba534e0d2c782f6d29f06 Mon Sep 17 00:00:00 2001 From: Paul Chavard Date: Tue, 9 Oct 2018 11:43:25 +0200 Subject: [PATCH 3/8] Refactor form validation helpers --- app/javascript/new_design/form-validation.js | 23 ++++++++++++++------ 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/app/javascript/new_design/form-validation.js b/app/javascript/new_design/form-validation.js index 06b9c161c..9f0b74184 100644 --- a/app/javascript/new_design/form-validation.js +++ b/app/javascript/new_design/form-validation.js @@ -1,10 +1,19 @@ -import $ from 'jquery'; +import { delegate } from '@utils'; -$(document).on('blur keydown', 'input, textarea', () => { - $(this).addClass('touched'); +delegate('blur keydown', 'input, textarea', ({ target }) => { + touch(target); }); -$(document).on('click', 'input[type="submit"]:not([formnovalidate])', () => { - const $form = $(this).closest('form'); - $('input, textarea', $form).addClass('touched'); -}); +delegate( + 'click', + 'input[type="submit"]:not([formnovalidate])', + ({ target }) => { + let form = target.closest('form'); + let inputs = form ? form.querySelectorAll('input, textarea') : []; + [...inputs].forEach(touch); + } +); + +function touch({ classList }) { + classList.add('touched'); +} From 3897d4abf41395d64b641741b22776badb658aaa Mon Sep 17 00:00:00 2001 From: Paul Chavard Date: Tue, 9 Oct 2018 11:43:38 +0200 Subject: [PATCH 4/8] Refactor messagerie helpers --- app/javascript/new_design/messagerie.js | 24 +++++++----------------- app/javascript/shared/utils.js | 17 +++++++++++------ 2 files changed, 18 insertions(+), 23 deletions(-) diff --git a/app/javascript/new_design/messagerie.js b/app/javascript/new_design/messagerie.js index a7dd2bc39..91e9190db 100644 --- a/app/javascript/new_design/messagerie.js +++ b/app/javascript/new_design/messagerie.js @@ -1,27 +1,17 @@ -import $ from 'jquery'; +import { scrollTo, scrollToBottom } from '@utils'; export function scrollMessagerie() { - const $ul = $('.messagerie ul').first(); + const ul = document.querySelector('.messagerie ul'); - if ($ul.length) { - const $elementToScroll = $('.date.highlighted').first(); + if (ul) { + const elementToScroll = document.querySelector('.date.highlighted'); - if ($elementToScroll.length != 0) { - scrollTo($ul, $elementToScroll); + if (elementToScroll) { + scrollTo(ul, elementToScroll); } else { - scrollToBottom($ul); + scrollToBottom(ul); } } } -function scrollTo($container, $scrollTo) { - $container.scrollTop( - $scrollTo.offset().top - $container.offset().top + $container.scrollTop() - ); -} - -function scrollToBottom($container) { - $container.scrollTop($container.prop('scrollHeight')); -} - addEventListener('turbolinks:load', scrollMessagerie); diff --git a/app/javascript/shared/utils.js b/app/javascript/shared/utils.js index 8270f4d70..9b413e98b 100644 --- a/app/javascript/shared/utils.js +++ b/app/javascript/shared/utils.js @@ -37,15 +37,12 @@ export function getJSON(url, data, method = 'get') { } export function scrollTo(container, scrollTo) { - $(container).scrollTop( - $(scrollTo).offset().top - - $(container).offset().top + - $(container).scrollTop() - ); + container.scrollTop = + offset(scrollTo).top - offset(container).top + container.scrollTop; } export function scrollToBottom(container) { - $(container).scrollTop(container.scrollHeight); + container.scrollTop = container.scrollHeight; } export function on(selector, eventName, fn) { @@ -53,3 +50,11 @@ export function on(selector, eventName, fn) { element.addEventListener(eventName, event => fn(event, event.detail)) ); } + +function offset(element) { + const rect = element.getBoundingClientRect(); + return { + top: rect.top + document.body.scrollTop, + left: rect.left + document.body.scrollLeft + }; +} From 9d5ffba0687d3a6a1de64b30d5b7d692f2b15c8f Mon Sep 17 00:00:00 2001 From: Paul Chavard Date: Tue, 9 Oct 2018 11:43:51 +0200 Subject: [PATCH 5/8] Refactor state button helpers --- app/assets/stylesheets/new_design/motivation.scss | 1 - app/javascript/new_design/state-button.js | 10 +++++----- .../dossiers/_state_button_motivation.html.haml | 2 +- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/app/assets/stylesheets/new_design/motivation.scss b/app/assets/stylesheets/new_design/motivation.scss index 52781f9b2..5adcbc78b 100644 --- a/app/assets/stylesheets/new_design/motivation.scss +++ b/app/assets/stylesheets/new_design/motivation.scss @@ -2,7 +2,6 @@ @import "constants"; .motivation { - display: none; padding: $default-padding; color: $black; width: 450px; diff --git a/app/javascript/new_design/state-button.js b/app/javascript/new_design/state-button.js index 0f0983a41..da47340fd 100644 --- a/app/javascript/new_design/state-button.js +++ b/app/javascript/new_design/state-button.js @@ -1,12 +1,12 @@ -import $ from 'jquery'; +import { show, hide } from '@utils'; export function showMotivation(event, state) { event.preventDefault(); - $(`.motivation.${state}`).show(); - $('.dropdown-items').hide(); + show(document.querySelector(`.motivation.${state}`)); + hide(document.querySelector('.dropdown-items')); } export function motivationCancel() { - $('.motivation').hide(); - $('.dropdown-items').show(); + document.querySelectorAll('.motivation').forEach(hide); + show(document.querySelector('.dropdown-items')); } diff --git a/app/views/new_gestionnaire/dossiers/_state_button_motivation.html.haml b/app/views/new_gestionnaire/dossiers/_state_button_motivation.html.haml index d72c793e7..99a6dfc88 100644 --- a/app/views/new_gestionnaire/dossiers/_state_button_motivation.html.haml +++ b/app/views/new_gestionnaire/dossiers/_state_button_motivation.html.haml @@ -1,4 +1,4 @@ -.motivation{ class: popup_class } +.motivation.hidden{ class: popup_class } %h3 %span.icon{ class: popup_class } #{popup_title} From 08d5e7d328828e4ebdf5fde3a94f3488c1edd2e1 Mon Sep 17 00:00:00 2001 From: Paul Chavard Date: Tue, 9 Oct 2018 11:44:02 +0200 Subject: [PATCH 6/8] Refactor toggle chart helpers --- app/javascript/new_design/toggle-chart.js | 32 ++++++++++------------- 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/app/javascript/new_design/toggle-chart.js b/app/javascript/new_design/toggle-chart.js index b51622402..2de8b6394 100644 --- a/app/javascript/new_design/toggle-chart.js +++ b/app/javascript/new_design/toggle-chart.js @@ -1,28 +1,24 @@ -import $ from 'jquery'; import Chartkick from 'chartkick'; +import { toggle } from '@utils'; export function toggleChart(event, chartClass) { - const nextSelectorItem = $(event.target), - nextChart = $(chartClass), - nextChartId = nextChart - .children() - .first() - .attr('id'), - currentSelectorItem = nextSelectorItem - .parent() - .find('.segmented-control-item-active'), - currentChart = nextSelectorItem - .parent() - .parent() - .find('.chart:not(.hidden)'); + const nextSelectorItem = event.target, + nextChart = document.querySelector(chartClass), + nextChartId = nextChart.children[0].id, + currentSelectorItem = nextSelectorItem.parentElement.querySelector( + '.segmented-control-item-active' + ), + currentChart = nextSelectorItem.parentElement.parentElement.querySelector( + '.chart:not(.hidden)' + ); // Change the current selector and the next selector states - currentSelectorItem.toggleClass('segmented-control-item-active'); - nextSelectorItem.toggleClass('segmented-control-item-active'); + currentSelectorItem.classList.toggle('segmented-control-item-active'); + nextSelectorItem.classList.toggle('segmented-control-item-active'); // Hide the currently shown chart and show the new one - currentChart.toggleClass('hidden'); - nextChart.toggleClass('hidden'); + toggle(currentChart); + toggle(nextChart); // Reflow needed, see https://github.com/highcharts/highcharts/issues/1979 Chartkick.charts[nextChartId].getChartObject().reflow(); From b79e77687e30c6c190517bd99eb7bfcb78c729fc Mon Sep 17 00:00:00 2001 From: Paul Chavard Date: Wed, 10 Oct 2018 14:53:59 +0200 Subject: [PATCH 7/8] Refactor avis helpers --- app/assets/stylesheets/new_design/avis.scss | 1 - app/javascript/new_design/avis.js | 4 ++-- app/views/new_gestionnaire/shared/avis/_form.html.haml | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/app/assets/stylesheets/new_design/avis.scss b/app/assets/stylesheets/new_design/avis.scss index 51930f4bc..0217f3d76 100644 --- a/app/assets/stylesheets/new_design/avis.scss +++ b/app/assets/stylesheets/new_design/avis.scss @@ -65,7 +65,6 @@ } .confidentiel-explanation { - display: none; font-size: 14px; color: $grey; margin-top: -$default-padding; diff --git a/app/javascript/new_design/avis.js b/app/javascript/new_design/avis.js index c35fdc6eb..99b4f869c 100644 --- a/app/javascript/new_design/avis.js +++ b/app/javascript/new_design/avis.js @@ -1,5 +1,5 @@ -import $ from 'jquery'; +import { toggle } from '@utils'; export function toggleCondidentielExplanation() { - $('.confidentiel-explanation').toggle(); + toggle(document.querySelector('.confidentiel-explanation')); } diff --git a/app/views/new_gestionnaire/shared/avis/_form.html.haml b/app/views/new_gestionnaire/shared/avis/_form.html.haml index c429b8103..29aefebfa 100644 --- a/app/views/new_gestionnaire/shared/avis/_form.html.haml +++ b/app/views/new_gestionnaire/shared/avis/_form.html.haml @@ -17,7 +17,7 @@ .confidentiel-wrapper = f.label :confidentiel, 'Cet avis est' = f.select :confidentiel, [['partagé avec les autres experts', false], ['confidentiel', true]], {}, onchange: "javascript:DS.toggleCondidentielExplanation(event);" - .confidentiel-explanation + .confidentiel-explanation.hidden Il ne sera pas affiché aux autres experts consultés mais sera visible par les instructeurs .send-wrapper = f.submit 'Demander un avis', class: 'button send' From 136031bea455b66afecf8704f1a64c5d3d4960e9 Mon Sep 17 00:00:00 2001 From: Paul Chavard Date: Tue, 9 Oct 2018 11:44:24 +0200 Subject: [PATCH 8/8] Remove jQuery import from new design --- app/javascript/packs/application.js | 6 ------ 1 file changed, 6 deletions(-) diff --git a/app/javascript/packs/application.js b/app/javascript/packs/application.js index 758b934fa..530b94bdf 100644 --- a/app/javascript/packs/application.js +++ b/app/javascript/packs/application.js @@ -4,7 +4,6 @@ import Rails from 'rails-ujs'; import ActiveStorage from '../shared/activestorage/ujs'; import Chartkick from 'chartkick'; import Highcharts from 'highcharts'; -import jQuery from 'jquery'; import '../shared/sentry'; import '../shared/rails-ujs-fix'; @@ -41,11 +40,6 @@ Rails.start(); Turbolinks.start(); ActiveStorage.start(); -// Disable jQuery-driven animations during tests -if (process.env['RAILS_ENV'] === 'test') { - jQuery.fx.off = true; -} - // Expose globals window.DS = window.DS || DS; window.Chartkick = Chartkick;