diff --git a/preview-src/drivers-tabs.adoc b/preview-src/drivers-tabs.adoc new file mode 100644 index 00000000..6b46a32e --- /dev/null +++ b/preview-src/drivers-tabs.adoc @@ -0,0 +1,248 @@ += Tabbed sections in Drivers Manual + +Up to Neo4j 4.1 the Drivers Manual includes tabs to allow users to choose with driver language sections to display. +From 4.2 on, the Drivers Manual is split into a separate manual per language. + +== Example drivers manual content + +.Acquire the driver +[.tabbed-example] +==== + +[.include-with-dotnet] +====== + +The .NET driver is distributed via the NuGet Gallery. +To find the latest version of the driver, visit https://www.nuget.org/packages/Neo4j.Driver/. + +*Dependencies* + +* .NETStandard (^2.0) +* System.Net.NameResolution (^4.3.0) +* System.Net.Security (^4.3.2) +* System.Net.Sockets (^4.3.0) +* System.Runtime.InteropServices.RuntimeInformation (^4.3.0) +* System.Runtime.Serialization.Primitives (^4.3.0) +* System.Threading.Thread (^4.3.0) +* System.ValueTuple (^4.5.0) + +The .NET Reactive API is under package `Neo4j.Driver.Reactive`. +It is built upon https://github.com/dotnet/reactive[`System.Reactive`]. +There is no extra dependency required use .NET reactive API. + +.Installation via Install-package +======== +To install the latest version of the driver using NuGet in Visual Studio: + +[source, csharp, subs="attributes, specialcharacters"] +---- +PM> Install-Package Neo4j.Driver +---- + +It is also an option to install a certain version of the driver. + +[source, csharp, subs="attributes, specialcharacters"] +---- +PM> Install-Package Neo4j.Driver -Version $DOTNET_DRIVER_VERSION +---- + +The .Net driver uses asynchronous methods by default. +If you want to use blocking calls, the `Neo4j.Driver.Simple` NuGet package contains a set of extensions. +This can be found at https://www.nuget.org/packages/Neo4j.Driver.Simple/. +The initial examples make use of these extensions. + +In the following example we are installing driver version {dotnet-driver-version}. + +[source, csharp, subs="attributes, specialcharacters"] +---- +PM> Install-Package Neo4j.Driver -Version {dotnet-driver-version} +---- +======== + +The release notes for this driver are available https://github.com/neo4j/neo4j-dotnet-driver/releases[here]. + +====== + +[.include-with-go] +====== + +To find out the latest version of the driver, visit https://github.com/neo4j/neo4j-go-driver/releases + +======== + +To install the latest version of the driver using `go get`: + +[source, shell, subs="attributes, specialcharacters"] +---- +go get github.com/neo4j/neo4j-go-driver/v4@ +---- +Note that this requires that Go modules are enabled. + +======== + +====== + +[.include-with-java] +====== + +To use the Java driver, it is recommended employing a dependency manager, such as Maven or Gradle. +To find the latest version of the driver, visit the https://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22org.neo4j.driver%22%20AND%20a%3A%22neo4j-java-driver%22[Maven Central Repository]. + +*Dependencies* + +* org.reactivestreams:reactive-streams +* org.apache.logging.log4j:log4j (optional) + +The driver is dependent on the https://www.reactive-streams.org/[Reactive Streams API], thus maintaining JDK 8 compatibility. +To make optimal use of the reactive APIs, we suggest an additional framework like Project Reactor or RxJava2. +Both implement the Reactive Streams API and provide an exhaustive set of operators. + + +.Installation via Maven +======== + +When using Maven, add the following block to the _pom.xml_ file. +The driver version can either be declared as a property (as in the first example) or as an explicit version number (as in the second). + +[source, xml, subs="attributes, specialcharacters"] +---- + + + org.neo4j.driver + neo4j-java-driver + $JAVA_DRIVER_VERSION + + +---- + +In the following example, driver version {java-driver-version} is added. + +[source, xml, subs="attributes, specialcharacters"] +---- + + + org.neo4j.driver + neo4j-java-driver + {java-driver-version} + + +---- +======== + +.Installation via Gradle +======== + +For Gradle, a compile line will be required. Again, this can use a property or an explicit version number. + +[source, groovy, subs="attributes, specialcharacters"] +---- +compile 'org.neo4j.driver:neo4j-java-driver:$JAVA_DRIVER_VERSION' +---- + +In the following example, a driver version {java-driver-version} is added. + +[source, groovy, subs="attributes, specialcharacters"] +---- +compile 'org.neo4j.driver:neo4j-java-driver:{java-driver-version}' +---- +======== + +The release notes for this driver are available https://github.com/neo4j/neo4j-java-driver/wiki[here]. + +====== + +[.include-with-javascript] +====== + +To use the JavaScript driver, it is recommended employing `npm`. +To find the latest version of the driver, use: + +[source, shell, subs="attributes, specialcharacters"] +---- +npm show neo4j-driver@* version +---- + +*Dependencies* + +* Babel/Runtime (^7.5.5) +* RxJS (^6.5.2) +* text-encoding-utf-8 (^1.0.2) +* URI-js (^4.2.2) + + +The JavaScript Reactive API is built and exposed via RxJs. +A dependency of RxJs is automatically installed with the driver. + +.Installation via npm +======== + +To install the latest version of the driver: + +[source, shell, subs="attributes, specialcharacters"] +---- +npm install neo4j-driver +---- + +It is also an option to install a certain version of the driver. + +[source, shell, subs="attributes, specialcharacters"] +---- +npm install neo4j-driver@$JAVASCRIPT-DRIVER-VERSION +---- + +In the following example, driver version {javascript-driver-version} is installed. + +[source, shell, subs="attributes, specialcharacters"] +---- +npm install neo4j-driver@{javascript-driver-version} +---- +======== + +The release notes for this driver are available https://github.com/neo4j/neo4j-javascript-driver/wiki[here]. + +====== + +[.include-with-python] +====== + +To find the latest stable version of the Python Driver, visit https://pypi.org/project/neo4j/ + +To find a list of all available releases, visit https://pypi.org/simple/neo4j/ + +To install the latest stable version of the Python Driver: +[source, shell, subs="attributes, specialcharacters"] +---- +pip install neo4j +---- + +It is also an option to install a certain version of the driver. + +.Installation with Python +======== +The following is the syntax for installing a certain version of the Python Driver: +[source, shell, subs="attributes, specialcharacters"] +---- +pip install neo4j==$PYTHON_DRIVER_VERSION +---- + +In the following example we are installing Python Driver version {python-driver-version}. +[source, shell, subs="attributes, specialcharacters"] +---- +pip install neo4j=={python-driver-version} +---- +======== + +.Installation with Python, get Python Driver prerelease +======== +In the following example we get the latest prerelease version: +[source, shell, subs="attributes, specialcharacters"] +---- +pip install neo4 --pre +---- +======== + +The release notes for the Python Driver are available https://github.com/neo4j/neo4j-python-driver/wiki[here] + +====== + +==== diff --git a/preview-src/ui-model.yml b/preview-src/ui-model.yml index 754f6b94..0c711022 100644 --- a/preview-src/ui-model.yml +++ b/preview-src/ui-model.yml @@ -159,6 +159,9 @@ page: - content: Private Page url: private-page.html urlType: internal + - content: Drivers tabs + url: drivers-tabs.html + urlType: internal asciidoc: attributes: diff --git a/src/js/06-code.js b/src/js/06-code.js index b12dfe0f..6cb211dc 100644 --- a/src/js/06-code.js +++ b/src/js/06-code.js @@ -70,6 +70,26 @@ document.addEventListener('DOMContentLoaded', function () { document.body.removeChild(textarea) } + function capitalizeFirstLetter (string) { + return string.charAt(0).toUpperCase() + string.slice(1) + } + + var casedLang = function (lang) { + var cased + switch (lang) { + case 'csharp': + case 'dotnet': + cased = 'C#' + break + case 'javascript': + cased = 'JavaScript' + break + default: + cased = capitalizeFirstLetter(lang) + } + return cased + } + var addCodeHeader = function (pre) { var dotContent = pre.parentElement var listingBlock = dotContent.parentElement @@ -92,7 +112,7 @@ document.addEventListener('DOMContentLoaded', function () { languageDiv.className = 'code-language' if (language) { - languageDiv.innerHTML = language + languageDiv.innerHTML = casedLang(language) } var children = [languageDiv] diff --git a/src/js/06-tabs-block.js b/src/js/06-tabs-block.js new file mode 100644 index 00000000..5a089dff --- /dev/null +++ b/src/js/06-tabs-block.js @@ -0,0 +1,187 @@ +// Code functions + +document.addEventListener('DOMContentLoaded', function () { + function capitalizeFirstLetter (string) { + return string.charAt(0).toUpperCase() + string.slice(1) + } + + var casedLang = function (lang) { + var cased + switch (lang) { + case 'csharp': + case 'dotnet': + cased = 'C#' + break + case 'javascript': + cased = 'JavaScript' + break + default: + cased = capitalizeFirstLetter(lang) + } + return cased + } + + var createElement = function (el, className, children) { + var output = document.createElement(el) + output.setAttribute('class', className) + + Array.isArray(children) && children.forEach(function (child) { + if (child) output.appendChild(child) + }) + + return output + } + + var targetActive = 'tabbed-target--active' + var tabActive = 'tabbed-tab--active' + var sessionStorageAvailable = typeof window.sessionStorage !== 'undefined' && + typeof window.sessionStorage.getItem === 'function' && + typeof window.sessionStorage.setItem === 'function' + + var switchTab = function (e) { + var tab = e.target + var lang = tab.dataset.lang + var title = tab.dataset.title + // Switch Tabs + var targetTabs = document.querySelectorAll('.tabbed-target[data-title="' + title + '"]') + targetTabs.forEach(function (target) { + target.parentElement.querySelectorAll('.' + targetActive) + .forEach(function (el) { + el.classList.remove(targetActive) + }) + + target.classList.add(targetActive) + + target.parentElement.parentElement.querySelectorAll('.' + tabActive) + .forEach(function (el) { + el.classList.remove(tabActive) + }) + + target.parentElement.parentElement.querySelectorAll('.tabbed-tab[data-title="' + title + '"]') + .forEach(function (el) { + el.classList.add(tabActive) + }) + }) + + var toolbarOffset = 0 + var toolbar = document.querySelector('.toolbar') + if (toolbar.offsetHeight) { + toolbarOffset = toolbar.offsetHeight + } + var offset = document.querySelector('.navbar').offsetHeight + toolbarOffset + 20 + + var bodyRect = document.body.getBoundingClientRect().top + var elementRect = tab.getBoundingClientRect().top + var elementPosition = elementRect - bodyRect + var offsetPosition = elementPosition - offset + + window.scrollTo({ + top: offsetPosition, + behavior: 'smooth', + }) + + if (sessionStorageAvailable) { + window.sessionStorage.setItem('code_example_language', lang) + } + } + + // + // Tabbed sections in the drivers manual + // + + var defaultLang = 'dotnet' + var langList = ['dotnet', 'go', 'java', 'javascript', 'python'] + + var currentLanguage = defaultLang + if (sessionStorageAvailable) { + var searchParams = new URLSearchParams(window.location.search) + var languageFromParams = searchParams.get('language') + if (languageFromParams && langList.includes(languageFromParams.toLocaleLowerCase())) { + currentLanguage = languageFromParams.toLocaleLowerCase() + window.sessionStorage.setItem('code_example_language', currentLanguage) + } else { + var storedLanguage = window.sessionStorage.getItem('code_example_language') + if (storedLanguage && langList.includes(storedLanguage)) { + currentLanguage = storedLanguage + } + } + } + + Array.from(document.querySelectorAll('.tabbed-example')) + .forEach(function (tab) { + var tabsTitle = tab.querySelector('.title') + var originalTab = tab + var parent = tab.parentElement + + // Build an array of elements + var elements = [] + + // add sections for each language from driver manual html output format + langList.forEach(function (lang) { + tab.querySelectorAll('.include-with-' + lang).forEach(function (block) { + block.setAttribute('data-title', lang) + block.setAttribute('data-lang', lang) + elements.push(block) + }) + }) + + // Don't do anything if there's only one tab + if (elements.length <= 1) { + return + } + + var tabbedContainer = createElement('div', 'tabbed-container', []) + var tabbedParent = createElement('div', 'tabbed', [tabbedContainer]) + + if (tabsTitle) { + parent.insertBefore(tabsTitle, originalTab) + } + parent.insertBefore(tabbedParent, originalTab) + + // Build up tabs + var tabs = elements.map(function (element) { + var lang = element.getAttribute('data-lang') + var tabText = casedLang(lang) + var tabElement = createElement('li', 'tabbed-tab', [document.createTextNode(tabText)]) + + element.dataset.title = tabText + element.dataset.lang = lang + tabElement.dataset.title = tabText + tabElement.dataset.lang = lang + + if (lang === currentLanguage) tabElement.classList.add(tabActive) + tabElement.addEventListener('click', switchTab) + + return tabElement + }) + + // Remove elements from parent and add to tab container + var activeAdded = false + elements.forEach(function (element) { + tabbedContainer.appendChild(element) + element.classList.add('tabbed-target') + if (element.getAttribute('data-lang') === currentLanguage) { + element.classList.add('tabbed-target--active') + activeAdded = true + } + }) + + if (!activeAdded) { + // get the data-lang of the first tab + var setLang = elements[0].getAttribute('data-lang') + // add active to matching tabs and targets + var elIndex = 0 + elements.forEach(function (element) { + if (element.getAttribute('data-lang') === setLang) { + element.classList.add('tabbed-target--active') + tabs[elIndex].classList.add('tabbed-tab--active') + } + elIndex++ + }) + } + + tabbedParent.insertBefore(createElement('ul', 'tabbed-tabs', tabs), tabbedContainer) + + parent.removeChild(originalTab) + }) +})