From 5e02fedcccb8b8cbbb56eaf993fd055f9fae5bb6 Mon Sep 17 00:00:00 2001 From: Alex-D Date: Sun, 3 Mar 2024 18:42:03 +0100 Subject: [PATCH] refactor(giphy): use fetch instead of $.ajax --- plugins/giphy/trumbowyg.giphy.js | 465 +++++++++++---------- plugins/giphy/ui/sass/trumbowyg.giphy.scss | 2 +- 2 files changed, 241 insertions(+), 226 deletions(-) diff --git a/plugins/giphy/trumbowyg.giphy.js b/plugins/giphy/trumbowyg.giphy.js index 2fba21eed..e181595a7 100644 --- a/plugins/giphy/trumbowyg.giphy.js +++ b/plugins/giphy/trumbowyg.giphy.js @@ -1,238 +1,253 @@ +/* global AbortController: true */ (function ($) { - 'use strict'; - - $.extend(true, $.trumbowyg, { - langs: { - // jshint camelcase:false - en: { - giphy: 'Insert GIF', - }, - az: { - giphy: 'GIF yerləşdir', - }, - by: { - giphy: 'Уставіць GIF', - }, - de: { - giphy: 'GIF einfügen', - }, - et: { - giphy: 'Sisesta GIF', - }, - fr: { - giphy: 'Insérer un GIF', - }, - hu: { - giphy: 'GIF beszúrás', - }, - ru: { - giphy: 'Вставить GIF', - }, - sl: { - giphy: 'Vstavi GIF', - }, - tr: { - giphy: 'GIF ekle', - }, - // jshint camelcase:true - } - }); - - var giphyLogo = ''; // jshint ignore:line - - var CANCEL_EVENT = 'tbwcancel'; - - // Throttle helper - function trumbowygThrottle(callback, delay) { - var last; - var timer; - - return function () { - var context = this; - var now = +new Date(); - var args = arguments; - - if (last && now < last + delay) { - clearTimeout(timer); - timer = setTimeout(function () { - last = now; - callback.apply(context, args); - }, delay); - } else { - last = now; - callback.apply(context, args); - } - }; - } - - // Fills modal with response gifs - function renderGifs(response, $giphyModal, trumbowyg, mustEmpty) { - var width = ($giphyModal.width() - 20) / 3; - - var html = response.data - .filter(function (gifData) { - // jshint camelcase:false - var downsized = gifData.images.downsized || gifData.images.downsized_medium; - // jshint camelcase:true - return !!downsized.url; - }) - .map(function (gifData) { - // jshint camelcase:false - var downsized = gifData.images.downsized || gifData.images.downsized_medium; - // jshint camelcase:true - var image = downsized, - imageRatio = image.height / image.width, - altText = gifData.title; - - var imgHtml = '' + altText + ''; - return '
' + imgHtml + '
'; - }) - .join('') - ; - - if (mustEmpty === true) { - if (html.length === 0) { - if ($('.' + trumbowyg.o.prefix + 'giphy-no-result', $giphyModal).length > 0) { - return; - } - - html = ''; - } + 'use strict'; - $giphyModal.empty(); - } - $giphyModal.append(html); - - // Remove gray overlay on image load - // moved here from inline callback definition due to CSP issue - // Note: this is being done post-factum because load event doesn't bubble up and so can't be delegated - var addLoadedClass = function (img) { img.classList.add('tbw-loaded'); }; - $('img', $giphyModal).each(function (){ - var img = this; - if (img.complete){ // images load instantly when cached and esp. when loaded in previous modal open - addLoadedClass(img); - } else { - img.addEventListener('load', function(){ addLoadedClass(this); }); - } - }); - - $('img', $giphyModal).on('click', function () { - var src = $(this).attr('src'), - alt = $(this).attr('alt'); - trumbowyg.restoreRange(); - trumbowyg.execCmd('insertImage', src, false, true); - - // relay alt tag into inserted image - if (alt){ - var $img = $('img[src="' + src + '"]:not([alt])',trumbowyg.$box); - $img.attr('alt', alt); - // Note: This seems to fire relatively early and could be wrapped in a setTimeout if needed - trumbowyg.syncCode(); - } - $('img', $giphyModal).off(); - trumbowyg.closeModal(); + $.extend(true, $.trumbowyg, { + langs: { + // jshint camelcase:false + en: { + giphy: 'Insert GIF' + }, + az: { + giphy: 'GIF yerləşdir' + }, + by: { + giphy: 'Уставіць GIF' + }, + de: { + giphy: 'GIF einfügen' + }, + et: { + giphy: 'Sisesta GIF' + }, + fr: { + giphy: 'Insérer un GIF' + }, + hu: { + giphy: 'GIF beszúrás' + }, + ru: { + giphy: 'Вставить GIF' + }, + sl: { + giphy: 'Vstavi GIF' + }, + tr: { + giphy: 'GIF ekle' + } + // jshint camelcase:true + } }); - } - - var defaultOptions = { - rating: 'g', - apiKey: null, - throttleDelay: 300, - noResultGifUrl: 'https://media.giphy.com/media/2Faz9FbRzmwxY0pZS/giphy.gif' - }; - - // Add dropdown with font sizes - $.extend(true, $.trumbowyg, { - plugins: { - giphy: { - init: function (trumbowyg) { - trumbowyg.o.plugins.giphy = $.extend({}, - defaultOptions, - trumbowyg.o.plugins.giphy || {} - ); - - trumbowyg.addBtnDef('giphy', { - fn: function() { - if (trumbowyg.o.plugins.giphy.apiKey === null) { - throw new Error('You must set a Giphy API Key'); - } - - var BASE_URL = 'https://api.giphy.com/v1/gifs/search?api_key=' + trumbowyg.o.plugins.giphy.apiKey + '&rating=' + trumbowyg.o.plugins.giphy.rating, - DEFAULT_URL = BASE_URL.replace('/search', '/trending'); - var previousAjaxCall = {abort: function () {}}; - var prefix = trumbowyg.o.prefix; - - // Create and open the modal - var searchInput = '', - closeButton = '', - poweredByGiphy = '
Powered by' + giphyLogo + '
', - giphyModalHtml = searchInput + closeButton + poweredByGiphy + '
'; - - trumbowyg - .openModal(null, giphyModalHtml, false) - .one(CANCEL_EVENT, function () { - try { - previousAjaxCall.abort(); - } catch (e) {} - - trumbowyg.closeModal(); - }); - - var $giphyInput = $('.' + prefix + 'giphy-search'), - $giphyClose = $('.' + prefix + 'giphy-close'), - $giphyModal = $('.' + prefix + 'giphy-modal'); - - var ajaxError = function () { - if (!navigator.onLine && !$('.' + prefix + 'giphy-offline', $giphyModal).length) { - $giphyModal.empty(); - $giphyModal.append('

You are offline

'); - } - }; - - // Load trending gifs as default - $.ajax({ - url: DEFAULT_URL, - dataType: 'json', - success: function(response) { - renderGifs(response, $giphyModal, trumbowyg, true); - }, - error: ajaxError - }); - - var searchGifsOnInput = function () { - var query = $giphyInput.val(); + var giphyLogo = ''; // jshint ignore:line + + var CANCEL_EVENT = 'tbwcancel'; + + // Throttle helper + function trumbowygThrottle(callback, delay) { + var last; + var timer; + + return function () { + var context = this; + var now = new Date().getTime(); + var args = arguments; + + if (last && now < last + delay) { + clearTimeout(timer); + timer = setTimeout(function () { + last = now; + callback.apply(context, args); + }, delay); + } else { + last = now; + callback.apply(context, args); + } + }; + } - if (query.length === 0) { - return; + // Fills modal with response gifs + function renderGifs(response, $giphyModal, trumbowyg, mustEmpty) { + var width = ($giphyModal.width() - 20) / 3; + + var html = response.data + .filter(function (gifData) { + // jshint camelcase:false + var downsized = gifData.images.downsized || gifData.images.downsized_medium; + // jshint camelcase:true + return !!downsized.url; + }) + .map(function (gifData) { + // jshint camelcase:false + var downsized = gifData.images.downsized || gifData.images.downsized_medium; + // jshint camelcase:true + var image = downsized, + imageRatio = image.height / image.width, + altText = gifData.title; + + var imgHtml = '' + altText + ''; + return '
' + imgHtml + '
'; + }) + .join('') + ; + + if (mustEmpty === true) { + if (html.length === 0) { + if ($('.' + trumbowyg.o.prefix + 'giphy-no-result', $giphyModal).length > 0) { + return; } - try { - previousAjaxCall.abort(); - } catch (e) {} + html = ''; + } - previousAjaxCall = $.ajax({ - url: BASE_URL + '&q=' + encodeURIComponent(query), - dataType: 'json', - - success: function(response) { - renderGifs(response, $giphyModal, trumbowyg, true); - }, - error: ajaxError + $giphyModal.empty(); + } + $giphyModal.append(html); + + // Remove gray overlay on image load + // moved here from inline callback definition due to CSP issue + // Note: this is being done post-factum because load event doesn't bubble up and so can't be delegated + var addLoadedClass = function (img) { + img.classList.add('tbw-loaded'); + }; + $('img', $giphyModal).each(function () { + var img = this; + if (img.complete) { // images load instantly when cached and esp. when loaded in previous modal open + addLoadedClass(img); + } else { + img.addEventListener('load', function () { + addLoadedClass(this); }); - }; - var throttledInputRequest = trumbowygThrottle(searchGifsOnInput, trumbowyg.o.plugins.giphy.throttleDelay); + } + }); + + $('img', $giphyModal).on('click', function () { + var src = $(this).attr('src'), + alt = $(this).attr('alt'); + trumbowyg.restoreRange(); + trumbowyg.execCmd('insertImage', src, false, true); + + // relay alt tag into inserted image + if (alt) { + var $img = $('img[src="' + src + '"]:not([alt])', trumbowyg.$box); + $img.attr('alt', alt); + // Note: This seems to fire relatively early and could be wrapped in a setTimeout if needed + trumbowyg.syncCode(); + } + $('img', $giphyModal).off(); + trumbowyg.closeModal(); + }); + } - $giphyInput.on('input', throttledInputRequest); - $giphyInput.focus(); + var defaultOptions = { + rating: 'g', + apiKey: null, + throttleDelay: 300, + noResultGifUrl: 'https://media.giphy.com/media/2Faz9FbRzmwxY0pZS/giphy.gif' + }; - $giphyClose.one('click', function() { - $giphyModal.trigger(CANCEL_EVENT); - }); - }, - }); + // Add dropdown with font sizes + $.extend(true, $.trumbowyg, { + plugins: { + giphy: { + init: function (trumbowyg) { + trumbowyg.o.plugins.giphy = $.extend({}, + defaultOptions, + trumbowyg.o.plugins.giphy || {} + ); + + trumbowyg.addBtnDef('giphy', { + fn: function () { + if (trumbowyg.o.plugins.giphy.apiKey === null) { + throw new Error('You must set a Giphy API Key'); + } + + var BASE_URL = 'https://api.giphy.com/v1/gifs/search?api_key=' + trumbowyg.o.plugins.giphy.apiKey + '&rating=' + trumbowyg.o.plugins.giphy.rating, + DEFAULT_URL = BASE_URL.replace('/search', '/trending'); + var prefix = trumbowyg.o.prefix; + var abortController = new AbortController(); + + // Create and open the modal + var searchInput = '', + closeButton = '', + poweredByGiphy = '
Powered by' + giphyLogo + '
', + giphyModalHtml = searchInput + closeButton + poweredByGiphy + '
'; + + trumbowyg + .openModal(null, giphyModalHtml, false) + .one(CANCEL_EVENT, function () { + try { + abortController.abort(); + abortController = new AbortController(); + } catch (e) { + } + + trumbowyg.closeModal(); + }); + + var $giphyInput = $('.' + prefix + 'giphy-search'), + $giphyClose = $('.' + prefix + 'giphy-close'), + $giphyModal = $('.' + prefix + 'giphy-modal'); + + var onError = function () { + if (navigator.onLine || $('.' + prefix + 'giphy-offline', $giphyModal).length) { + return; + } + + $giphyModal.empty(); + $giphyModal.append('

You are offline

'); + }; + + // Load trending gifs as default + fetch(DEFAULT_URL, { + method: 'GET', + cache: 'no-cache', + signal: abortController.signal + }).then((response) => { + response.json().then((responseJson) => { + renderGifs(responseJson, $giphyModal, trumbowyg, true); + }); + }).catch(() => { + onError(); + }); + + var searchGifsOnInput = function () { + var query = $giphyInput.val(); + + if (query.length === 0) { + return; + } + + try { + abortController.abort(); + abortController = new AbortController(); + } catch (e) { + } + + fetch(BASE_URL + '&q=' + encodeURIComponent(query), { + method: 'GET', + cache: 'no-cache', + signal: abortController.signal + }).then((response) => { + response.json().then((responseJson) => { + renderGifs(responseJson, $giphyModal, trumbowyg, true); + }); + }).catch(() => { + onError(); + }); + }; + var throttledInputRequest = trumbowygThrottle(searchGifsOnInput, trumbowyg.o.plugins.giphy.throttleDelay); + + $giphyInput.on('input', throttledInputRequest); + $giphyInput.focus(); + + $giphyClose.one('click', function () { + $giphyModal.trigger(CANCEL_EVENT); + }); + } + }); + } + } } - } - } - }); + }); })(jQuery); diff --git a/plugins/giphy/ui/sass/trumbowyg.giphy.scss b/plugins/giphy/ui/sass/trumbowyg.giphy.scss index b2bed8d99..6a5ea4cd1 100644 --- a/plugins/giphy/ui/sass/trumbowyg.giphy.scss +++ b/plugins/giphy/ui/sass/trumbowyg.giphy.scss @@ -46,7 +46,7 @@ svg { width: 66px; height: 15px; - vertical-align: bottom; + vertical-align: middle; margin-left: 6px; opacity: 0.45; }