From 52e5e20aa7763e000be9b8e0edcec24e135405a8 Mon Sep 17 00:00:00 2001 From: Scott Anderson Date: Thu, 15 Feb 2024 07:45:45 -0700 Subject: [PATCH] Consolidate sessions cookies and implement APIs to manage each (#5319) * WIP restructuring of cookies to pull from a limited set of cookies * WIP update cloud-urls.js to use new cookie api * move api-libs-related js into own file * minor updates to cookies.js * Apply suggestions from code review Co-authored-by: Jason Stirnaman * Update assets/js/notifications.js * set get started date default to null * remove line breaks in header js template * Add cookie migration (#5323) * migrate old cookies to new cookie structure * set explicit expiration date on influxdata_docs_ported cookie --------- Co-authored-by: Jason Stirnaman --- assets/js/api-libs.js | 37 + assets/js/cookies.js | 333 ++++++++ assets/js/custom-timestamps.js | 256 +++--- assets/js/docs-themes.js | 44 +- assets/js/feature-callouts.js | 42 +- assets/js/influxdb-url.js | 748 ++++++++++-------- assets/js/notifications.js | 78 +- assets/js/sidebar-toggle.js | 47 +- assets/js/tabbed-content.js | 85 +- assets/js/v3-wayfinding.js | 95 ++- assets/styles/layouts/_feature-callouts.scss | 63 +- data/notifications.yaml | 20 +- layouts/partials/footer/javascript.html | 18 +- .../partials/footer/modals/influxdb-url.html | 8 +- layouts/partials/header/javascript.html | 9 +- layouts/partials/sidebar/sidebar-toggle.html | 3 +- layouts/partials/topnav.html | 15 +- 17 files changed, 1209 insertions(+), 692 deletions(-) create mode 100644 assets/js/api-libs.js create mode 100644 assets/js/cookies.js diff --git a/assets/js/api-libs.js b/assets/js/api-libs.js new file mode 100644 index 000000000..7cd5a7573 --- /dev/null +++ b/assets/js/api-libs.js @@ -0,0 +1,37 @@ +//////////////////////////////////////////////////////////////////////////////// +///////////////// Preferred Client Library programming language /////////////// +//////////////////////////////////////////////////////////////////////////////// + +function getVisitedApiLib () { + const path = window.location.pathname.match( + /client-libraries\/((?:v[0-9]|flight)\/)?([a-zA-Z0-9]*)/ + ); + return path && path.length && path[2]; +} + +function isApiLib () { + return /\/client-libraries\//.test(window.location.pathname); +} + +// Set the user's programming language (client library) preference. +function setApiLibPreference (preference) { + setPreference('api_lib', preference); +} + +// Retrieve the user's programming language (client library) preference. +function getApiLibPreference () { + return getPreference('api_lib') || ''; +} + +// When visit a client library page, set the api_lib preference +if (isApiLib()) { + var selectedApiLib = getVisitedApiLib(); + setPreference('api_lib', selectedApiLib); +} + +// Activate code-tabs based on the cookie then override with query param. +var tab = getApiLibPreference(); +['.tabs, .code-tabs'].forEach( + selector => activateTabs(selector, tab), + updateBtnURLs(tab) +); diff --git a/assets/js/cookies.js b/assets/js/cookies.js new file mode 100644 index 000000000..77abf1d46 --- /dev/null +++ b/assets/js/cookies.js @@ -0,0 +1,333 @@ +/* + This represents an API for managing cookies for the InfluxData documentation. + It uses the Cookies.js library to store data as session cookies. + This is done to comply with cookie privacy laws and limit the cookies used + to manage the user experience throughout the InfluxData documentation. + + These functions manage the following InfluxDB cookies + + - influxdata_docs_preferences: Docs UI/UX-related preferences (obj) + - influxdata_docs_urls: User-defined InfluxDB URLs for each product (obj) + - influxdata_docs_notifications: + - messages: Messages (data/notifications.yaml) that have been seen (array) + - callouts: Feature callouts that have been seen (array) + - influxdata_docs_ported: Temporary cookie to help port old cookies to new structure +*/ + +// Prefix for all InfluxData docs cookies +const cookiePrefix = 'influxdata_docs_'; + +/* + Initialize a cookie with a default value. +*/ +initializeCookie = (cookieName, defaultValue) => { + fullCookieName = cookiePrefix + cookieName; + + // Check if the cookie exists before initializing the cookie + if (Cookies.get(fullCookieName) === undefined) { + Cookies.set(fullCookieName, defaultValue); + } +}; + +// Initialize all InfluxData docs cookies with defaults + +/* +//////////////////////////////////////////////////////////////////////////////// +////////////////////////// INFLUXDATA DOCS PREFERENCES ///////////////////////// +//////////////////////////////////////////////////////////////////////////////// +*/ + +const prefCookieName = cookiePrefix + 'preferences'; + +// Default preferences +var defaultPref = { + api_lib: null, + influxdb_url: 'cloud', + sidebar_state: 'open', + theme: 'light', + sample_get_started_date: null, + v3_wayfinding_show: true, +}; + +/* + Retrieve a preference from the preference cookie. + If the cookie doesn't exist, initialize it with default values. +*/ +getPreference = prefName => { + // Initialize the preference cookie if it doesn't already exist + if (Cookies.get(prefCookieName) === undefined) { + initializeCookie('preferences', defaultPref); + } + + // Retrieve and parse the cookie as JSON + prefString = Cookies.get(prefCookieName); + prefObj = JSON.parse(prefString); + + // Return the value of the specified preference + return prefObj[prefName]; +}; + +// Set a preference in the preferences cookie +setPreference = (prefID, prefValue) => { + var prefString = Cookies.get(prefCookieName); + let prefObj = JSON.parse(prefString); + + prefObj[prefID] = prefValue; + + Cookies.set(prefCookieName, prefObj); +}; + +// Return an object containing all preferences +getPreferences = () => JSON.parse(Cookies.get(prefCookieName)); + +/* +//////////////////////////////////////////////////////////////////////////////// +///////////////////////////// INFLUXDATA DOCS URLS ///////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +*/ + +const urlCookieName = cookiePrefix + 'urls'; + +// Default URLs per product +var defaultUrls = { + oss: 'http://localhost:8086', + cloud: 'https://us-west-2-1.aws.cloud2.influxdata.com', + serverless: 'https://us-east-1-1.aws.cloud2.influxdata.com', + dedicated: 'cluster-id.influxdb.io', + clustered: 'cluster-host.com', +}; + +// Defines the default urls cookie value +var defaultUrlsCookie = { + oss: defaultUrls.oss, + cloud: defaultUrls.cloud, + serverless: defaultUrls.serverless, + dedicated: defaultUrls.dedicated, + clustered: defaultUrls.clustered, + prev_oss: defaultUrls.oss, + prev_cloud: defaultUrls.cloud, + prev_serverless: defaultUrls.serverless, + prev_dedicated: defaultUrls.dedicated, + prev_clustered: defaultUrls.clustered, + custom: '', +}; + +// Return an object that contains all InfluxDB urls stored in the urls cookie +getInfluxDBUrls = () => { + // Initialize the urls cookie if it doesn't already exist + if (Cookies.get(urlCookieName) === undefined) { + initializeCookie('urls', defaultUrlsCookie); + } + + return JSON.parse(Cookies.get(urlCookieName)); +}; + +// Get the current or previous URL for a specific product or a custom url +getInfluxDBUrl = product => { + // Initialize the urls cookie if it doesn't already exist + if (Cookies.get(urlCookieName) === undefined) { + initializeCookie('urls', defaultUrlsCookie); + } + + // Retrieve and parse the cookie as JSON + urlsString = Cookies.get(urlCookieName); + urlsObj = JSON.parse(urlsString); + + // Return the URL of the specified product + return urlsObj[product]; +}; + +/* + Set multiple product URLs in the urls cookie. + Input should be an object where the key is the product and the value is the + URL to set for that product. +*/ +setInfluxDBUrls = updatedUrlsObj => { + var urlsString = Cookies.get(urlCookieName); + let urlsObj = JSON.parse(urlsString); + + newUrlsObj = { ...urlsObj, ...updatedUrlsObj }; + + Cookies.set(urlCookieName, newUrlsObj); +}; + +// Set an InfluxDB URL to an empty string in the urls cookie +removeInfluxDBUrl = product => { + var urlsString = Cookies.get(urlCookieName); + let urlsObj = JSON.parse(urlsString); + + urlsObj[product] = ''; + + Cookies.set(urlCookieName, urlsObj); +}; + +/* +//////////////////////////////////////////////////////////////////////////////// +///////////////////////// INFLUXDATA DOCS NOTIFICATIONS //////////////////////// +//////////////////////////////////////////////////////////////////////////////// +*/ + +const notificationCookieName = cookiePrefix + 'notifications'; + +// Default notifications +var defaultNotifications = { + messages: [], + callouts: [], +}; + +getNotifications = () => { + // Initialize the notifications cookie if it doesn't already exist + if (Cookies.get(notificationCookieName) === undefined) { + initializeCookie('notifications', defaultNotifications); + } + + // Retrieve and parse the cookie as JSON + notificationString = Cookies.get(notificationCookieName); + notificationObj = JSON.parse(notificationString); + + // Return the value of the specified preference + return notificationObj; +}; + +/* + Checks if a notification is read. Provide the notification ID and one of the + following notification types: + + - message + - callout + + If the notification ID exists in the array assigned to the specified type, the + notification has been read. +*/ +notificationIsRead = (notificationID, notificationType) => { + let notificationsObj = getNotifications(); + readNotifications = notificationsObj[`${notificationType}s`]; + + return readNotifications.includes(notificationID); +}; + +/* + Sets a notification as read. Provide the notification ID and one of the + following notification types: + + - message + - callout + + The notification ID is added to the array assigned to the specified type. +*/ +setNotificationAsRead = (notificationID, notificationType) => { + let notificationsObj = getNotifications(); + let readNotifications = notificationsObj[`${notificationType}s`]; + + readNotifications.push(notificationID); + notificationsObj[notificationType + 's'] = readNotifications; + + Cookies.set(notificationCookieName, notificationsObj); +}; + +/* +//////////////////////////////////////////////////////////////////////////////// +//////////////// Port all old docs cookies to the new structure //////////////// +///////////////// Remove everything below after March 15, 2024 ///////////////// +//////////////////////////////////////////////////////////////////////////////// +*/ + +portOldCookies = () => { + preferenceCookies = [ + 'influx-docs-api-lib', + 'influx-docs-sidebar-state', + 'influx-docs-theme', + 'influxdb_get_started_date', + 'influxdb_pref', + 'influx-iox-show-wayfinding', + ]; + notificationCookies = [ + 'influx-future-of-flux-notification-seen', + 'influx-influxdb-clustered-announcement-notification-seen', + 'influx-serverless-wip-notification-seen', + 'influx-influxdb-3-announcement-notification-seen', + 'influx-signing-key-rotation-notification-seen', + 'influx-iox-doc-fork-notification-seen', + 'influx-tsm-doc-fork-notification-seen', + 'influx-iox-wip-notification-seen', + 'influx-search-disabled-notification-seen', + 'influx-v2-cloud-upgrade-notification-seen', + 'influx-v2-ga-notification-seen', + 'influx-rc1-upgrade-notification-seen', + ]; + calloutCookies = ['influxdb_url_selector_seen']; + urlCookies = [ + 'influxdb_oss_url', + 'influxdb_cloud_url', + 'influxdb_dedicated_url', + 'influxdb_clustered_url', + 'influxdb_prev_oss_url', + 'influxdb_prev_cloud_url', + 'influxdb_prev_dedicated_url', + 'influxdb_prev_clustered_url', + 'influxdb_custom_url', + ]; + + preferenceCookies.forEach(cookie => { + if (cookie.includes('influx-docs-')) { + newCookieName = cookie.replace(/influx-docs-/, '').replace(/-/, '_'); + try { + setPreference( + newCookieName, + Cookies.get(cookie).replace(/-theme|sidebar-/, '') + ); + Cookies.remove(cookie); + } catch {} + } else if (cookie === 'influxdb_get_started_date') { + newCookieName = 'sample_get_started_date'; + try { + setPreference(newCookieName, Cookies.get(cookie)); + Cookies.remove(cookie); + } catch {} + } else if (cookie === 'influx-iox-show-wayfinding') { + newCookieName = 'v3_wayfinding_show'; + try { + setPreference(newCookieName, Cookies.get(cookie)); + Cookies.remove(cookie); + } catch {} + } else if (cookie === 'influxdb_pref') { + newCookieName = 'influxdb_url'; + try { + setPreference(newCookieName, Cookies.get(cookie)); + Cookies.remove(cookie); + } catch {} + } + }); + + notificationCookies.forEach(cookie => { + notificationName = cookie.replace( + /(^influx-)(.*)(-notification-seen$)/, + '$2' + ); + + if (Cookies.get(cookie) !== undefined) { + setNotificationAsRead(notificationName, 'message'); + Cookies.remove(cookie); + } + }); + + calloutCookies.forEach(cookie => Cookies.remove(cookie)); + + urlCookies.forEach(cookie => { + newUrlKey = cookie.replace(/(^influxdb_)(.*)(_url)/, '$2'); + + try { + urlObj = {}; + urlObj[newUrlKey] = Cookies.get(cookie); + setInfluxDBUrls(urlObj); + Cookies.remove(cookie); + } catch {} + }); +}; + +if (Cookies.get('influxdata_docs_ported') === undefined) { + portOldCookies(); + Cookies.set('influxdata_docs_ported', true, { + expires: new Date('2024-03-15T00:00:00Z'), + }); +} diff --git a/assets/js/custom-timestamps.js b/assets/js/custom-timestamps.js index 7d643aeb2..2442931f8 100644 --- a/assets/js/custom-timestamps.js +++ b/assets/js/custom-timestamps.js @@ -1,142 +1,180 @@ // Placeholder start date used in InfluxDB custom timestamps -const defaultStartDate = "2022-01-01" +const defaultStartDate = '2022-01-01'; // Return yyyy-mm-dd formatted string from a Date object -function formatDate(dateObj) { - return dateObj.toISOString().replace(/T.*$/, '') +function formatDate (dateObj) { + return dateObj.toISOString().replace(/T.*$/, ''); } // Return yesterday's date -function yesterday() { - const yesterday = new Date() - yesterday.setDate(yesterday.getDate() - 1) +function yesterday () { + const yesterday = new Date(); + yesterday.setDate(yesterday.getDate() - 1); - return formatDate(yesterday) + return formatDate(yesterday); } // Split a date string into year, month, and day -function datePart(date) { - datePartRegex = /(\d{4})-(\d{2})-(\d{2})/ - year = date.replace(datePartRegex, "$1") - month = date.replace(datePartRegex, "$2") - day = date.replace(datePartRegex, "$3") +function datePart (date) { + datePartRegex = /(\d{4})-(\d{2})-(\d{2})/; + year = date.replace(datePartRegex, '$1'); + month = date.replace(datePartRegex, '$2'); + day = date.replace(datePartRegex, '$3'); - return {year: year, month: month, day: day} + return { year: year, month: month, day: day }; } -////////////////////////// SESSION / COOKIE MANAGEMENT ////////////////////////// +///////////////////////// PREFERENCE COOKIE MANAGEMENT ///////////////////////// -cookieID = 'influxdb_get_started_date' +prefID = 'sample_get_started_date'; -function setStartDate(setDate) { - Cookies.set(cookieID, setDate) +function setStartDate (setDate) { + setPreference(prefID, setDate); } -function getStartDate() { - return Cookies.get(cookieID) -} - -function removeStartDate() { - Cookies.remove(cookieID) +function getStartDate () { + return getPreference(prefID); } //////////////////////////////////////////////////////////////////////////////// // If the user has not set the startDate cookie, default the startDate to yesterday -var startDate = (getStartDate() != undefined) ? getStartDate() : yesterday() +var startDate = getStartDate() || yesterday(); // Convert a time value to a Unix timestamp (seconds) -function timeToUnixSeconds(time) { - unixSeconds = new Date(time).getTime() / 1000 - - return unixSeconds +function timeToUnixSeconds (time) { + unixSeconds = new Date(time).getTime() / 1000; + + return unixSeconds; } // Default time values in getting started sample data let times = [ - {"rfc3339": `${defaultStartDate}T08:00:00Z`, "unix": timeToUnixSeconds(`${defaultStartDate}T08:00:00Z`)}, // 1641024000 - {"rfc3339": `${defaultStartDate}T09:00:00Z`, "unix": timeToUnixSeconds(`${defaultStartDate}T09:00:00Z`)}, // 1641027600 - {"rfc3339": `${defaultStartDate}T10:00:00Z`, "unix": timeToUnixSeconds(`${defaultStartDate}T10:00:00Z`)}, // 1641031200 - {"rfc3339": `${defaultStartDate}T11:00:00Z`, "unix": timeToUnixSeconds(`${defaultStartDate}T11:00:00Z`)}, // 1641034800 - {"rfc3339": `${defaultStartDate}T12:00:00Z`, "unix": timeToUnixSeconds(`${defaultStartDate}T12:00:00Z`)}, // 1641038400 - {"rfc3339": `${defaultStartDate}T13:00:00Z`, "unix": timeToUnixSeconds(`${defaultStartDate}T13:00:00Z`)}, // 1641042000 - {"rfc3339": `${defaultStartDate}T14:00:00Z`, "unix": timeToUnixSeconds(`${defaultStartDate}T14:00:00Z`)}, // 1641045600 - {"rfc3339": `${defaultStartDate}T15:00:00Z`, "unix": timeToUnixSeconds(`${defaultStartDate}T15:00:00Z`)}, // 1641049200 - {"rfc3339": `${defaultStartDate}T16:00:00Z`, "unix": timeToUnixSeconds(`${defaultStartDate}T16:00:00Z`)}, // 1641052800 - {"rfc3339": `${defaultStartDate}T17:00:00Z`, "unix": timeToUnixSeconds(`${defaultStartDate}T17:00:00Z`)}, // 1641056400 - {"rfc3339": `${defaultStartDate}T18:00:00Z`, "unix": timeToUnixSeconds(`${defaultStartDate}T18:00:00Z`)}, // 1641060000 - {"rfc3339": `${defaultStartDate}T19:00:00Z`, "unix": timeToUnixSeconds(`${defaultStartDate}T19:00:00Z`)}, // 1641063600 - {"rfc3339": `${defaultStartDate}T20:00:00Z`, "unix": timeToUnixSeconds(`${defaultStartDate}T20:00:00Z`)} // 1641067200 -] + { + rfc3339: `${defaultStartDate}T08:00:00Z`, + unix: timeToUnixSeconds(`${defaultStartDate}T08:00:00Z`), + }, // 1641024000 + { + rfc3339: `${defaultStartDate}T09:00:00Z`, + unix: timeToUnixSeconds(`${defaultStartDate}T09:00:00Z`), + }, // 1641027600 + { + rfc3339: `${defaultStartDate}T10:00:00Z`, + unix: timeToUnixSeconds(`${defaultStartDate}T10:00:00Z`), + }, // 1641031200 + { + rfc3339: `${defaultStartDate}T11:00:00Z`, + unix: timeToUnixSeconds(`${defaultStartDate}T11:00:00Z`), + }, // 1641034800 + { + rfc3339: `${defaultStartDate}T12:00:00Z`, + unix: timeToUnixSeconds(`${defaultStartDate}T12:00:00Z`), + }, // 1641038400 + { + rfc3339: `${defaultStartDate}T13:00:00Z`, + unix: timeToUnixSeconds(`${defaultStartDate}T13:00:00Z`), + }, // 1641042000 + { + rfc3339: `${defaultStartDate}T14:00:00Z`, + unix: timeToUnixSeconds(`${defaultStartDate}T14:00:00Z`), + }, // 1641045600 + { + rfc3339: `${defaultStartDate}T15:00:00Z`, + unix: timeToUnixSeconds(`${defaultStartDate}T15:00:00Z`), + }, // 1641049200 + { + rfc3339: `${defaultStartDate}T16:00:00Z`, + unix: timeToUnixSeconds(`${defaultStartDate}T16:00:00Z`), + }, // 1641052800 + { + rfc3339: `${defaultStartDate}T17:00:00Z`, + unix: timeToUnixSeconds(`${defaultStartDate}T17:00:00Z`), + }, // 1641056400 + { + rfc3339: `${defaultStartDate}T18:00:00Z`, + unix: timeToUnixSeconds(`${defaultStartDate}T18:00:00Z`), + }, // 1641060000 + { + rfc3339: `${defaultStartDate}T19:00:00Z`, + unix: timeToUnixSeconds(`${defaultStartDate}T19:00:00Z`), + }, // 1641063600 + { + rfc3339: `${defaultStartDate}T20:00:00Z`, + unix: timeToUnixSeconds(`${defaultStartDate}T20:00:00Z`), + }, // 1641067200 +]; -function updateTimestamps(newStartDate) { - // Update the times array with replacement times - times = times.map(x => { - var newStartTimestamp = x.rfc3339.replace(/^.*T/, newStartDate + "T") +function updateTimestamps (newStartDate) { + // Update the times array with replacement times + times = times.map(x => { + var newStartTimestamp = x.rfc3339.replace(/^.*T/, newStartDate + 'T'); - return { - "rfc3339": x.rfc3339, - "unix": x.unix, - "rfc3339_new": newStartTimestamp, - "unix_new": timeToUnixSeconds(newStartTimestamp) - } - }) + return { + rfc3339: x.rfc3339, + unix: x.unix, + rfc3339_new: newStartTimestamp, + unix_new: timeToUnixSeconds(newStartTimestamp), + }; + }); - var updateBlockElWhitelist = [ - '.custom-timestamps pre', - '.custom-timestamps li', - '.custom-timestamps p', - '.custom-timestamps table' - ] + var updateBlockElWhitelist = [ + '.custom-timestamps pre', + '.custom-timestamps li', + '.custom-timestamps p', + '.custom-timestamps table', + ]; - $(updateBlockElWhitelist.join()).each(function() { - var wrapper = $(this)[0] + $(updateBlockElWhitelist.join()).each(function () { + var wrapper = $(this)[0]; - times.forEach(function(x) { - oldDatePart = datePart(x.rfc3339.replace(/T.*$/, "")) - newDatePart = datePart(x.rfc3339_new.replace(/T.*$/, "")) - rfc3339Regex = new RegExp(`${oldDatePart.year}(.*)${oldDatePart.month}(.*)${oldDatePart.day}`, 'g') - rfc3339Repl = `${newDatePart.year}$1${newDatePart.month}$2${newDatePart.day}` + times.forEach(function (x) { + oldDatePart = datePart(x.rfc3339.replace(/T.*$/, '')); + newDatePart = datePart(x.rfc3339_new.replace(/T.*$/, '')); + rfc3339Regex = new RegExp( + `${oldDatePart.year}(.*)${oldDatePart.month}(.*)${oldDatePart.day}`, + 'g' + ); + rfc3339Repl = `${newDatePart.year}$1${newDatePart.month}$2${newDatePart.day}`; - wrapper.innerHTML = - wrapper.innerHTML - .replaceAll(x.unix, x.unix_new) - .replaceAll(rfc3339Regex, rfc3339Repl) - }) - }) + wrapper.innerHTML = wrapper.innerHTML + .replaceAll(x.unix, x.unix_new) + .replaceAll(rfc3339Regex, rfc3339Repl); + }); + }); - $('span.custom-timestamps').each(function() { - var wrapper = $(this)[0] + $('span.custom-timestamps').each(function () { + var wrapper = $(this)[0]; - times.forEach(function(x) { - oldDatePart = datePart(x.rfc3339.replace(/T.*$/, "")) - newDatePart = datePart(x.rfc3339_new.replace(/T.*$/, "")) - rfc3339Regex = new RegExp(`${oldDatePart.year}-${oldDatePart.month}-${oldDatePart.day}`, 'g') - rfc3339Repl = `${newDatePart.year}-${newDatePart.month}-${newDatePart.day}` + times.forEach(function (x) { + oldDatePart = datePart(x.rfc3339.replace(/T.*$/, '')); + newDatePart = datePart(x.rfc3339_new.replace(/T.*$/, '')); + rfc3339Regex = new RegExp( + `${oldDatePart.year}-${oldDatePart.month}-${oldDatePart.day}`, + 'g' + ); + rfc3339Repl = `${newDatePart.year}-${newDatePart.month}-${newDatePart.day}`; - wrapper.innerHTML = - wrapper.innerHTML - .replaceAll(x.unix, x.unix_new) - .replaceAll(rfc3339Regex, rfc3339Repl) - }) - }) + wrapper.innerHTML = wrapper.innerHTML + .replaceAll(x.unix, x.unix_new) + .replaceAll(rfc3339Regex, rfc3339Repl); + }); + }); - // Create a new seed times array with new start time for next change - times = times.map(x => { - var newStartTimestamp = x.rfc3339.replace(/^.*T/, newStartDate + "T") + // Create a new seed times array with new start time for next change + times = times.map(x => { + var newStartTimestamp = x.rfc3339.replace(/^.*T/, newStartDate + 'T'); - return { - "rfc3339": newStartTimestamp, - "unix": timeToUnixSeconds(newStartTimestamp) - } - }) - + return { + rfc3339: newStartTimestamp, + unix: timeToUnixSeconds(newStartTimestamp), + }; + }); } /////////////////////// MODAL INTERACTIONS / DATE PICKER /////////////////////// // Date picker form element -var datePickerEl = $('#custom-date-selector') +var datePickerEl = $('#custom-date-selector'); // Initialize the date picker with the current startDate const elem = datePickerEl[0]; @@ -145,7 +183,7 @@ const datepicker = new Datepicker(elem, { format: 'yyyy-mm-dd', nextArrow: '>', prevArrow: '<', -}); +}); //////////////////////////////////// ACTIONS /////////////////////////////////// @@ -153,22 +191,20 @@ const datepicker = new Datepicker(elem, { // Conditionally set the start date cookie it startDate is equal to the default value updateTimestamps(startDate); if (startDate === yesterday()) { - setStartDate(startDate); + setStartDate(startDate); } // Sumbit new date -$('#submit-custom-date').click(function() { - let newDate = datepicker.getDate() +$('#submit-custom-date').click(function () { + let newDate = datepicker.getDate(); - if (newDate != undefined) { - newDate = formatDate(newDate) + if (newDate != undefined) { + newDate = formatDate(newDate); - updateTimestamps(newDate); - setStartDate(newDate) - toggleModal('#influxdb-gs-date-select') - - } else { - toggleModal('#influxdb-gs-date-select') - } - -}) \ No newline at end of file + updateTimestamps(newDate); + setStartDate(newDate); + toggleModal('#influxdb-gs-date-select'); + } else { + toggleModal('#influxdb-gs-date-select'); + } +}); diff --git a/assets/js/docs-themes.js b/assets/js/docs-themes.js index 31b224717..ce9fa90f4 100644 --- a/assets/js/docs-themes.js +++ b/assets/js/docs-themes.js @@ -4,35 +4,39 @@ */ // *** TO BE CUSTOMISED *** -var style_cookie_name = "influx-docs-theme" ; -var style_cookie_duration = 30 ; -var style_domain = "docs.influxdata.com" ; +var style_preference_name = 'theme'; +var style_cookie_duration = 30; +var style_domain = 'docs.influxdata.com'; // *** END OF CUSTOMISABLE SECTION *** // You do not need to customise anything below this line -function switch_style ( css_title ) -{ -// You may use this script on your site free of charge provided -// you do not remove this notice or the URL below. Script from -// http://www.thesitewizard.com/javascripts/change-style-sheets.shtml - var i, link_tag ; - for (i = 0, link_tag = document.getElementsByTagName("link") ; - i < link_tag.length ; i++ ) { - if ((link_tag[i].rel.indexOf("stylesheet") != -1) && link_tag[i].title.includes("theme")) { - link_tag[i].disabled = true ; - if (link_tag[i].title == css_title ) { - link_tag[i].disabled = false ; +function switchStyle (css_title) { + // You may use this script on your site free of charge provided + // you do not remove this notice or the URL below. Script from + // http://www.thesitewizard.com/javascripts/change-style-sheets.shtml + var i, link_tag; + for ( + i = 0, link_tag = document.getElementsByTagName('link'); + i < link_tag.length; + i++ + ) { + if ( + link_tag[i].rel.indexOf('stylesheet') != -1 && + link_tag[i].title.includes('theme') + ) { + link_tag[i].disabled = true; + if (link_tag[i].title == css_title) { + link_tag[i].disabled = false; } } - Cookies.set(style_cookie_name, css_title); + setPreference(style_preference_name, css_title.replace(/-theme/, '')); } } -function set_style_from_cookie() -{ - var css_title = Cookies.get(style_cookie_name); +function setStyleFromCookie () { + var css_title = `${getPreference(style_preference_name)}-theme`; if (css_title !== undefined) { - switch_style(css_title); + switchStyle(css_title); } } diff --git a/assets/js/feature-callouts.js b/assets/js/feature-callouts.js index b9b24355c..918d783c2 100644 --- a/assets/js/feature-callouts.js +++ b/assets/js/feature-callouts.js @@ -1,12 +1,36 @@ -// Show the url feature callout on page load -if ( Cookies.get('influxdb_url_selector_seen') != 'true' ) { - $('#callout-url-selector').fadeIn(300).removeClass('start-position') +/* + This feature is designed to callout new features added to the documentation + CSS is required for the callout bubble to determine look and position, but the + element must have the `callout` class and a unique id. + Callouts are treated as notifications and use the notification cookie API in + assets/js/cookies.js. +*/ + +// Get notification ID +function getCalloutID (el) { + return $(el).attr('id'); } -// Set feature cookie when the button is clicked -$('button.url-trigger, #callout-url-selector .close').click(function() { - if ( Cookies.get('influxdb_url_selector_seen') != 'true') { - Cookies.set('influxdb_url_selector_seen', 'true') - $('#callout-url-selector').fadeOut(200) +// Hide a callout and update the cookie with the viewed callout +function hideCallout (calloutID) { + if (!notificationIsRead(calloutID)) { + setNotificationAsRead(calloutID, 'callout'); + $(`#${calloutID}`).fadeOut(200); } -}) \ No newline at end of file +} + +// Show the url feature callouts on page load +$('.feature-callout').each(function () { + calloutID = calloutID($(this)); + + if (!notificationIsRead(calloutID, 'callout')) { + $(`#${calloutID}.feature-callout`) + .fadeIn(300) + .removeClass('start-position'); + } +}); + +// Hide the InfluxDB URL selector callout +// $('button.url-trigger, #influxdb-url-selector .close').click(function () { +// hideCallout('influxdb-url-selector'); +// }); diff --git a/assets/js/influxdb-url.js b/assets/js/influxdb-url.js index 166143f46..cf656169e 100644 --- a/assets/js/influxdb-url.js +++ b/assets/js/influxdb-url.js @@ -1,31 +1,33 @@ var placeholderUrls = { - cloud: "https://cloud2.influxdata.com", - oss: "http://localhost:8086", - dedicated: "cluster-id.influxdb.io", - clustered: "cluster-host.com" -} + oss: 'http://localhost:8086', + cloud: 'https://cloud2.influxdata.com', + serverless: 'https://cloud2.influxdata.com', + dedicated: 'cluster-id.influxdb.io', + clustered: 'cluster-host.com', +}; -var defaultUrls = { - cloud: "https://us-west-2-1.aws.cloud2.influxdata.com", - oss: "http://localhost:8086", - dedicated: "cluster-id.influxdb.io", - clustered: "cluster-host.com" -} +/* + NOTE: The defaultUrls variable is defined in assets/js/cookies.js +*/ -var elementSelector = ".article--content pre:not(.preserve)" +var elementSelector = '.article--content pre:not(.preserve)'; -// Return the page context (cloud, oss/enterprise, dedicated, clustered, other) -function context() { - if (/\/influxdb\/cloud(?:-serverless)/.test(window.location.pathname)) { - return "cloud" +// Return the page context (cloud, serverless, oss/enterprise, dedicated, clustered, other) +function context () { + if (/\/influxdb\/cloud\//.test(window.location.pathname)) { + return 'cloud'; + } else if (/\/influxdb\/cloud-serverless/.test(window.location.pathname)) { + return 'serverless'; } else if (/\/influxdb\/cloud-dedicated/.test(window.location.pathname)) { - return "dedicated" + return 'dedicated'; } else if (/\/influxdb\/clustered/.test(window.location.pathname)) { - return "clustered" - } else if (/\/(enterprise_|influxdb).*\/v[1-2]\//.test(window.location.pathname)) { - return "oss/enterprise" + return 'clustered'; + } else if ( + /\/(enterprise_|influxdb).*\/v[1-2]\//.test(window.location.pathname) + ) { + return 'oss/enterprise'; } else { - return "other" + return 'other'; } } @@ -35,63 +37,65 @@ function context() { // Retrieve the user's InfluxDB preference (cloud or oss) from the influxdb_pref session cookie // Default is cloud. -function getPreference() { - return Cookies.get('influxdb_pref') || "cloud" +function getURLPreference () { + return getPreference('influxdb_url'); } // Set the user's selected InfluxDB preference (cloud or oss) -function setPreference(preference) { - Cookies.set('influxdb_pref', preference) +function setURLPreference (preference) { + setPreference('influxdb_url', preference); } -// Set the user's programming language (client library) preference. -function setApiLibPreference(preference) { - Cookies.set('influx-docs-api-lib', preference) +/* + influxdata_docs_urls cookie object keys: + + - oss + - cloud + - dedicated + - clustered + - prev_oss + - prev_cloud + - prev_dedicated + - prev_clustered + - custom +*/ + +// Store URLs in the urls session cookies +function storeUrl (context, newUrl, prevUrl) { + urlsObj = {}; + urlsObj['prev_' + context] = prevUrl; + urlsObj[context] = newUrl; + + setInfluxDBUrls(urlsObj); } -// InfluxDB URL-Related Session keys -// -// influxdb_oss_url -// influxdb_cloud_url -// influxdb_dedicated_url -// influxdb_clustered_url -// influxdb_prev_oss_url -// influxdb_prev_cloud_url -// influxdb_prev_dedicated_url -// influxdb_prev_clustered_url -// influxdb_pref (cloud | oss) -// influxdb_custom_url - -// Store the InfluxDB URL session cookies – influxdb_url and influxdb_prev_url -function storeUrl(context, newUrl, prevUrl) { - Cookies.set('influxdb_prev_' + context + '_url', prevUrl) - Cookies.set('influxdb_' + context + '_url', newUrl) -} - -// Store custom URL session cookie – influxdb_custom_url +// Store custom URL in the url session cookie. // Used to populate the custom URL field -function storeCustomUrl(customUrl) { - Cookies.set('influxdb_custom_url', customUrl) - $('input#custom[type=radio]').val(customUrl) +function storeCustomUrl (customUrl) { + setInfluxDBUrls({ custom: customUrl }); + $('input#custom[type=radio]').val(customUrl); } -// Remove custom URL session cookie – influxdb_custom_url +// Set a URL in the urls session cookie to an empty string // Used to clear the form when custom url input is left empty -function removeCustomUrl() { - Cookies.remove('influxdb_custom_url') +function removeCustomUrl () { + removeInfluxDBUrl('custom'); } -// Store product URL session cookie – influxdb_dedicated_url, influxdb_clustered_url, etc. +// Store a product URL in the urls session cookie // Used to populate the custom URL field -function storeProductUrl(product, productUrl) { - Cookies.set(`influxdb_${product}_url`, productUrl) - $(`input#${product}-url-field`).val(productUrl) +function storeProductUrl (product, productUrl) { + urlsObj = {}; + urlsObj[product] = productUrl; + + setInfluxDBUrls(urlsObj); + $(`input#${product}-url-field`).val(productUrl); } -// Remove product URL session cookie – influxdb_dedicated_url, influxdb_clustered_url, etc. +// Set a product URL in the urls session cookie to an empty string // Used to clear the form when dedicated url input is left empty -function removeProductUrl(product) { - Cookies.remove(`influxdb_${product}_url`) +function removeProductUrl (product) { + removeInfluxDBUrl(product); } //////////////////////////////////////////////////////////////////////////////// @@ -100,195 +104,211 @@ function removeProductUrl(product) { // Preserve URLs in codeblocks that come just after or are inside a div // with the class, .keep-url -function addPreserve() { +function addPreserve () { $('.keep-url').each(function () { // For code blocks with no syntax highlighting - $(this).next('pre').addClass('preserve') + $(this).next('pre').addClass('preserve'); // For code blocks with no syntax highlighting inside of a link (API endpoint blocks) - $(this).next('a').find('pre').addClass('preserve') + $(this).next('a').find('pre').addClass('preserve'); // For code blocks with syntax highlighting - $(this).next('.highlight').find('pre').addClass('preserve') + $(this).next('.highlight').find('pre').addClass('preserve'); // For code blocks inside .keep-url div // Special use case for codeblocks generated from yaml data / frontmatter - $(this).find('pre').addClass('preserve') - }) + $(this).find('pre').addClass('preserve'); + }); } -// Retrieve the previously selected cloud and oss URLs from the -// influxdb_cloud_url and influxdb_oss_url session cookies. -function getUrls() { - var currentCloudUrl = Cookies.get('influxdb_cloud_url') || defaultUrls.cloud - var currentOSSUrl = Cookies.get('influxdb_oss_url') || defaultUrls.oss - var currentDedicatedUrl = Cookies.get('influxdb_dedicated_url') || defaultUrls.dedicated - var currentClusteredUrl = Cookies.get('influxdb_clustered_url') || defaultUrls.clustered +// Retrieve the currently selected URLs from the urls session cookie. +function getUrls () { + var storedUrls = getInfluxDBUrls(); + var currentCloudUrl = storedUrls.cloud; + var currentOSSUrl = storedUrls.oss; + var currentServerlessUrl = storedUrls.serverless; + var currentDedicatedUrl = storedUrls.dedicated; + var currentClusteredUrl = storedUrls.clustered; var urls = { - cloud: currentCloudUrl, oss: currentOSSUrl, + cloud: currentCloudUrl, + serverless: currentServerlessUrl, dedicated: currentDedicatedUrl, - clustered: currentClusteredUrl + clustered: currentClusteredUrl, }; return urls; } -// Retrieve the previously selected cloud and oss URLs from the -// prev_influxdb_cloud_url and prev_influxdb_oss_url session cookies. +// Retrieve the previously selected URLs from the from the urls session cookie. // This is used to update URLs whenever you switch between browser tabs. -function getPrevUrls() { - var prevCloudUrl = Cookies.get('influxdb_prev_cloud_url') || defaultUrls.cloud - var prevOSSUrl = Cookies.get('influxdb_prev_oss_url') || defaultUrls.oss - var prevDedicatedUrl = Cookies.get('influxdb_prev_dedicated_url') || defaultUrls.dedicated - var prevClusteredUrl = Cookies.get('influxdb_prev_clustered_url') || defaultUrls.clustered +function getPrevUrls () { + var storedUrls = getInfluxDBUrls(); + var prevCloudUrl = storedUrls.prev_cloud; + var prevOSSUrl = storedUrls.prev_oss; + var prevServerlessUrl = storedUrls.prev_serverless; + var prevDedicatedUrl = storedUrls.prev_dedicated; + var prevClusteredUrl = storedUrls.prev_clustered; var prevUrls = { - cloud: prevCloudUrl, oss: prevOSSUrl, + cloud: prevCloudUrl, + serverless: prevServerlessUrl, dedicated: prevDedicatedUrl, - clustered: prevClusteredUrl + clustered: prevClusteredUrl, }; return prevUrls; } -//////////////////////////////////////////////////////////////////////////////// -///////////////// Preferred Client Library programming language /////////////// -//////////////////////////////////////////////////////////////////////////////// - -function getVisitedApiLib() { - const path = window.location.pathname.match(/client-libraries\/([a-zA-Z0-9]*)/) - return path && path.length && path[1] -} - -var selectedApiLib = getVisitedApiLib() -Cookies.set('influx-docs-api-lib', selectedApiLib) - //selectedApiLib && setApiLibPreference(selectedApiLib); - // Iterate through code blocks and update InfluxDB urls -// Requires objects with cloud and oss keys and url values -function updateUrls(prevUrls, newUrls) { - var preference = getPreference() +function updateUrls (prevUrls, newUrls) { + var preference = getURLPreference(); var prevUrlsParsed = { - cloud: {}, oss: {}, + cloud: {}, + serverless: {}, dedicated: {}, - clustered: {} - } + clustered: {}, + }; var newUrlsParsed = { - cloud: {}, oss: {}, + cloud: {}, + serverless: {}, dedicated: {}, - clustered: {} - } + clustered: {}, + }; - Object.keys(prevUrls).forEach(function(k) { + Object.keys(prevUrls).forEach(function (k) { try { - prevUrlsParsed[k] = new URL(prevUrls[k]) + prevUrlsParsed[k] = new URL(prevUrls[k]); } catch { - prevUrlsParsed[k] = { origin: prevUrls[k], host: prevUrls[k] } - } - }) - - Object.keys(newUrls).forEach(function(k) { - try { - newUrlsParsed[k] = new URL(newUrls[k]) - } catch { - newUrlsParsed[k] = { origin: newUrls[k], host: newUrls[k] } - } - }) - - /** - * Match and replace host with host - * then replace URL with URL. - **/ - var cloudReplacements = [ - { replace: prevUrlsParsed.cloud, with: newUrlsParsed.cloud }, - { replace: prevUrlsParsed.oss, with: newUrlsParsed.cloud }, - ] - var ossReplacements = [ - { replace: prevUrlsParsed.cloud, with: newUrlsParsed.cloud }, - { replace: prevUrlsParsed.oss, with: newUrlsParsed.oss }, - ] - var dedicatedReplacements = [ - { replace: prevUrlsParsed.dedicated, with: newUrlsParsed.dedicated }, - ] - var clusteredReplacements = [ - { replace: prevUrlsParsed.clustered, with: newUrlsParsed.clustered }, - ] - - if (context() === "cloud") { var replacements = cloudReplacements } - else if (context() === "dedicated") { var replacements = dedicatedReplacements } - else if (context() === "clustered") { var replacements = clusteredReplacements } - else if (context() === "oss/enterprise") { var replacements = ossReplacements } - else if ( preference === "cloud" ) { var replacements = cloudReplacements } - else { var replacements = ossReplacements } - - replacements.forEach(function (o) { - if (o.replace.origin != o.with.origin) { - var fuzzyOrigin = new RegExp(o.replace.origin + "(:(^443)|[0-9]+)?", "g"); - $(elementSelector).each(function() { - $(this).html( - $(this).html().replace(fuzzyOrigin, function(m){ - return o.with.origin || m; - }) - ); - }) + prevUrlsParsed[k] = { origin: prevUrls[k], host: prevUrls[k] }; } }); - function replaceWholename(startStr, endStr, replacement) { + Object.keys(newUrls).forEach(function (k) { + try { + newUrlsParsed[k] = new URL(newUrls[k]); + } catch { + newUrlsParsed[k] = { origin: newUrls[k], host: newUrls[k] }; + } + }); + + /** + * Match and replace host with host + * then replace URL with URL. + **/ + var ossReplacements = [ + { replace: prevUrlsParsed.cloud, with: newUrlsParsed.cloud }, + { replace: prevUrlsParsed.oss, with: newUrlsParsed.oss }, + ]; + var cloudReplacements = [ + { replace: prevUrlsParsed.cloud, with: newUrlsParsed.cloud }, + { replace: prevUrlsParsed.oss, with: newUrlsParsed.cloud }, + ]; + var serverlessReplacements = [ + { replace: prevUrlsParsed.serverless, with: newUrlsParsed.serverless }, + { replace: prevUrlsParsed.oss, with: newUrlsParsed.serverless }, + ]; + var dedicatedReplacements = [ + { replace: prevUrlsParsed.dedicated, with: newUrlsParsed.dedicated }, + ]; + var clusteredReplacements = [ + { replace: prevUrlsParsed.clustered, with: newUrlsParsed.clustered }, + ]; + + if (context() === 'cloud') { + var replacements = cloudReplacements; + } else if (context() === 'serverless') { + var replacements = serverlessReplacements; + } else if (context() === 'dedicated') { + var replacements = dedicatedReplacements; + } else if (context() === 'clustered') { + var replacements = clusteredReplacements; + } else if (context() === 'oss/enterprise') { + var replacements = ossReplacements; + } else if (preference === 'cloud') { + var replacements = cloudReplacements; + } else { + var replacements = ossReplacements; + } + + replacements.forEach(function (o) { + if (o.replace.origin != o.with.origin) { + var fuzzyOrigin = new RegExp(o.replace.origin + '(:(^443)|[0-9]+)?', 'g'); + $(elementSelector).each(function () { + $(this).html( + $(this) + .html() + .replace(fuzzyOrigin, function (m) { + return o.with.origin || m; + }) + ); + }); + } + }); + + function replaceWholename (startStr, endStr, replacement) { var startsWithSeparator = new RegExp('[/.]'); var endsWithSeparator = new RegExp('[-.:]'); - if(!startsWithSeparator.test(startStr) && !endsWithSeparator.test(endStr)) { - var newHost = startStr + replacement + endStr + if ( + !startsWithSeparator.test(startStr) && + !endsWithSeparator.test(endStr) + ) { + var newHost = startStr + replacement + endStr; return newHost; } } replacements - .map(function(o) { - return {replace: o.replace.host, with: o.with.host} - }) - .forEach(function (o) { - if (o.replace != o.with) { - var fuzzyHost = new RegExp("(.?)" + o.replace + "(.?)", "g"); - $(elementSelector).each(function() { - $(this).html( - $(this).html().replace(fuzzyHost, function(m, p1, p2) { - var r = replaceWholename(p1, p2, o.with) || m; - return r - }) - ); - }) - } - }); + .map(function (o) { + return { replace: o.replace.host, with: o.with.host }; + }) + .forEach(function (o) { + if (o.replace != o.with) { + var fuzzyHost = new RegExp('(.?)' + o.replace + '(.?)', 'g'); + $(elementSelector).each(function () { + $(this).html( + $(this) + .html() + .replace(fuzzyHost, function (m, p1, p2) { + var r = replaceWholename(p1, p2, o.with) || m; + return r; + }) + ); + }); + } + }); } -// Append the URL selector button to each codeblock with an InfluxDB Cloud or OSS URL -function appendUrlSelector() { - +// Append the URL selector button to each codeblock containing a placeholder URL +function appendUrlSelector () { var appendToUrls = [ - placeholderUrls.cloud, placeholderUrls.oss, + placeholderUrls.cloud, + placeholderUrls.serverless, placeholderUrls.dedicated, - placeholderUrls.clustered - ] + placeholderUrls.clustered, + ]; - if (context() === "cloud") { - var selectorText = "InfluxDB Cloud Region" - } else if (context() === "dedicated") { - var selectorText = "Set dedicated cluster URL" - } else if (context() === "clustered") { - var selectorText = "Set InfluxDB cluster URL" - } else if (context() === "oss/enterprise") { - var selectorText = "Change InfluxDB URL" + if (context() === 'cloud' || 'serverless') { + var selectorText = 'InfluxDB Cloud Region'; + } else if (context() === 'dedicated') { + var selectorText = 'Set Dedicated cluster URL'; + } else if (context() === 'clustered') { + var selectorText = 'Set InfluxDB cluster URL'; + } else if (context() === 'oss/enterprise') { + var selectorText = 'Change InfluxDB URL'; } else { - var selectorText = "InfluxDB Cloud or OSS?" + var selectorText = 'InfluxDB Cloud or OSS?'; } - appendToUrls.forEach(function(url){ - $(elementSelector).each(function() { - var code = $(this).html() + appendToUrls.forEach(function (url) { + $(elementSelector).each(function () { + var code = $(this).html(); if (code.includes(url)) { - $(this).after("") - $('.select-url').fadeIn(400) + $(this).after( + "' + ); + $('.select-url').fadeIn(400); } }); }); @@ -299,16 +319,16 @@ function appendUrlSelector() { //////////////////////////////////////////////////////////////////////////////// // Add the preserve tag to code blocks that shouldn't be updated -addPreserve() +addPreserve(); // Append URL selector buttons to code blocks -appendUrlSelector() +appendUrlSelector(); // Update URLs on load -updateUrls(placeholderUrls, getUrls()) +updateUrls(placeholderUrls, getUrls()); // Set active radio button on page load -setRadioButtons(getUrls()) +setRadioButtons(getUrls()); //////////////////////////////////////////////////////////////////////////////// ////////////////////////// Modal window interactions /////////////////////////// @@ -317,189 +337,219 @@ setRadioButtons(getUrls()) // General modal window interactions are controlled in modals.js // Open the InfluxDB URL selector modal -$(".url-trigger").click(function(e) { - e.preventDefault() - toggleModal('#influxdb-url-list') -}) +$('.url-trigger').click(function (e) { + e.preventDefault(); + toggleModal('#influxdb-url-list'); +}); // Set the selected URL radio buttons to :checked -function setRadioButtons() { - currentUrls = getUrls() - $('input[name="influxdb-cloud-url"][value="' + currentUrls.cloud + '"]').prop("checked", true) - $('input[name="influxdb-oss-url"][value="' + currentUrls.oss + '"]').prop("checked", true) +function setRadioButtons () { + currentUrls = getUrls(); + $('input[name="influxdb-cloud-url"][value="' + currentUrls.cloud + '"]').prop( + 'checked', + true + ); + $( + 'input[name="influxdb-serverless-url"][value="' + + currentUrls.serverless + + '"]' + ).prop('checked', true); + $('input[name="influxdb-oss-url"][value="' + currentUrls.oss + '"]').prop( + 'checked', + true + ); } - // Add checked to fake-radio if cluster is selected on page load -if ($("ul.clusters label input").is(":checked")) { - var group = $("ul.clusters label input:checked").parent().parent().parent().siblings(); - $(".fake-radio", group).addClass("checked"); -}; +if ($('ul.clusters label input').is(':checked')) { + var group = $('ul.clusters label input:checked') + .parent() + .parent() + .parent() + .siblings(); + $('.fake-radio', group).addClass('checked'); +} // Select first cluster when region is clicked -$("p.region").click(function () { - if (!$(".fake-radio", this).hasClass("checked")) { - $(".fake-radio", this).addClass("checked"); - $("+ ul.clusters li:first label", this).trigger("click"); - }; +$('p.region').click(function () { + if (!$('.fake-radio', this).hasClass('checked')) { + $('.fake-radio', this).addClass('checked'); + $('+ ul.clusters li:first label', this).trigger('click'); + } }); // Remove checked class from fake-radio when another region is selected -$(".region-group").click(function () { - if (!$(".fake-radio", this).hasClass("checked")) { - $(".fake-radio", !this).removeClass("checked"); - $(".fake-radio", this).addClass("checked"); +$('.region-group').click(function () { + if (!$('.fake-radio', this).hasClass('checked')) { + $('.fake-radio', !this).removeClass('checked'); + $('.fake-radio', this).addClass('checked'); } -}) +}); // Update URLs and URL preference when selected/clicked in the modal -$('input[name="influxdb-cloud-url"]').change(function() { - var newUrl = $(this).val() - storeUrl("cloud", newUrl, getUrls().cloud) - updateUrls(getPrevUrls(), getUrls()) -}) -$('input[name="influxdb-cloud-url"]').click(function() {setPreference("cloud")}) +$('input[name="influxdb-oss-url"]').change(function () { + var newUrl = $(this).val(); + storeUrl('oss', newUrl, getUrls().oss); + updateUrls(getPrevUrls(), getUrls()); + setURLPreference('oss'); +}); +$('input[name="influxdb-oss-url"]').click(function () { + setURLPreference('oss'); +}); -$('input[name="influxdb-oss-url"]').change(function() { - var newUrl = $(this).val() - storeUrl("oss", newUrl, getUrls().oss) - updateUrls(getPrevUrls(), getUrls()) - setPreference("oss") -}) -$('input[name="influxdb-oss-url"]').click(function() {setPreference("oss")}) +$('input[name="influxdb-cloud-url"]').change(function () { + var newUrl = $(this).val(); + storeUrl('cloud', newUrl, getUrls().cloud); + updateUrls(getPrevUrls(), getUrls()); +}); +$('input[name="influxdb-cloud-url"]').click(function () { + setURLPreference('cloud'); +}); -$('input[name="influxdb-dedicated-url"]').change(function() { - var newUrl = $(this).val() - storeUrl("dedicated", newUrl, getUrls().dedicated) - updateUrls(getPrevUrls(), getUrls()) -}) +$('input[name="influxdb-serverless-url"]').change(function () { + var newUrl = $(this).val(); + storeUrl('serverless', newUrl, getUrls().serverless); + updateUrls(getPrevUrls(), getUrls()); +}); -$('input[name="influxdb-clustered-url"]').change(function() { - var newUrl = $(this).val() - storeUrl("clustered", newUrl, getUrls().clustered) - updateUrls(getPrevUrls(), getUrls()) -}) +$('input[name="influxdb-dedicated-url"]').change(function () { + var newUrl = $(this).val(); + storeUrl('dedicated', newUrl, getUrls().dedicated); + updateUrls(getPrevUrls(), getUrls()); +}); + +$('input[name="influxdb-clustered-url"]').change(function () { + var newUrl = $(this).val(); + storeUrl('clustered', newUrl, getUrls().clustered); + updateUrls(getPrevUrls(), getUrls()); +}); // Toggle preference tabs -function togglePrefBtns(el) { - preference = el.length ? el.attr("id").replace("pref-", "") : "cloud" - prefUrls = $("#" + preference + "-urls") +function togglePrefBtns (el) { + preference = el.length ? el.attr('id').replace('pref-', '') : 'cloud'; + prefUrls = $('#' + preference + '-urls'); - el.addClass("active") - el.siblings().removeClass("active") - prefUrls.addClass("active").removeClass("inactive") - prefUrls.siblings().addClass("inactive").removeClass("active") - setPreference(preference) + el.addClass('active'); + el.siblings().removeClass('active'); + prefUrls.addClass('active').removeClass('inactive'); + prefUrls.siblings().addClass('inactive').removeClass('active'); + setURLPreference(preference); } // Select preference tab on click -$('#pref-tabs .pref-tab').click(function() { - togglePrefBtns($(this)) -}) +$('#pref-tabs .pref-tab').click(function () { + togglePrefBtns($(this)); +}); // Select preference tab from cookie -function showPreference() { - var preference = Cookies.get("influxdb_pref") - prefTab = $("#pref-" + preference) - togglePrefBtns(prefTab) +function showPreference () { + var preference = getPreference('influxdb_url'); + prefTab = $('#pref-' + preference); + togglePrefBtns(prefTab); } // Toggled preferred service on load -showPreference() +showPreference(); //////////////////////////////////////////////////////////////////////////////// ///////////////////////////////// Custom URLs ////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// // Validate custom URLs -function validateUrl(url) { +function validateUrl (url) { /** validDomain = (Named host | IPv6 host | IPvFuture host)(:Port)? **/ - var validDomain = new RegExp(`([a-z0-9\-._~%]+` - + `|\[[a-f0-9:.]+\]` - + `|\[v[a-f0-9][a-z0-9\-._~%!$&'()*+,;=:]+\])` - + `(:[0-9]+)?`); + var validDomain = new RegExp( + `([a-z0-9\-._~%]+` + + `|\[[a-f0-9:.]+\]` + + `|\[v[a-f0-9][a-z0-9\-._~%!$&'()*+,;=:]+\])` + + `(:[0-9]+)?` + ); - if (!['dedicated','clustered'].includes(context())) { + if (!['dedicated', 'clustered'].includes(context())) { // Validation for non-dedicated, non-clustered custom InfluxDB URLs try { new URL(url); - return {valid: true, error: ""} - } catch(e) { - var validProtocol = /^http(s?)/ - var protocol = url.match(/http(s?):\/\//) ? url.match(/http(s?):\/\//)[0] : ""; - var domain = url.replace(protocol, "") + return { valid: true, error: '' }; + } catch (e) { + var validProtocol = /^http(s?)/; + var protocol = url.match(/http(s?):\/\//) + ? url.match(/http(s?):\/\//)[0] + : ''; + var domain = url.replace(protocol, ''); if (validProtocol.test(protocol) == false) { - return {valid: false, error: "Invalid protocol, use http[s]"} + return { valid: false, error: 'Invalid protocol, use http[s]' }; } else if (validDomain.test(domain) == false) { - return {valid: false, error: "Invalid domain"} + return { valid: false, error: 'Invalid domain' }; } else if (e) { - return {valid: false, error: "Invalid URL"} + return { valid: false, error: 'Invalid URL' }; } } } else { // Validation for product-specific URLs - var includesProtocol = /^.*:\/\// - var protocol = url.match(/^.*:\/\//) ? url.match(/^.*:\/\//)[0] : ""; - var domain = url.replace(protocol, "") + var includesProtocol = /^.*:\/\//; + var protocol = url.match(/^.*:\/\//) ? url.match(/^.*:\/\//)[0] : ''; + var domain = url.replace(protocol, ''); if (url.length === 0) { - return {valid: true, error: ""} + return { valid: true, error: '' }; } else if (includesProtocol.test(protocol) == true) { - return {valid: false, error: "Do not include the protocol"} + return { valid: false, error: 'Do not include the protocol' }; } else if (validDomain.test(domain) == false) { - return {valid: false, error: "Invalid domain"} + return { valid: false, error: 'Invalid domain' }; } else { - return {valid: true, error: ""} + return { valid: true, error: '' }; } - } + } } // Show validation errors -function showValidationMessage(validation) { - $('#custom-url').addClass("error") - $('#custom-url').attr("data-message", validation.error) +function showValidationMessage (validation) { + $('#custom-url').addClass('error'); + $('#custom-url').attr('data-message', validation.error); } // Hide validation messages and replace the message attr with empty string -function hideValidationMessage() { - $('#custom-url').removeClass("error").attr("data-message", "") +function hideValidationMessage () { + $('#custom-url').removeClass('error').attr('data-message', ''); } // Set the custom URL cookie and apply the change // If the custom URL field is empty, it defaults to the OSS default -function applyCustomUrl() { - var custUrl = $('#custom-url-field').val() - let urlValidation = validateUrl(custUrl) - if (custUrl.length > 0 ) { +function applyCustomUrl () { + var custUrl = $('#custom-url-field').val(); + let urlValidation = validateUrl(custUrl); + if (custUrl.length > 0) { if (urlValidation.valid) { - hideValidationMessage() - storeCustomUrl(custUrl) - storeUrl("oss", custUrl, getUrls().oss) - updateUrls(getPrevUrls(), getUrls()) + hideValidationMessage(); + storeCustomUrl(custUrl); + storeUrl('oss', custUrl, getUrls().oss); + updateUrls(getPrevUrls(), getUrls()); } else { - showValidationMessage(urlValidation) + showValidationMessage(urlValidation); } } else { removeCustomUrl(); - hideValidationMessage() - $('input[name="influxdb-oss-url"][value="' + defaultUrls.oss + '"]').trigger('click') + hideValidationMessage(); + $( + 'input[name="influxdb-oss-url"][value="' + defaultUrls.oss + '"]' + ).trigger('click'); } } // Set the product URL cookie and apply the change // If the product URL field is empty, it defaults to the product default -function applyProductUrl(product) { - var productUrl = $(`#${product}-url-field`).val() - let urlValidation = validateUrl(productUrl) - if (productUrl.length > 0 ) { +function applyProductUrl (product) { + var productUrl = $(`#${product}-url-field`).val(); + let urlValidation = validateUrl(productUrl); + if (productUrl.length > 0) { if (urlValidation.valid) { - hideValidationMessage() - storeProductUrl(product, productUrl) - getUrls(product, productUrl, getUrls()[product]) - updateUrls(getPrevUrls(), getUrls()) + hideValidationMessage(); + storeProductUrl(product, productUrl); + getUrls(product, productUrl, getUrls()[product]); + updateUrls(getPrevUrls(), getUrls()); } else { - showValidationMessage(urlValidation) + showValidationMessage(urlValidation); } } else { removeProductUrl(product); @@ -508,12 +558,12 @@ function applyProductUrl(product) { } // Trigger radio button on custom URL field focus -$('input#custom-url-field').focus(function(e) { - $('input#custom[type="radio"]').trigger('click') -}) +$('input#custom-url-field').focus(function (e) { + $('input#custom[type="radio"]').trigger('click'); +}); // Update URLs and close modal when using 'enter' to exit custom URL field -$("#custom-url").submit(function(e) { +$('#custom-url').submit(function (e) { e.preventDefault(); const productContext = context(); @@ -541,67 +591,69 @@ $("#custom-url").submit(function(e) { var urlValueElements = [ '#custom-url-field', '#dedicated-url-field', - '#clustered-url-field' -].join() + '#clustered-url-field', +].join(); // Store the custom InfluxDB URL or product-specific URL when exiting the field -$(urlValueElements).blur(function() { - (!['dedicated', 'clustered'].includes(context())) ? applyCustomUrl() : applyProductUrl(context()); -}) +$(urlValueElements).blur(function () { + !['dedicated', 'clustered'].includes(context()) + ? applyCustomUrl() + : applyProductUrl(context()); +}); /** Delay execution of a function `fn` for a number of milliseconds `ms` - * e.g., delay a validation handler to avoid annoying the user. - */ -function delay(fn, ms) { - let timer = 0 - return function(...args) { - clearTimeout(timer) - timer = setTimeout(fn.bind(this, ...args), ms || 0) - } + * e.g., delay a validation handler to avoid annoying the user. + */ +function delay (fn, ms) { + let timer = 0; + return function (...args) { + clearTimeout(timer); + timer = setTimeout(fn.bind(this, ...args), ms || 0); + }; } -function handleUrlValidation() { - let url = $(urlValueElements).val() - let urlValidation = validateUrl(url) +function handleUrlValidation () { + let url = $(urlValueElements).val(); + let urlValidation = validateUrl(url); if (urlValidation.valid) { - hideValidationMessage() + hideValidationMessage(); } else { - showValidationMessage(urlValidation) + showValidationMessage(urlValidation); } } // When in erred state, revalidate custom URL on keyup $(document).on('keyup', urlValueElements, delay(handleUrlValidation, 500)); // Populate the custom InfluxDB URL field on page load -if ( Cookies.get('influxdb_custom_url') != undefined ) { - $('input#custom').val(Cookies.get('influxdb_custom_url')) - $('#custom-url-field').val(Cookies.get('influxdb_custom_url')) +var customUrlOnLoad = getInfluxDBUrl('custom'); +if (customUrlOnLoad != '') { + $('input#custom').val(customUrlOnLoad); + $('#custom-url-field').val(customUrlOnLoad); } // Populate the product-specific URL fields on page load -var productsWithUniqueURLs = ['dedicated', 'clustered'] +var productsWithUniqueURLs = ['dedicated', 'clustered']; -productsWithUniqueURLs.forEach(function(productEl) { - if ( Cookies.get(`influxdb_${productEl}_url`) != undefined ) { - $(`input#${productEl}-url-field`).val(Cookies.get(`influxdb_${productEl}_url`)) - $(`#${productEl}-url-field`).val(Cookies.get(`influxdb_${productEl}_url`)) - } -}) +productsWithUniqueURLs.forEach(function (productEl) { + productUrlCookie = getInfluxDBUrl(productEl); + $(`input#${productEl}-url-field`).val(productUrlCookie); + $(`#${productEl}-url-field`).val(productUrlCookie); +}); //////////////////////////////////////////////////////////////////////////////// /////////////////////////// Dynamically update URLs //////////////////////////// //////////////////////////////////////////////////////////////////////////////// // Extract the protocol and hostname of referrer -referrerMatch = document.referrer.match(/^(?:[^\/]*\/){2}[^\/]+/g) -referrerHost = referrerMatch ? referrerMatch[0] : ""; +referrerMatch = document.referrer.match(/^(?:[^\/]*\/){2}[^\/]+/g); +referrerHost = referrerMatch ? referrerMatch[0] : ''; // Check if the referrerHost is one of the cloud URLs // cloudUrls is built dynamically in layouts/partials/footer/javascript.html if (cloudUrls.includes(referrerHost)) { - storeUrl("cloud", referrerHost, getUrls().cloud) - updateUrls(getPrevUrls(), getUrls()) - setRadioButtons() - setPreference("cloud") - showPreference() + storeUrl('cloud', referrerHost, getUrls().cloud); + updateUrls(getPrevUrls(), getUrls()); + setRadioButtons(); + setURLPreference('cloud'); + showPreference(); } diff --git a/assets/js/notifications.js b/assets/js/notifications.js index 114d99bfc..ac5e1c86b 100644 --- a/assets/js/notifications.js +++ b/assets/js/notifications.js @@ -1,57 +1,71 @@ -// Get notification cookie name -function notificationCookieName(el) { - return "influx-" + $(el).attr('id') + "-notification-seen" +/* + Notification messages appear in the top right of the docs site. + When a user closes a notification, it adds the notification ID to the + messages array in the influxdata_docs_notifications cookie. + IDs in the messages array are considered read and no longer appear to the user. +*/ + +// Get notification ID +function notificationID (el) { + return $(el).attr('id'); } -// Show notifications that are within scope and haven't been ssen -function showNotifications() { - $('#docs-notifications > .notification').each(function() { - +// Show notifications that are within scope and haven't been read +function showNotifications () { + $('#docs-notifications > .notification').each(function () { // Check if the path includes paths defined in the data-scope attribute // of the notification html element - function inScope(path, scope) { - for(let i = 0; i < scope.length; i++){ + function inScope (path, scope) { + for (let i = 0; i < scope.length; i++) { if (path.includes(scope[i])) { return true; - }; + } } return false; } - var scope = $(this).data('scope').split(',') - var pageInScope = inScope(window.location.pathname, scope) - var notificationCookie = Cookies.get( notificationCookieName(this) ) + var scope = $(this).data('scope').split(','); + var pageInScope = inScope(window.location.pathname, scope); + var notificationRead = notificationIsRead(notificationID(this), 'message'); - if (pageInScope && notificationCookie != 'true') { - $(this).show().animate({right: 0, opacity: 1}, 200, 'swing') + if (pageInScope && !notificationRead) { + $(this).show().animate({ right: 0, opacity: 1 }, 200, 'swing'); } }); } -// Hide a notification and set cookie as true -function hideNotification(el) { - $(el).closest('.notification').animate({height: 0, opacity: 0}, 200, 'swing', function(){ - $(this).hide(); - Cookies.set(notificationCookieName(this), true); - }); +// Hide a notification and set the notification as read +function hideNotification (el) { + $(el) + .closest('.notification') + .animate({ height: 0, opacity: 0 }, 200, 'swing', function () { + $(this).hide(); + setNotificationAsRead(notificationID(this), 'message'); + }); } // Show notifications on page load -showNotifications() +showNotifications(); -// Hide a notification and set see cookie to true -$('.close-notification').click(function(e) { +// Hide a notification and set the notification as read +$('.close-notification').click(function (e) { e.preventDefault(); hideNotification(this); -}) +}); -$('.notification .show').click(function() { +$('.notification .show').click(function () { $(this).closest('.notification').toggleClass('min'); -}) +}); // Notification element scroll position -const notificationsInitialPosition = parseInt($('#docs-notifications').css('top'), 10) -$(window).scroll(function(){ - var notificationPosition = (notificationsInitialPosition - scrollY > 10) ? notificationsInitialPosition - scrollY : 10; - $('#docs-notifications').css('top', notificationPosition) -}) \ No newline at end of file +const notificationsInitialPosition = parseInt( + $('#docs-notifications').css('top'), + 10 +); +$(window).scroll(function () { + var notificationPosition = + notificationsInitialPosition - scrollY > 10 + ? notificationsInitialPosition - scrollY + : 10; + $('#docs-notifications').css('top', notificationPosition); +}); diff --git a/assets/js/sidebar-toggle.js b/assets/js/sidebar-toggle.js index fd494e0cc..2c20b3ddf 100644 --- a/assets/js/sidebar-toggle.js +++ b/assets/js/sidebar-toggle.js @@ -4,35 +4,42 @@ */ // *** TO BE CUSTOMISED *** -var sidebar_state_cookie_name = "influx-docs-sidebar-state" ; -var sidebar_state_duration = 30 ; -var style_domain = "docs.influxdata.com" ; +var sidebar_state_preference_name = 'sidebar_state'; +var sidebar_state_duration = 30; +var style_domain = 'docs.influxdata.com'; // *** END OF CUSTOMISABLE SECTION *** // You do not need to customise anything below this line -function toggle_sidebar ( toggle_state ) -{ -// You may use this script on your site free of charge provided -// you do not remove this notice or the URL below. Script from -// http://www.thesitewizard.com/javascripts/change-style-sheets.shtml - var i, link_tag ; - for (i = 0, link_tag = document.getElementsByTagName("link") ; - i < link_tag.length ; i++ ) { - if ((link_tag[i].rel.indexOf("stylesheet") != -1) && link_tag[i].title.includes("sidebar")) { - link_tag[i].disabled = true ; - if (link_tag[i].title == toggle_state ) { - link_tag[i].disabled = false ; +function toggleSidebar (toggle_state) { + // You may use this script on your site free of charge provided + // you do not remove this notice or the URL below. Script from + // http://www.thesitewizard.com/javascripts/change-style-sheets.shtml + var i, link_tag; + for ( + i = 0, link_tag = document.getElementsByTagName('link'); + i < link_tag.length; + i++ + ) { + if ( + link_tag[i].rel.indexOf('stylesheet') != -1 && + link_tag[i].title.includes('sidebar') + ) { + link_tag[i].disabled = true; + if (link_tag[i].title == toggle_state) { + link_tag[i].disabled = false; } } - Cookies.set(sidebar_state_cookie_name, toggle_state); + setPreference( + sidebar_state_preference_name, + toggle_state.replace(/sidebar-/, '') + ); } } -function set_sidebar_state() -{ - var toggle_state = Cookies.get(sidebar_state_cookie_name); +function setSidebarState () { + var toggle_state = `sidebar-${getPreference(sidebar_state_preference_name)}`; if (toggle_state !== undefined) { - toggle_sidebar(toggle_state); + toggleSidebar(toggle_state); } } diff --git a/assets/js/tabbed-content.js b/assets/js/tabbed-content.js index 7442103de..33a6416a8 100644 --- a/assets/js/tabbed-content.js +++ b/assets/js/tabbed-content.js @@ -1,12 +1,11 @@ //////////////////////////////// Tabbed Content //////////////////////////////// -/** - * NOTE: Tab elements are whitelisted elements that do not trigger - * smoothscroll when clicked. The whitelist is defined in content-interactions.js. -**/ - -function tabbedContent(container, tab, content) { +/** + * NOTE: Tab elements are whitelisted elements that do not trigger + * smoothscroll when clicked. The whitelist is defined in content-interactions.js. + **/ +function tabbedContent (container, tab, content) { // Add the active class to the first tab in each tab group, // in case it wasn't already set in the markup. $(container).each(function () { @@ -14,7 +13,7 @@ function tabbedContent(container, tab, content) { $(tab + ':first', this).addClass('is-active'); }); - $(tab).on('click', function(e) { + $(tab).on('click', function (e) { e.preventDefault(); // Make sure the tab being clicked is marked as active, and make the rest inactive. @@ -22,7 +21,7 @@ function tabbedContent(container, tab, content) { // Render the correct tab content based on the position of the tab being clicked. const activeIndex = $(tab).index(this); - $(content).each(function(i) { + $(content).each(function (i) { if (i === activeIndex) { $(this).show(); $(this).siblings(content).hide(); @@ -34,69 +33,67 @@ function tabbedContent(container, tab, content) { tabbedContent('.code-tabs-wrapper', '.code-tabs p a', '.code-tab-content'); tabbedContent('.tabs-wrapper', '.tabs p a', '.tab-content'); -// Retrieve the user's programming language (client library) preference. -function getApiLibPreference() { - return Cookies.get('influx-docs-api-lib') || ''; -} - -function getTabQueryParam() { +function getTabQueryParam () { const queryParams = new URLSearchParams(window.location.search); return $('