| @@ -11,21 +11,97 @@ | ||
| 11 | 11 | * |
| 12 | 12 | */ |
| 13 | 13 | |
| 14 | 14 | jQuery(function($) { |
| 15 | + const MSHOT_REFRESH_DELAY = 6000; | |
| 16 | + const MSHOT_REFRESH_QUERY_ARG = 'mainwp_mshot_refresh'; | |
| 15 | 17 | |
| 18 | + function mainwp_preview_append_cache_bust(url, token) { | |
| 19 | + if (!url) { | |
| 20 | + return url; | |
| 21 | + } | |
| 22 | + | |
| 23 | + let separator = url.indexOf('?') === -1 ? '?' : '&'; | |
| 24 | + | |
| 25 | + return url + separator + MSHOT_REFRESH_QUERY_ARG + '=' + encodeURIComponent(token + '-' + Date.now()); | |
| 26 | + } | |
| 27 | + | |
| 28 | + function mainwp_preview_get_button_mshot_url(element, requeue) { | |
| 29 | + let attrName = requeue ? 'data-mainwp-mshot-requeue-src' : 'data-mainwp-mshot-src'; | |
| 30 | + let mshotUrl = $(element).attr(attrName); | |
| 31 | + | |
| 32 | + if (mshotUrl) { | |
| 33 | + return mshotUrl; | |
| 34 | + } | |
| 35 | + | |
| 36 | + let linkUrl = $(element).attr('preview-site-url'); | |
| 37 | + | |
| 38 | + if (!linkUrl) { | |
| 39 | + return ''; | |
| 40 | + } | |
| 41 | + | |
| 42 | + mshotUrl = '//s0.wp.com/mshots/v1/' + encodeURIComponent(linkUrl) + '?w=900'; | |
| 43 | + | |
| 44 | + if (requeue) { | |
| 45 | + mshotUrl += '&requeue=true'; | |
| 46 | + } | |
| 47 | + | |
| 48 | + return mshotUrl; | |
| 49 | + } | |
| 50 | + | |
| 51 | + function mainwp_preview_clear_image_recovery(img) { | |
| 52 | + if (img && img.mainwpMshotRecoveryTimer) { | |
| 53 | + clearTimeout(img.mainwpMshotRecoveryTimer); | |
| 54 | + img.mainwpMshotRecoveryTimer = null; | |
| 55 | + } | |
| 56 | + } | |
| 57 | + | |
| 58 | + function mainwp_preview_queue_image_recovery(img) { | |
| 59 | + if (!img || img.dataset.mainwpMshotRecoveryRequested === '1') { | |
| 60 | + return; | |
| 61 | + } | |
| 62 | + | |
| 63 | + let primarySrc = img.getAttribute('data-mainwp-mshot-src') || img.getAttribute('data-src') || img.getAttribute('src'); | |
| 64 | + let requeueSrc = img.getAttribute('data-mainwp-mshot-requeue-src'); | |
| 65 | + | |
| 66 | + if (!primarySrc || !requeueSrc) { | |
| 67 | + return; | |
| 68 | + } | |
| 69 | + | |
| 70 | + img.dataset.mainwpMshotRecoveryRequested = '1'; | |
| 71 | + mainwp_preview_clear_image_recovery(img); | |
| 72 | + | |
| 73 | + // Ask mShots to regenerate the thumbnail once, then retry the canonical URL. | |
| 74 | + img.setAttribute('src', mainwp_preview_append_cache_bust(requeueSrc, 'requeue')); | |
| 75 | + img.mainwpMshotRecoveryTimer = setTimeout(function () { | |
| 76 | + img.setAttribute('src', mainwp_preview_append_cache_bust(primarySrc, 'reload')); | |
| 77 | + }, MSHOT_REFRESH_DELAY); | |
| 78 | + } | |
| 79 | + | |
| 80 | + if (!window.mainwpPreviewImageRecoveryBound) { | |
| 81 | + document.addEventListener('error', function (event) { | |
| 82 | + let target = event.target; | |
| 83 | + | |
| 84 | + if (target && target.tagName === 'IMG') { | |
| 85 | + mainwp_preview_queue_image_recovery(target); | |
| 86 | + } | |
| 87 | + }, true); | |
| 88 | + | |
| 89 | + window.mainwpPreviewImageRecoveryBound = true; | |
| 90 | + } | |
| 91 | + | |
| 16 | 92 | /** |
| 17 | 93 | * Init site preview function. |
| 18 | 94 | */ |
| 19 | 95 | window.mainwp_preview_init_event = function () { |
| 20 | 96 | let mshotRemovalTimer = null; |
| 21 | - let mshotSecondTryTimer = null | |
| 22 | - let mshotThirdTryTimer = null | |
| 23 | - | |
| 97 | + let mshotSecondTryTimer = null; | |
| 98 | + let mshotThirdTryTimer = null; | |
| 99 | + let previewTableSelector = '.mainwp-with-preview-table'; | |
| 24 | 100 | let mshotEnabledLinkSelector = 'td span.mainwp-preview-item'; |
| 25 | 101 | |
| 26 | 102 | // Show a preview image of the hovered URL. |
| 27 | - $('.mainwp-with-preview-table').on('click', mshotEnabledLinkSelector, function () { | |
| 103 | + $(previewTableSelector).off('.mainwpPreview').on('click.mainwpPreview', mshotEnabledLinkSelector, function () { | |
| 28 | 104 | clearTimeout(mshotRemovalTimer); |
| 29 | 105 | |
| 30 | 106 | if ($('.mainwp-preview-mshot').length > 0) { |
| 31 | 107 | if ($('.mainwp-preview-mshot:first').data('link') == this) { |
| @@ -33,8 +109,10 @@ | ||
| 33 | 109 | return; |
| 34 | 110 | } |
| 35 | 111 | else { |
| 36 | 112 | // A new link is being hovered, so remove the old preview. |
| 113 | + let existingImage = $('.mainwp-preview-mshot .mshot-image').get(0); | |
| 114 | + mainwp_preview_clear_image_recovery(existingImage); | |
| 37 | 115 | $('.mainwp-preview-mshot').remove(); |
| 38 | 116 | } |
| 39 | 117 | } |
| 40 | 118 | |
| @@ -40,11 +118,21 @@ | ||
| 40 | 118 | |
| 41 | 119 | clearTimeout(mshotSecondTryTimer); |
| 42 | 120 | clearTimeout(mshotThirdTryTimer); |
| 43 | 121 | |
| 44 | - let thisHref = $(this).attr('preview-site-url'); | |
| 122 | + let primarySrc = mainwp_preview_get_button_mshot_url(this, false); | |
| 123 | + let requeueSrc = mainwp_preview_get_button_mshot_url(this, true); | |
| 124 | + let $image = $('<img />', { | |
| 125 | + src: primarySrc, | |
| 126 | + width: 450, | |
| 127 | + height: 338, | |
| 128 | + class: 'mshot-image' | |
| 129 | + }); | |
| 130 | + let mShot = $('<div class="mainwp-preview-mshot mshot-container"><div class="mshot-arrow"></div></div>'); | |
| 45 | 131 | |
| 46 | - let mShot = $('<div class="mainwp-preview-mshot mshot-container"><div class="mshot-arrow"></div><img src="' + mainwp_preview_mshot_url(thisHref) + '" width="450" height="338" class="mshot-image" /></div>'); | |
| 132 | + $image.attr('data-mainwp-mshot-src', primarySrc); | |
| 133 | + $image.attr('data-mainwp-mshot-requeue-src', requeueSrc); | |
| 134 | + mShot.append($image); | |
| 47 | 135 | mShot.data('link', this); |
| 48 | 136 | |
| 49 | 137 | let offset = $(this).offset(); |
| 50 | 138 | |
| @@ -56,17 +144,17 @@ | ||
| 56 | 144 | // These retries appear to be superfluous if .mshot-image has already loaded, but it's because mShots |
| 57 | 145 | // can return a "Generating thumbnail..." image if it doesn't have a thumbnail ready, so we need |
| 58 | 146 | // to retry to see if we can get the newly generated thumbnail. |
| 59 | 147 | mshotSecondTryTimer = setTimeout(function () { |
| 60 | - mShot.find('.mshot-image').attr('src', mainwp_preview_mshot_url(thisHref, 2)); | |
| 61 | - }, 6000); | |
| 148 | + mShot.find('.mshot-image').attr('src', mainwp_preview_append_cache_bust(primarySrc, 'retry-2')); | |
| 149 | + }, MSHOT_REFRESH_DELAY); | |
| 62 | 150 | |
| 63 | 151 | mshotThirdTryTimer = setTimeout(function () { |
| 64 | - mShot.find('.mshot-image').attr('src', mainwp_preview_mshot_url(thisHref, 3)); | |
| 65 | - }, 12000); | |
| 152 | + mShot.find('.mshot-image').attr('src', mainwp_preview_append_cache_bust(primarySrc, 'retry-3')); | |
| 153 | + }, MSHOT_REFRESH_DELAY * 2); | |
| 66 | 154 | |
| 67 | 155 | $('body').append(mShot); |
| 68 | - }).on('mouseover', 'tr', function () { | |
| 156 | + }).on('mouseover.mainwpPreview', 'tr', function () { | |
| 69 | 157 | // When the mouse hovers over a row, begin preloading mshots for links. |
| 70 | 158 | let linksToPreloadMshotsFor = $(this).find(mshotEnabledLinkSelector); |
| 71 | 159 | |
| 72 | 160 | linksToPreloadMshotsFor.each(function () { |
| @@ -72,19 +160,22 @@ | ||
| 72 | 160 | linksToPreloadMshotsFor.each(function () { |
| 73 | 161 | // Don't attempt to preload an mshot for a single link twice. Browser caching should cover this, but in case of |
| 74 | 162 | // race conditions, save a flag locally when we've begun trying to preload one. |
| 75 | 163 | if (!$(this).data('mainwp-preview-mshot-preloaded')) { |
| 76 | - mainwp_preview_preload_mshot($(this).attr('preview-site-url')); | |
| 164 | + mainwp_preview_preload_mshot(this); | |
| 77 | 165 | $(this).data('mainwp-preview-mshot-preloaded', true); |
| 78 | 166 | } |
| 79 | 167 | }); |
| 80 | 168 | }); |
| 81 | 169 | |
| 82 | - $(document).on('mouseup', function () { | |
| 170 | + $(document).off('mouseup.mainwpPreview').on('mouseup.mainwpPreview', function () { | |
| 83 | 171 | if ($('.mainwp-preview-mshot').length > 0) { |
| 84 | 172 | mshotRemovalTimer = setTimeout(function () { |
| 85 | 173 | clearTimeout(mshotSecondTryTimer); |
| 86 | 174 | clearTimeout(mshotThirdTryTimer); |
| 175 | + let previewImage = $('.mainwp-preview-mshot .mshot-image').get(0); | |
| 176 | + | |
| 177 | + mainwp_preview_clear_image_recovery(previewImage); | |
| 87 | 178 | $('.mainwp-preview-mshot').remove(); |
| 88 | 179 | }, 100); |
| 89 | 180 | } |
| 90 | 181 | }); |
| @@ -93,30 +184,17 @@ | ||
| 93 | 184 | // init preview. |
| 94 | 185 | mainwp_preview_init_event(); |
| 95 | 186 | |
| 96 | 187 | /** |
| 97 | - * Generate an mShot URL if given a link URL. | |
| 188 | + * Begin loading an mShot preview of a link. | |
| 98 | 189 | * |
| 99 | - * @param string linkUrl | |
| 100 | - * @param int retry If retrying a request, the number of the retry. | |
| 101 | - * @return string The mShot URL; | |
| 190 | + * @param object linkElement Preview trigger element. | |
| 102 | 191 | */ |
| 103 | - function mainwp_preview_mshot_url(linkUrl, retry) { | |
| 104 | - let mshotUrl = '//s0.wordpress.com/mshots/v1/' + encodeURIComponent(linkUrl) + '?w=900'; | |
| 192 | + function mainwp_preview_preload_mshot(linkElement) { | |
| 193 | + let img = new Image(); | |
| 194 | + let primarySrc = mainwp_preview_get_button_mshot_url(linkElement, false); | |
| 105 | 195 | |
| 106 | - if (retry) { | |
| 107 | - mshotUrl += '&r=' + encodeURIComponent(retry); | |
| 196 | + if (primarySrc) { | |
| 197 | + img.src = primarySrc; | |
| 108 | 198 | } |
| 109 | - | |
| 110 | - return mshotUrl; | |
| 111 | - } | |
| 112 | - | |
| 113 | - /** | |
| 114 | - * Begin loading an mShot preview of a link. | |
| 115 | - * | |
| 116 | - * @param string linkUrl | |
| 117 | - */ | |
| 118 | - function mainwp_preview_preload_mshot(linkUrl) { | |
| 119 | - let img = new Image(); | |
| 120 | - img.src = mainwp_preview_mshot_url(linkUrl); | |
| 121 | 199 | } |
| 122 | 200 | }); |