Tag Archives: javascript
JavaScript || How To Use Geolocation To Get Current Position With Promises Using Vanilla JavaScript
The following is a module with functions which demonstrates how to use geolocation to get the device current position with promises using vanilla JavaScript.
The following function is a wrapper for the navigator.geolocation.getCurrentPosition, updated to use promises to run as an asynchronous operation.
1. Get Current Position
The example below demonstrates the use of ‘Utils.getCurrentPosition‘ to get the current position of the device.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
// Get Current Position <script> (async () => { try { // Get device position let position = await Utils.getCurrentPosition(); console.log(position); alert(`Latitude: ${position.coords.latitude}, Longitude: ${position.coords.longitude}`); } catch (error) { console.log(error); alert(`Error Code: ${error.code}, Error Message: ${error.message}`); } })(); </script> // example output: /* { "coords": { "accuracy": 13.094 "altitude": null "altitudeAccuracy": null "heading": null "latitude": 36.4458083 "longitude": -114.6677835 "speed": null } "timestamp": 1639609018611 } */ |
3. Utils Namespace
The following is the Utils.js Namespace. Include this in your project to start using!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
// ============================================================================ // Author: Kenneth Perkins // Date: Dec 15, 2021 // Taken From: http://programmingnotes.org/ // File: Utils.js // Description: Javascript that handles general utility functions // ============================================================================ /** * NAMESPACE: Utils * USE: Handles general utility functions. */ var Utils = Utils || {}; (function(namespace) { 'use strict'; // Property to hold public variables and functions let exposed = namespace; /** * FUNCTION: getCurrentPosition * USE: Gets the current position of the device * @param options: The PositionOptions * @return: A promise that will contain the GeolocationPosition of the device on completion */ exposed.getCurrentPosition = (options = null) => { return new Promise((resolve, reject) => { if (navigator && navigator.geolocation) { navigator.geolocation.getCurrentPosition(resolve, reject, options); } else { reject(new Error('Geolocation is not supported by this environment')); } }); } (function (factory) { if (typeof define === 'function' && define.amd) { define([], factory); } else if (typeof exports === 'object') { module.exports = factory(); } }(function() { return namespace; })); }(Utils)); // http://programmingnotes.org/ |
QUICK NOTES:
The highlighted lines are sections of interest to look out for.
The code is heavily commented, so no further insight is necessary. If you have any questions, feel free to leave a comment below.
Angular || How To Create A Simple Personal Contact List Using Angular
The following is an implementation which demonstrates how to create a simple personal contact list using Angular.
This project allows you to add a new contact, update an existing contact, and delete a contact. All contacts are retrieved and updated using web request calls on a mock API.
1. Get Started
To get started, make sure you have a package manager like Node.js installed. Node.js is used to install packages.
You’ll also want to have Angular cli installed. Visit the official documentation for more information on how this is done.
Next, navigate to the project directory in the terminal, then run the following commands (Node.js):
Project Setup
npm install
Compiles and hot-reloads for development
npm run start
2. Features
This project implements a simple personal contact list which demonstrates how to:
- Work with data, methods, conditional statements, and events
- Create, update, view, and delete contacts from the system
- Make API calls for each of the above actions
- Use tables, forms, and form validation
3. Screenshots
Initial Contact List Fetched From API
Contact List With New Contact Added
4. Download
QUICK NOTES:
The highlighted lines are sections of interest to look out for.
The code is heavily commented, so no further insight is necessary. If you have any questions, feel free to leave a comment below.
JavaScript || How To Add & Populate A Dropdown List With An Array Using Vanilla JavaScript
The following is a module with functions which demonstrates how to add and populate a dropdown select list with an array of items using vanilla JavaScript.
The function demonstrated on this page allows to add items from an array into a dropdown list, as well as adding option groups and custom data attributes.
1. Basic Usage
The example below demonstrates the use of ‘Utils.bindDropdown‘ to bind the data in a simple array to a dropdown list.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
<!-- Basic Usage --> <!-- Declare dropdown --> <select id="dropdown"></select> <script> (() => { // Declare dropdown items let items = ['Kenneth', 'Jennifer', 'Lynn', 'Sole']; // Get dropdown let dropdown = document.querySelector('#dropdown'); // Add dropdown items Utils.bindDropdown(dropdown, items); })(); </script> |
Sample:
2. Additional Options
The example below demonstrates the use of ‘Utils.bindDropdown‘ to bind the data in an options initialization array to a dropdown list.
In this example, the text and values are specified, as well as custom option groups, the selected option value, and custom data attributes.
You can add any properties you wish to the object, and it will be added to the dropdown list option!
Note: Option groups are not required using this notation, as indicated by the ‘Ungrouped Items’.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
<!-- Additional Options --> <!-- Declare dropdown --> <select id="dropdown"></select> <script> (() => { // Declare dropdown items let items = [ {text: 'Kenneth', value: 31, group: 'Parents'}, {text: 'Jennifer', value: 28, group: 'Parents', selected: true}, {text: 'Lynn', value: 87, group: 'Children'}, {text: 'Sole', value: 91, group: 'Children', 'data-test': 'test attribute'}, {text: 'Ungrouped Item #1', value: 1019}, {text: 'Ungrouped Item #2', value: 8791, disabled: false}, ]; // Get dropdown let dropdown = document.querySelector('#dropdown'); // Add dropdown items Utils.bindDropdown(dropdown, items); })(); </script> |
Sample:
3. Utils Namespace
The following is the Utils.js Namespace. Include this in your project to start using!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 |
// ============================================================================ // Author: Kenneth Perkins // Date: Jan 30, 2021 // Taken From: http://programmingnotes.org/ // File: Utils.js // Description: Javascript that handles general utility functions // ============================================================================ /** * NAMESPACE: Utils * USE: Handles general utility functions. */ var Utils = Utils || {}; (function(namespace) { 'use strict'; // Property to hold public variables and functions let exposed = namespace; /** * FUNCTION: bindDropdown * USE: Binds data to a dropdown list * @param dropdown: Javascript element to add dropdown options * @param items: An array of items to bind to the dropdown list * @return: N/A */ exposed.bindDropdown = (dropdown, items) => { // Clear existing entries while (dropdown.hasChildNodes()) { dropdown.removeChild(dropdown.firstChild); } // Set up option groups for the dropdown const groupKey = 'group'; let groups = {}; for (let item of items) { if (typeof item !== 'object' || !(groupKey in item) || (item[groupKey] in groups)) { continue; } let groupName = item[groupKey]; let optGroup = document.createElement('optgroup'); optGroup.label = groupName; groups[groupName] = { element: optGroup, added: false }; } // Add new entries for (let item of items) { if (typeof item !== 'object') { let text = String(item); item = {}; item.text = text; item.value = text; } let isEmptyOption = true; let isGroupOption = false; let option = document.createElement('option'); for (let prop in item) { if (prop === groupKey) { isGroupOption = true; continue; } let value = item[prop]; if (prop in option) { option[prop] = value; } else { option.setAttribute(prop, value); } isEmptyOption = false; } // Add option to the dropdown if (isGroupOption) { let groupInfo = groups[item[groupKey]]; let optGroup = groupInfo.element; if (!groupInfo.added) { dropdown.appendChild(optGroup); groupInfo.added = true; } if (!isEmptyOption) { optGroup.appendChild(option); } } else { dropdown.appendChild(option); } } } (function (factory) { if (typeof define === 'function' && define.amd) { define([], factory); } else if (typeof exports === 'object') { module.exports = factory(); } }(function() { return namespace; })); }(Utils)); // http://programmingnotes.org/ |
4. More Examples
Below are more examples demonstrating the use of ‘Utils.js‘. Don’t forget to include the module when running the examples!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
<!-- // ============================================================================ // Author: Kenneth Perkins // Date: Jan 30, 2021 // Taken From: http://programmingnotes.org/ // File: Utils.html // Description: Demonstrates the use of Utils.js // ============================================================================ --> <!DOCTYPE html> <html> <head> <meta charset="utf-8"/> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>My Programming Notes Utils.js Demo</title> <style> .main { text-align:center; margin-left:auto; margin-right:auto; } </style> <!-- // Include module --> <script type="text/javascript" src="./Utils.js"></script> </head> <body> <main class="main"> <div>My Programming Notes Utils.js Demo</div> <!-- Declare dropdown --> <select id="dropdown"></select> </main> <script> document.addEventListener('DOMContentLoaded', function(eventLoaded) { // Get dropdown let dropdown = document.querySelector('#dropdown'); dropdown.addEventListener('change', (e) => { let text = dropdown.options[dropdown.selectedIndex].text; let value = dropdown.value; alert(`Text: ${text} - Value: ${value}`); }); // Declare dropdown items let items = [ {text: 'Kenneth', value: 31, group: 'Parents'}, {text: 'Jennifer', value: 28, group: 'Parents', selected: true}, {text: 'Lynn', value: 87, group: 'Children'}, {text: 'Sole', value: 91, group: 'Children', 'data-test': 'test attribute'}, {text: 'Ungrouped Item #1', value: 1019}, {text: 'Ungrouped Item #2', value: 8791, disabled: false}, ]; //items = ['Kenneth', 'Jennifer', 'Lynn', 'Sole']; //items = [31, 28, 87, 91, 1019, 8791]; // Add dropdown items Utils.bindDropdown(dropdown, items); }); </script> </body> </html><!-- // http://programmingnotes.org/ --> |
QUICK NOTES:
The highlighted lines are sections of interest to look out for.
The code is heavily commented, so no further insight is necessary. If you have any questions, feel free to leave a comment below.
Vue || How To Build & Deploy A Vue Site/App For Production Under A Web Hosting Environment
The following page demonstrates how to build and deploy a Vue site/app for production under a shared hosting environment.
Note: This page assumes you already have a domain and hosting plan setup. It also assumes your project is completed and ready to be deployed. For an overview on how to get started with Vue, visit the official documentation.
Contents
1. Build The Project
2. Deploy Site
3. Deploy Site - Subfolder
4. Server Configuration - HTML5 History Mode
1. Build The Project
The first step is to build the project for production. This can be achieved by a simple command.
First, navigate to the project directory in the terminal, then type one of the following commands depending on your package manager.
NPM:
npm run build
Yarn:
yarn build
Once this process is complete, in your project directory you will see a new folder named ‘dist‘. This dist folder will contain the files that are needed to upload to the server.
The ‘dist‘ folder should contain something like the following:
• css - [folder]
• img - [folder]
• js - [folder]
• favicon.ico - [file]
• index.html - [file]
2. Deploy Site
The files generated in Step 1 contained in the ‘dist‘ folder can be uploaded to your server using any method familiar to you.
On your server, the public_html directory is typically where you would place the files, which is the document root folder for your primary domain name.
Once the files are uploaded, your site should be live!
3. Deploy Site – Subfolder
If you wish to deploy your site into a subfolder (i.e: site.com/your-subfolder/), this can be done by making only a few changes!
Before you build your project (as highlighted in Step 1), it needs to be updated to point to the subfolder as the ‘base’ path. This is configured in the vue.config.js file.
If this file doesn’t already exist in your project, you can create it. It should be placed in the root directory of your project.
Next, add the following to the vue.config.js file:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
// ============================================================================ // Author: Kenneth Perkins // Date: Jan 17, 2021 // Taken From: http://programmingnotes.org/ // File: vue.config.js // Description: Adds additional options to the site config // ============================================================================ module.exports = { // Project deployment base // By default we assume your app will be deployed at the root of a domain, // e.g. https://www.my-app.com/ // If your app is deployed at a sub-path, you will need to specify that // sub-path here. For example, if your app is deployed at // https://www.foobar.com/my-app/ // then change this to '/my-app/' publicPath: process.env.NODE_ENV === 'production' ? '/your-subfolder/' : '/', }// http://programmingnotes.org/ |
If you are using Vue Router in your project, make sure to update the related base property of the router.
This can be done by updating the router index.js like so:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
// ============================================================================ // Author: Kenneth Perkins // Date: Jan 17, 2021 // Taken From: http://programmingnotes.org/ // File: index.js // Description: Router index file which sets up the routes for the project // ============================================================================ import { createWebHistory, createRouter } from 'vue-router'; let routes = []; // This sets the base url using the 'publicPath' property from vue.config.js const router = createRouter({ history: createWebHistory( process.env.BASE_URL ), routes }); export default router; // http://programmingnotes.org/ |
After the changes above are applied, follow the steps highlighted in Step 1 to build your project.
Next, upload the files generated in the ‘dist‘ folder into the subfolder directory on your server. The files can be uploaded using any method familiar to you.
Once the files are uploaded, your site should be live!
4. Server Configuration – HTML5 History Mode
When using Vue Router with HTML5 history mode, without a proper server configuration, users will get a 404 server error if they access ‘http://yoursite.com/user/id’ directly in their browser.
To fix the issue, all you need to do is add a simple catch-all fallback route to your server. If the URL doesn’t match any static assets, it should serve the same index.html page that your app lives in.
For example, if using Apache, this is configured in the .htaccess file.
If this file doesn’t already exist, you can create it. It should be placed in the same directory as your apps index.html file.
Next, add the following to the .htaccess file:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
# ============================================================================ # Author: Kenneth Perkins # Date: Jan 17, 2021 # Taken From: http://programmingnotes.org/ # File: .htaccess # Description: Catch all server fallback for routes in a app # ============================================================================ <IfModule mod_rewrite.c> RewriteEngine On RewriteBase / RewriteRule ^index\.html$ - [L] RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule . /index.html [L] </IfModule> # http://programmingnotes.org/ |
If your app is deployed in a subfolder, using Apache, this is also configured in the .htaccess file.
If this file doesn’t already exist, you can create it. It should be placed in the same directory as your apps index.html file.
Next, add the following to the .htaccess file:
Note: Replace ‘[[[your-subfolder]]]‘ with the subfolder name where your app resides.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
# ============================================================================ # Author: Kenneth Perkins # Date: Jan 17, 2021 # Taken From: http://programmingnotes.org/ # File: .htaccess # Description: Catch all server fallback for routes in a subfolder app # ============================================================================ <IfModule mod_rewrite.c> RewriteEngine On RewriteBase / RewriteRule ^index\.html$ - [L] RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule . /[[[your-subfolder]]]/index.html [L] </IfModule> # http://programmingnotes.org/ |
For more example configurations, visit the official documentation for more information!
QUICK NOTES:
The highlighted lines are sections of interest to look out for.
The code is heavily commented, so no further insight is necessary. If you have any questions, feel free to leave a comment below.
Vue || How To Create A Simple Store With Shopping Cart Using Vuex, Vue Router & Vue
The following is an implementation which demonstrates how to create a simple store with a shopping cart using Vuex, Vue Router and Vue.
This store allows you to add and remove items from a cart, filter items by category, create a new user, log in and log out (with automatic redirect), and “purchase” the items in the cart on the checkout page.
1. Get Started
To get started, make sure you have a package manager like Node.js installed. Node.js is used to install packages.
You’ll also want to have vue-cli installed. Visit the official documentation for more information on how this is done.
Next, navigate to the project directory in the terminal, then run the following commands (Node.js):
Project Setup
npm install
Compiles and hot-reloads for development
npm run serve
2. Features
This project implements a simple store with the following features:
1. Login / Create account (with automatic redirect)
2. Retrieve products from a mock 'API'
3. Add/Remove item to shopping cart
4. Simulate purchasing items on checkout
5. Custom 404 page
6. Display products per category
7. Hamburger 'options' menu
3. Screenshots
4. Download
QUICK NOTES:
The highlighted lines are sections of interest to look out for.
The code is heavily commented, so no further insight is necessary. If you have any questions, feel free to leave a comment below.
JavaScript/CSS/HTML || SlidePanel.js – How To Create An Animated Sidebar Navigation Menu Panel Using Vanilla JavaScript
The following is a module with functions that demonstrates how to create an animated sliding sidebar navigation ‘hamburger’ menu panel using Vanilla JavaScript.
Using Vanilla JavaScript and CSS, by default the menu panel swipes in and out from left to right. The panel can also be opened from right to left, top to bottom, and bottom to top. All of this behavior, as well as its look and feel can be adjusted via CSS.
Contents
1. Basic Usage
2. Navigation SlidePanel Menu HTML
3. SlidePanel.js & CSS Source
4. More Examples
1. Basic Usage
Syntax is very straightforward. The following demonstrates the JavaScript used to setup the sidebar navigation slide panels and menu event listeners.
Calling this function sets up all of the slide panels and buttons on the page.
1 2 3 4 5 6 7 8 |
<!-- Basic Usage --> <script> document.addEventListener("DOMContentLoaded", function(eventLoaded) { // Setup navigation slide panels and event listeners SlidePanel.init(); }); </script> |
2. Navigation SlidePanel Menu HTML
The following is the HTML used to setup the sidebar navigation slide panel. The placement of the ‘hamburger’ button, as well as the direction that the sidebar menu opens can easily be adjusted via CSS.
Below is a stripped down simple example demonstrating the basic html used to setup a sidebar panel. In this example, the panel is opened from left to right.
Navigation slide panel menus can also open from right to left, top to bottom, and bottom to top. Check out the end of the page for a full example!
Open Left To Right
The following demonstrates how to open the navigation slide panel menu from right to left.
By default, the menu opens on the left side of the page. Adding ‘right‘ to the class list places the menu on the right side of the page.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
<!-- SlidePanel Menu HTML --> <!-- Top Nav --> <nav> <!-- SlidePanel menu 'hamburger' button. -- The property 'data-for' specifies the element id of the slide panel the button should open --> <button class="slide-panel-button open" data-for="nav-menu"></button> <div style="margin: auto;"> <h1>My Programing Notes</h1> </div> </nav> . . . <!-- This is the SlidePanel. The opening behavior of the panel is defined here. -- The property 'data-includeBackground' determines whether a background overlay should be displayed behind the menu panel -- The property 'data-closeOnBackgroundClick' determines whether the menu panel should close when clicking on the background overlay --> <section class="slide-panel" id="nav-menu" data-includeBackground="true" data-closeOnBackgroundClick="true"> <!-- Close button --> <button class="slide-panel-button close"></button> <a href="#">About</a> <a href="#">Services</a> <a href="#">Clients</a> <a href="#">Contact</a> </section> |
Open Right To Left
The following demonstrates how to open the navigation slide panel menu from right to left.
By default, the menu opens on the left side of the page. Adding ‘right‘ to the class list places the menu on the right side of the page.
1 2 3 4 5 6 |
<!-- SlidePanel Menu HTML - Open Right To Left --> <section class="slide-panel right" id="nav-menu"> <!-- Close button --> <button class="slide-panel-button close"></button> </section> |
Open Top To Bottom
The following demonstrates how to open the navigation slide panel menu from top to bottom.
By default, the menu opens on the left side of the page. Adding ‘right‘ to the class list places the menu on the right side of the page.
1 2 3 4 5 6 |
<!-- SlidePanel Menu HTML - Open Top To Bottom --> <section class="slide-panel top" id="nav-menu"> <!-- Close button --> <button class="slide-panel-button close"></button> </section> |
Open Bottom To Top
The following demonstrates how to open the navigation slide panel menu from bottom to top.
By default, the menu opens on the left side of the page. Adding ‘right‘ to the class list places the menu on the right side of the page.
1 2 3 4 5 6 |
<!-- SlidePanel Menu HTML - Open Bottom To Top --> <section class="slide-panel bottom" id="nav-menu"> <!-- Close button --> <button class="slide-panel-button close"></button> </section> |
3. SlidePanel.js & CSS Source
The following is the SlidePanel.js Namespace & CSS Source. Include this in your project to start using!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 |
// ============================================================================ // Author: Kenneth Perkins // Date: Jan 9, 2021 // Taken From: http://programmingnotes.org/ // File: SlidePanel.js // Description: Module that opens/closes a slide panel // Example: // // Open SlidePanel // SlidePanel.open(element) // // // Close SlidePanel // SlidePanel.close(element) // ============================================================================ /** * NAMESPACE: SlidePanel * USE: Handles SlidePanel related functions */ var SlidePanel = SlidePanel || {}; (function(namespace) { 'use strict'; // -- Public data -- // Property to hold public variables and functions let exposed = namespace; // Set class names and other shared data const settings = { // Element class names classNameSlidePanel: '.slide-panel', classNameSlidePanelOpen: '.open', classNameSlidePanelClose: '.close', classNameSlidePanelButton: '.slide-panel-button', classNameSlidePanelBackground: '.slide-panel-background', // Element data names dataNamePanelFor: 'data-for', dataNameCloseOnBackgroundClick: 'data-closeOnBackgroundClick', dataNameIncludeBackground: 'data-includeBackground', cleanClassName: (str) => { return str ? str.trim().replace('.', '') : ''; }, }; exposed.settings = settings; /** * FUNCTION: init * USE: Adds click events for the slide panel menus * @param element: JavaScript element to search for slide panel buttons * @return: N/A */ exposed.init = (element = document) => { // Setup panels let panels = getPanels(element); for (let panel of panels) { // Include background if needed if (shouldIncludeBackground(panel)) { let background = getBackground(panel) || createBackground(panel); if (shouldCloseOnBackgroundClick(panel)) { background.addEventListener('click', backgroundCloseEvent); } } } // Register open button events let openButtons = getOpenButtons(element); for (let openButton of openButtons) { // Get the slide panel panel for the button let panel = getPanel(openButton); // Make sure panel exists if (isNull(panel)) { console.error(`Unable to open: SlidePanel element id '${getPanelFor(openButton)}' does not exist`); continue; } // Add click event openButton.addEventListener('click', openEvent); } // Register close button events let closeButtons = getCloseButtons(element); for (let closeButton of closeButtons) { // Add click event closeButton.addEventListener('click', closeEvent); } } /** * FUNCTION: open * USE: Opens the slide panel * @param panel: JavaScript element of the slide panel * @return: N/A */ exposed.open = (panel) => { let background = getBackground(panel); if (!isNull(background)) { addClass(background, settings.classNameSlidePanelOpen); } addClass(panel, settings.classNameSlidePanelOpen); } /** * FUNCTION: close * USE: Closes the slide panel * @param panel: JavaScript element of the slide panel * @return: N/A */ exposed.close = (panel) => { let background = getBackground(panel); if (!isNull(background)) { let duration = getTransitionDuration(panel); setTimeout(() => { removeClass(background, settings.classNameSlidePanelOpen); }, duration - 30); } removeClass(panel, settings.classNameSlidePanelOpen); } // -- Private data -- let openEvent = (event) => { let panel = getPanel(event.target); exposed.open(panel); } let closeEvent = (event) => { let panel = getPanel(event.target); exposed.close(panel); } let backgroundCloseEvent = (event) => { if (event.target != event.currentTarget) { return; } let panel = getPanel(event.target); exposed.close(panel); } let getPanel = (element) => { let panel = null; // Button if (hasClass(element, settings.classNameSlidePanelButton)) { // Open button if (hasClass(element, settings.classNameSlidePanelOpen)) { let navFor = getPanelFor(element); if (isEmpty(navFor)) { console.error(`'${settings.dataNamePanelFor}' is not specified for a SlidePanel 'open' button`); } else { panel = document.querySelector(`#${navFor}`); } // Close button } else if (hasClass(element, settings.classNameSlidePanelClose)) { panel = element.closest(settings.classNameSlidePanel) } // Background } else if (hasClass(element, settings.classNameSlidePanelBackground)) { panel = element.querySelector(settings.classNameSlidePanel) } return panel; } let getPanelFor = (element) => { return element.getAttribute(settings.dataNamePanelFor); } let getBackground = (panel) => { return panel.closest(settings.classNameSlidePanelBackground); } let getPanels = (element = document) => { return element.querySelectorAll(settings.classNameSlidePanel); } let getOpenButtons = (element = document) => { return element.querySelectorAll(`${settings.classNameSlidePanelButton}${settings.classNameSlidePanelOpen}`); } let getCloseButtons = (element = document) => { return element.querySelectorAll(`${settings.classNameSlidePanelButton}${settings.classNameSlidePanelClose}`); } let shouldCloseOnBackgroundClick = (element) => { let value = element.getAttribute(settings.dataNameCloseOnBackgroundClick); if (isNull(value)) { value = true; } return toBoolean(value); } let shouldIncludeBackground = (element) => { let value = element.getAttribute(settings.dataNameIncludeBackground); if (isNull(value)) { value = true; } return toBoolean(value); } let createBackground = (element) => { let container = document.createElement('div'); let parentNode = element.parentNode; addClass(container, settings.classNameSlidePanelBackground); parentNode.insertBefore(container, element); container.appendChild(element); return container; } let addClass = (element, cssClass) => { cssClass = settings.cleanClassName(cssClass); let modified = false; if (cssClass.length > 0 && !hasClass(element, cssClass)) { element.classList.add(cssClass) modified = true; } return modified; } let removeClass = (element, cssClass) => { cssClass = settings.cleanClassName(cssClass); let modified = false; if (cssClass.length > 0 && hasClass(element, cssClass)) { element.classList.remove(cssClass); modified = true; } return modified; } let hasClass = (element, cssClass) => { cssClass = settings.cleanClassName(cssClass); return element.classList.contains(cssClass); } let toBoolean = (value) => { value = String(value).trim().toLowerCase(); let ret = false; switch (value) { case 'true': case 'yes': case '1': ret = true; break; } return ret; } let isNull = (item) => { return undefined === item || null === item; } let isEmpty = (str) => { return isNull(str) || String(str).trim().length < 1; } let getTransitionDuration = (element) => { let style = window.getComputedStyle(element); let duration = style['transitionDuration'] || style['transition-duration']; // fix miliseconds vs seconds duration = (duration.indexOf('ms') > -1) ? parseFloat(duration) : parseFloat(duration) * 1000; return duration; } (function (factory) { if (typeof define === 'function' && define.amd) { define([], factory); } else if (typeof exports === 'object') { module.exports = factory(); } }(function() { return namespace; })); }(SlidePanel)); // http://programmingnotes.org/ |
The following is SlidePanel.css.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 |
/* // ============================================================================ // Author: Kenneth Perkins // Date: Jan 9, 2021 // Taken From: http://programmingnotes.org/ // File: SlidePanel.css // Description: CSS for the slide panel // ============================================================================ */ @import url('https://fonts.googleapis.com/css?family=Roboto:400,400italic,500,500italic,700,700italic,900,900italic,300italic,300,100italic,100'); .slide-panel { position: fixed; width: 300px; top: 0; left: 0; transform: translate(-100%, 0%); /* (x, y) */ height: 100%; overflow: auto; transition: transform 220ms ease-in-out; z-index: 1000; background-color: #f3f3f3; background-color: white; box-shadow: 0 0 15px rgba(0,0,0,0.55); font-family: "Roboto",sans-serif, Marmelad,"Lucida Grande",Arial,"Hiragino Sans GB",Georgia,"Helvetica Neue",Helvetica; } .slide-panel.right { right: 0; left: auto; transform: translate(100%, 0%); } .slide-panel.top { top: 0; bottom: auto; transform: translate(0%, -100%); } .slide-panel.bottom { bottom: 0; top: auto; transform: translate(0%, 100%); } .slide-panel.open { transform: translate(0%, 0%); } @media screen and (max-width: 450px) { .slide-panel { width: 80%; } .slide-panel.top, .slide-panel.bottom { width: 100%; } } .slide-panel-background { position: fixed; z-index: 1000; padding-top: 60px; left: 0; top: 0; width: 100%; height: 100%; background-color: rgba(0,0,0,0.5); opacity: 0; visibility: hidden; transition: visibility 300ms, opacity 300ms; } .slide-panel-background.open { opacity: 1; visibility: visible; } .slide-panel-button:hover { background-color: #eee; } .slide-panel-button { display: inline-block; cursor: pointer; padding: 10px; background: none; border: none; position: absolute; left: 0; } .slide-panel-button.right { right: 0; left: auto; } .slide-panel-button.open {} .slide-panel-button.close { top: 0; } .slide-panel-button:before { width: 25px; height: 25px; content: ""; display: inline-block; vertical-align: middle; background-size: 100%; background-repeat: no-repeat; } .slide-panel-button.open:before { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='35' height='35' viewBox='0 0 24 24' fill='none' stroke='%23000000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='3' y1='12' x2='21' y2='12'%3E%3C/line%3E%3Cline x1='3' y1='6' x2='21' y2='6'%3E%3C/line%3E%3Cline x1='3' y1='18' x2='21' y2='18'%3E%3C/line%3E%3C/svg%3E"); } .slide-panel-button.close:before { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='35' height='35' viewBox='0 0 24 24' fill='none' stroke='%23000000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='18' y1='6' x2='6' y2='18'%3E%3C/line%3E%3Cline x1='6' y1='6' x2='18' y2='18'%3E%3C/line%3E%3C/svg%3E"); }/* http://programmingnotes.org/ */ |
4. More Examples
Below are more examples demonstrating the use of ‘SlidePanel.js‘. Don’t forget to include the module when running the examples!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 |
<!-- // ============================================================================ // Author: Kenneth Perkins // Date: Jan 9, 2021 // Taken From: http://programmingnotes.org/ // File: SlidePanel.html // Description: Demonstrates a simple animated slide panel // ============================================================================ --> <!DOCTYPE html> <html> <head> <meta charset="utf-8"/> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>My Programming Notes SlidePanel.js Demo</title> <style> * { margin:0; padding:0; box-sizing:border-box; } .content { margin: 15px; } p { margin-top: 20px; } .nav { display: flex; align-items: center; position: sticky; top: 0; background-color: #e0e0cc; background-color: white; z-index: 1; padding: 8px 0; height: 52px; box-shadow: 0 1px 2px rgba(0,0,0,0.10),0 1px 4px rgba(0,0,0,0.10),0 2px 8px rgba(0,0,0,0.10); font-family: "Roboto",sans-serif, Marmelad,"Lucida Grande",Arial,"Hiragino Sans GB",Georgia,"Helvetica Neue",Helvetica; } .links a { padding: 8px 8px 8px 32px; text-decoration: none; font-size: 25px; color: #818181; display: block; } .links a:hover { color: orangered; } .links { padding-top: 40px; margin: auto; } .menu-header { margin-top: 50px; text-align: center; } </style> <!-- // Include module --> <link type="text/css" rel="stylesheet" href="./SlidePanel.css"> <script type="text/javascript" src="./SlidePanel.js"></script> </head> <body> <main> <nav class="nav"> <!-- SlidePanel menu 'hamburger' button. -- The property 'data-for' specifies the element id of the slide panel the button should open --> <button class="slide-panel-button open" data-for="nav-menu"></button> <button class="slide-panel-button open" data-for="nav-menu-top" style="left: 50px;"></button> <button class="slide-panel-button open right" data-for="nav-menu-right"></button> <button class="slide-panel-button open right" data-for="nav-menu-right-bottom" style="right: 50px;"></button> <div style="margin: auto;"> <h1>My Programing Notes</h1> </div> </nav> <section class="content"> <p> Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Placerat duis ultricies lacus sed turpis tincidunt id aliquet. Fringilla urna porttitor rhoncus dolor purus non. Tortor dignissim convallis aenean et. Nulla facilisi nullam vehicula ipsum a arcu cursus vitae. Egestas maecenas pharetra convallis posuere. Nam aliquam sem et tortor consequat. Scelerisque varius morbi enim nunc. In fermentum posuere urna nec. Malesuada fames ac turpis egestas sed. Fringilla ut morbi tincidunt augue interdum velit. Sed augue lacus viverra vitae congue eu consequat. </p> <p> Imperdiet sed euismod nisi porta lorem mollis. Purus sit amet volutpat consequat mauris. Eu nisl nunc mi ipsum faucibus vitae. Platea dictumst quisque sagittis purus sit. Ultrices tincidunt arcu non sodales neque sodales. Nec sagittis aliquam malesuada bibendum arcu vitae elementum curabitur. Vitae aliquet nec ullamcorper sit amet risus. Nisi quis eleifend quam adipiscing vitae proin sagittis nisl rhoncus. Est ullamcorper eget nulla facilisi. Quis vel eros donec ac odio tempor orci dapibus ultrices. Dapibus ultrices in iaculis nunc sed augue lacus viverra. Nec feugiat nisl pretium fusce id velit ut. A cras semper auctor neque vitae tempus. Faucibus scelerisque eleifend donec pretium vulputate sapien nec sagittis. Eget mi proin sed libero enim sed faucibus. <p> Bibendum enim facilisis gravida neque. A scelerisque purus semper eget. Nisl nisi scelerisque eu ultrices vitae auctor. Semper viverra nam libero justo laoreet sit. Nunc congue nisi vitae suscipit tellus mauris a diam maecenas. Auctor eu augue ut lectus arcu bibendum. Adipiscing commodo elit at imperdiet dui accumsan sit amet. Pellentesque habitant morbi tristique senectus et netus. Mauris nunc congue nisi vitae suscipit tellus mauris a diam. Felis donec et odio pellentesque diam. Ornare aenean euismod elementum nisi quis eleifend quam adipiscing. Ullamcorper malesuada proin libero nunc consequat. Viverra mauris in aliquam sem fringilla ut morbi tincidunt. Sodales ut etiam sit amet nisl purus in. Sed faucibus turpis in eu mi bibendum neque egestas congue. Viverra nam libero justo laoreet sit amet. Egestas quis ipsum suspendisse ultrices gravida dictum fusce ut. </p> <p> Felis imperdiet proin fermentum leo. Lacinia at quis risus sed vulputate odio ut enim blandit. Vitae sapien pellentesque habitant morbi. Amet facilisis magna etiam tempor orci eu lobortis. Massa placerat duis ultricies lacus sed turpis tincidunt id aliquet. Duis ut diam quam nulla porttitor massa. In egestas erat imperdiet sed euismod nisi porta lorem mollis. Interdum posuere lorem ipsum dolor sit amet consectetur adipiscing. Nunc sed id semper risus in hendrerit gravida. Ornare arcu dui vivamus arcu felis bibendum ut. Amet porttitor eget dolor morbi non. Vitae justo eget magna fermentum iaculis eu. Nibh tellus molestie nunc non blandit massa enim nec. Sollicitudin nibh sit amet commodo nulla facilisi nullam vehicula ipsum. Proin nibh nisl condimentum id venenatis a condimentum vitae sapien. Tempor id eu nisl nunc mi ipsum faucibus vitae. </p> <p> Et molestie ac feugiat sed lectus vestibulum mattis. Tristique senectus et netus et malesuada fames. Purus in mollis nunc sed id semper. Mauris cursus mattis molestie a iaculis. Auctor elit sed vulputate mi sit amet mauris commodo quis. Vel orci porta non pulvinar neque. Augue neque gravida in fermentum et. Non odio euismod lacinia at quis risus. In hac habitasse platea dictumst vestibulum rhoncus. Sapien et ligula ullamcorper malesuada proin. Sed vulputate mi sit amet mauris commodo. Et pharetra pharetra massa massa ultricies mi quis hendrerit. In nisl nisi scelerisque eu ultrices vitae auctor eu. Luctus accumsan tortor posuere ac ut consequat semper. </p> </section> </main> <!-- This is the SlidePanel. The opening behavior of the panel is defined here. -- The property 'data-includeBackground' determines whether a background overlay should be displayed behind the menu panel -- The property 'data-closeOnBackgroundClick' determines whether the menu panel should close when clicking on the background overlay --> <section class="slide-panel" id="nav-menu" data-includeBackground="true" data-closeOnBackgroundClick="true"> <!-- Close button --> <button class="slide-panel-button close"></button> <div class="menu-header"> Left SlidePanel Menu </div> <div class="links"> <a href="#">About</a> <a href="#">Services</a> <a href="#">Clients</a> <a href="#">Contact</a> </div> </section> <section class="slide-panel top" id="nav-menu-top"> <!-- Close button --> <button class="slide-panel-button close"></button> <div class="menu-header"> Left Top SlidePanel Menu </div> <div class="links"> <a href="#">About</a> <a href="#">Services</a> <a href="#">Clients</a> <a href="#">Contact</a> </div> </section> <section class="slide-panel right" id="nav-menu-right"> <!-- Close button --> <button class="slide-panel-button close"></button> <div class="menu-header"> Right SlidePanel Menu </div> <div class="links"> <a href="#">About</a> <a href="#">Services</a> <a href="#">Clients</a> <a href="#">Contact</a> </div> </section> <section class="slide-panel right bottom" id="nav-menu-right-bottom"> <!-- Close button --> <button class="slide-panel-button close"></button> <div class="menu-header"> Right Bottom SlidePanel Menu </div> <div class="links"> <a href="#">About</a> <a href="#">Services</a> <a href="#">Clients</a> <a href="#">Contact</a> </div> </section> <script> document.addEventListener('DOMContentLoaded', function(eventLoaded) { SlidePanel.init(); }); </script> </body> </html><!-- // http://programmingnotes.org/ --> |
QUICK NOTES:
The highlighted lines are sections of interest to look out for.
The code is heavily commented, so no further insight is necessary. If you have any questions, feel free to leave a comment below.
JavaScript || How To Get Timespan Between Two Dates & Convert Time From Seconds Into Years, Days, Hours, Minutes & Seconds Using Vanilla JavaScript
The following is a module with functions which demonstrates how to get the timespan between two dates and convert time from seconds into years, days, hours, minutes and seconds using vanilla JavaScript.
This page also demonstrates how to convert time from -seconds- into HH::MM::SS (hours, minutes seconds) format. So for example, if you had an input time of 9630 seconds, the program would display the converted time of 2 hours, 40 minutes, and 30 seconds.
Using simple math, this function utilizes the modulus operator, and the division operator during the conversion process.
1. Get Timespan – Dates
The example below demonstrates the use of ‘Utils.getTimespan‘ to get the timespan between two dates and return the time difference in years, days, hours, minutes and seconds.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
// Get Timespan - Dates <script> (() => { // Declare dates let date1 = new Date('1987-07-28 19:22:31'); let date2 = new Date('1991-01-27 10:19:28'); // Get the timespan let timespan = Utils.getTimespan(date1, date2); // Display result console.log(`Date 1: ${date1.toLocaleString()}`); console.log(`Date 2: ${date2.toLocaleString()}`); console.log(timespan.toString()); console.log(timespan); })(); </script> // expected output: /* Date 1: 7/28/1987, 7:22:31 PM Date 2: 1/27/1991, 10:19:28 AM 3 years, 183 days, 14 hours, 56 minutes, 57 seconds { "years": 3, "days": 183, "hours": 14, "minutes": 56, "seconds": 57, "milliseconds": 0, "totalYears": 3.5030763888888887, "totalDays": 1278.6228819444445, "totalHours": 30686.949166666665, "totalMinutes": 1841216.95, "totalSeconds": 110473017, "totalMilliseconds": 110473017000 } */ |
2. Get Timespan – Seconds
The example below demonstrates the use of ‘Utils.getTimespan‘ to get the timespan from seconds and return the timespan in years, days, hours, minutes and seconds.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
// Get Timespan - Seconds <script> (() => { // Declare seconds let seconds = 9630; // Get the timespan let timespan = Utils.getTimespan(seconds); // Display result console.log(`Seconds: ${seconds}`); console.log(timespan.toString()); console.log(timespan); })(); </script> // expected output: /* Seconds: 9630 2 hours, 40 minutes, 30 seconds { "years": 0, "days": 0, "hours": 2, "minutes": 40, "seconds": 30, "milliseconds": 0, "totalYears": 0.000305365296803653, "totalDays": 0.11145833333333334, "totalHours": 2.675, "totalMinutes": 160.5, "totalSeconds": 9630, "totalMilliseconds": 9630000 } */ |
3. Utils Namespace
The following is the Utils.js Namespace. Include this in your project to start using!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 |
// ============================================================================ // Author: Kenneth Perkins // Date: Jan 1, 2021 // Taken From: http://programmingnotes.org/ // File: Utils.js // Description: Javascript that handles general utility functions // ============================================================================ /** * NAMESPACE: Utils * USE: Handles general utility functions. */ var Utils = Utils || {}; (function(namespace) { 'use strict'; // Property to hold public variables and functions let exposed = namespace; /** * FUNCTION: getTimespan * USE: Returns the timespan between two dates, or a time value in seconds * @param start: The starting time * @param end: The ending time * @return: An object which contains information about the timespan */ exposed.getTimespan = (start, end = null) => { // Get the seconds let seconds = Number(start); if (isDate(start) && isDate(end)) { seconds = exposed.getDurationSeconds(start, end); } // Convert seconds to time let timespan = {}; let remainingTime = seconds; for (const def of conversion) { // Get time conversion timespan[def.key] = Math.floor(remainingTime / def.value); remainingTime %= def.value; // Add additional info let additionalKey = `total${capitalize(def.key)}`; timespan[additionalKey] = seconds / def.value; } // Add additional info timespan.toString = () => { let string = ''; for (const def of conversion) { let value = timespan[def.key] if (value != 0) { let name = def.key; if (name.endsWith('s')) { name = name.substring(0, name.length - 1); } string += string.length > 0 ? ',' : ''; string += ` ${value} ${name}${value == 1 ? '' : 's'}`; } } return string.trim(); } return timespan; } /** * FUNCTION: getDurationSeconds * USE: Returns the number of seconds between the two dates * @param dateStart: The starting date * @param dateEnd: The ending date * @return: The number of seconds between the two dates */ exposed.getDurationSeconds = (dateStart, dateEnd) => { let timeStart = dateStart ? treatAsUTC(dateStart).getTime() : 0; let timeEnd = dateEnd ? treatAsUTC(dateEnd).getTime() : 0; return (timeEnd - timeStart) / 1000; } let treatAsUTC = (date) => { let result = new Date(date); result.setMinutes(result.getMinutes() - result.getTimezoneOffset()); return result; } let isDate = (expression) => { return expression && (expression instanceof Date); } let capitalize = (string) => { return string.charAt(0).toUpperCase() + string.substring(1); } // Set the time conversion definitions (from seconds) const conversion = [ {key: 'years', value: 60 * 60 * 24 * 365}, {key: 'days', value: 60 * 60 * 24}, {key: 'hours', value: 60 * 60}, {key: 'minutes', value: 60}, {key: 'seconds', value: 1}, {key: 'milliseconds', value: 1 / 1000} ]; (function (factory) { if (typeof define === 'function' && define.amd) { define([], factory); } else if (typeof exports === 'object') { module.exports = factory(); } }(function() { return namespace; })); }(Utils)); // http://programmingnotes.org/ |
QUICK NOTES:
The highlighted lines are sections of interest to look out for.
The code is heavily commented, so no further insight is necessary. If you have any questions, feel free to leave a comment below.
Vue || How To Set, Add & Update Query Params With Vue Router Using Vue
The following is a module which demonstrates how to set, add and update query params with Vue using Vue Router.
Note: The examples below assumes your project is already set up and configured. For an overview on how to get started with Vue and Vue Router, visit the official documentation.
1. Add & Update Query
The example below is a simple page with a login link. The link has a redirect parameter to navigate back to the referring page after successful login.
Clicking on the link results in the following:
/login?[existing query + computed result]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
<!-- // ============================================================================ // Author: Kenneth Perkins // Date: Dec 31, 2020 // Taken From: http://programmingnotes.org/ // File: Home.vue // Description: Page that has a login redirect link // ============================================================================ --> <template> <section> <router-link :to="{name: 'Login', query: redirectQuery}"> Log in </router-link> </section> </template> <script> export default { data() { return {} }, computed: { redirectQuery() { return Object.assign({}, this.$route.query, {redirect: this.$route.query.redirect || this.$route.path}); } }, }; </script> <style scoped> </style> <!-- http://programmingnotes.org/ --> |
QUICK NOTES:
The highlighted lines are sections of interest to look out for.
The code is heavily commented, so no further insight is necessary. If you have any questions, feel free to leave a comment below.
Vue || How To Set Up Fade In & Fade Out Router View Transitions With Vue Router Using Vue
The following is a module which demonstrates how to set up fade in and fade out router view transitions with Vue using Vue Router.
Note: The examples below assumes your project is already set up and configured. For an overview on how to get started with Vue and Vue Router, visit the official documentation.
1. Router Index File
The example below is a sample router index.js file. This file sets up the routes in the project.
There are 2 routes: a ‘Home‘ page, and a ‘About‘ page.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
// ============================================================================ // Author: Kenneth Perkins // Date: Dec 30, 2020 // Taken From: http://programmingnotes.org/ // File: index.js // Description: Router index.js file // ============================================================================ import { createRouter, createWebHistory } from 'vue-router'; const routes = [ { path: '/', name: 'Home', component: () => import(/* webpackChunkName: "Home" */ '../views/Home.vue') }, { path: '/about', name: 'About', component: () => import(/* webpackChunkName: "About" */ '../views/About.vue') } ]; const router = createRouter({ history: createWebHistory(), routes }); export default router; // http://programmingnotes.org/ |
The layout of the routes above are not important. They are declared here simply to demonstrate a project with multiple routes set up.
2. App.vue
The example below is the ‘App.vue‘ page. This is the root of the application. In this example, this is where the fade in and fade out router view transitions will take effect.
When a route is clicked, its contents is loaded inside the router-view. The example below demonstrates how to set up the fade in and fade out router view transition effect.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
<!-- // ============================================================================ // Author: Kenneth Perkins // Date: Dec 30, 2020 // Taken From: http://programmingnotes.org/ // File: App.vue // Description: Home page that displays content via router-view // ============================================================================ --> <template> <div id="nav"> <router-link :to="{name: 'Home'}">Home</router-link> | <router-link :to="{name: 'About'}">About</router-link> </div> <router-view v-slot="slotProps"> <transition name="fade" mode="out-in"> <component :is="slotProps.Component"></component> </transition> </router-view> </template> <script> export default { data() { return {} }, methods: {} } </script> <style> .fade-enter-active, .fade-leave-active { transition: opacity 0.3s; } .fade-enter, .fade-leave-to { opacity: 0; } </style> <!-- http://programmingnotes.org/ --> |
QUICK NOTES:
The highlighted lines are sections of interest to look out for.
The code is heavily commented, so no further insight is necessary. If you have any questions, feel free to leave a comment below.
Vue || How To Set Up Vue Smooth Scroll Behavior With Vue Router Using Vue
The following is a module which demonstrates how to set up smooth anchor scroll behavior when navigating to a new route with Vue using Vue Router.
Note: The examples below assumes your project is already set up and configured. For an overview on how to get started with Vue and Vue Router, visit the official documentation.
1. Router Index File
The example below is a sample router index.js file. This file sets up the routes in the project. Its also where you set up the scrolling behavior when navigating to a new route.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
// ============================================================================ // Author: Kenneth Perkins // Date: Dec 26, 2020 // Taken From: http://programmingnotes.org/ // File: index.js // Description: Router index.js file // ============================================================================ import { createWebHistory, createRouter } from "vue-router"; const routes = []; const router = createRouter({ history: createWebHistory(), routes, scrollBehavior(to, from, savedPosition) { let defaultPos = {left: 0, top: 0}; if (savedPosition) { return savedPosition; } else if (to.hash) { let elem = document.querySelector(to.hash); return elem ? elem.scrollIntoView({ behavior: 'smooth' }) : defaultPos; } else { return defaultPos; } } }); export default router; // http://programmingnotes.org/ |
QUICK NOTES:
The highlighted lines are sections of interest to look out for.
The code is heavily commented, so no further insight is necessary. If you have any questions, feel free to leave a comment below.
Vue || How To Create A 404 Not Found Route With Dynamic Nested Routes With Vue Router Using Vue
The following is a module which demonstrates how to create a 404 not found route with dynamic nested routes via Vue Router using Vue.
Routes can be checked using Navigation Guards. This page will demonstrate verifying nested routes using the Per Route Guard.
This will demonstrate how to create a route that catches all non existing routes with Vue Router. It will also demonstrate how to use navigation guards to make sure nested dynamic routes exists.
Note: The examples below assumes your project is already set up and configured. For an overview on how to get started with Vue and Vue Router, visit the official documentation.
1. Router Index File
The example below is a sample router index.js file. This file sets up the routes in the project.
There are 4 routes: a ‘Home‘ page, a ‘DestinationDetails‘ page, a ‘ExperienceDetails‘ page, and a ‘NotFound‘ page.
The ‘ExperienceDetails‘ page is a nested child route.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
// ============================================================================ // Author: Kenneth Perkins // Date: Dec 25, 2020 // Taken From: http://programmingnotes.org/ // File: index.js // Description: Router index.js file // ============================================================================ import { createWebHistory, createRouter } from "vue-router"; const routes = [ { path: "/", name: "Home", component: () => import(/* webpackChunkName: "Home" */ "../views/Home.vue"), }, { path: "/destination/:slug", name: "DestinationDetails", props: true, component: () => import(/* webpackChunkName: "DestinationDetails" */ "../views/DestinationDetails.vue"), children: [{ path: ":experienceSlug", name: "ExperienceDetails", props: true, component: () => import(/* webpackChunkName: "ExperienceDetails" */ "../views/ExperienceDetails.vue") }], beforeEnter: (to, from, next) => { // Verify the route exists by checking the API let exists = false; // If this is a parent route, check if it exists if (to.params.slug) { // Do something to check if this is valid exists = true; } // If this is a child route, check if it exists if (to.params.experienceSlug) { // Do something to check if this is valid exists = true; } // If the route exists, navigate to it if (exists) { next(); } else { next({name: "NotFound"}); } } }, { path: "/404", name: "NotFound", component: () => import(/* webpackChunkName: "NotFound" */ "../views/NotFound.vue") }, { path: "/:catchAll(.*)", redirect: {name: "NotFound"} } ]; const router = createRouter({ history: createWebHistory(), routes }); export default router; // http://programmingnotes.org/ |
The DestinationDetails route is a dynamic route that accepts props. In this example, the route.params will be set as the component props. In this component, the ‘slug‘ prop is used as the dynamic route path identifier.
The ExperienceDetails nested child route is also a dynamic route. In this component, the ‘experienceSlug‘ prop is used as the dynamic route path identifier.
Using the beforeEnter navigation guard, we can check if the route is valid by checking the dynamic route path identifier. If the route is not valid, the ‘NotFound‘ route is navigated to.
The NotFound route catches all non existing routes.
2. Home Page
The example below is the ‘Home‘ route page. This demonstrates how to navigate to the DestinationDetails route using the dynamic props.
It uses router-link to navigate to the specific route.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
<!-- // ============================================================================ // Author: Kenneth Perkins // Date: Dec 25, 2020 // Taken From: http://programmingnotes.org/ // File: Home.vue // Description: Home page that shows all destinations // ============================================================================ --> <template> <section> <h1> All Destinations </h1> <div> <section v-for="destination in destinations" :key="destination.id"> <router-link :to="getNavigationPath(destination)" > <h2>{{destination.name}}</h2> </router-link> <figure> <router-link :to="getNavigationPath(destination)"> <img :src="destination.image" :alt="destination.name"> </router-link> </figure> </section> </div> </section> </template> <script> export default { data() { return { destinations: api.destinations } }, methods: { getNavigationPath(destination) { return { name: 'DestinationDetails', params: { id: destination.id, slug: destination.slug } }; } } }; </script> <style scoped> </style> <!-- http://programmingnotes.org/ --> |
3. Destination Details Page
The example below is the ‘DestinationDetails‘ route page. This demonstrates how to display information about the destination and navigate to the ExperienceDetails route using the dynamic props passed to it.
It uses router-link to navigate to the specific route, and uses router-view to display the nested content from the navigated child route.
When calling the child component, it will automatically receive the parent ‘slug‘ dynamic route path identifier as a parameter.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
<!-- // ============================================================================ // Author: Kenneth Perkins // Date: Dec 25, 2020 // Taken From: http://programmingnotes.org/ // File: DestinationDetails.vue // Description: Displays information about a destination // ============================================================================ --> <template> <section> <div> <h1>{{destination.name}}</h1> <div"> <img :src="destination.image" :alt="destination.name"> <p>{{ destination.description }}</p> </div> </div> <section> <h2> Top experiences in {{destination.name}} </h2> <div> <article v-for="experience in destination.experiences" :key="experience.slug"> <router-link :to="getNavigationPath(experience)"> <img :src="experience.image" :alt="experience.name"> <span> {{experience.name}} </span> </router-link> </article> </div> <router-view :key="$route.path" /> </section> </section> </template> <script> export default { data() { return { } }, props: { slug: { type: String, required: true } }, computed: { destination() { return api.destinations.find( destination => destination.slug == this.slug ); } }, methods: { getNavigationPath(experience) { return { name: 'ExperienceDetails', params: { experienceSlug: experience.slug }, hash: '#experience', }; } } } </script> <style scoped> </style> <!-- http://programmingnotes.org/ --> |
4. Experience Details Page
The example below is the ‘ExperienceDetails‘ route page. This demonstrates how to display information about the destination experience using the dynamic props passed to it.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
<!-- // ============================================================================ // Author: Kenneth Perkins // Date: Dec 25, 2020 // Taken From: http://programmingnotes.org/ // File: ExperienceDetails.vue // Description: Displays information about an experience // ============================================================================ --> <template> <section> <h2>{{experience.name}}</h2> <div> <img :src="experience.image" :alt="experience.name"> <p id="experience"> {{experience.description}} </p> </div> </section> </template> <script> export default { props: { slug: { type: String, required: true, }, experienceSlug: { type: String, required: true, } }, computed: { destination() { return api.destinations.find( destination => destination.slug == this.slug ); }, experience() { return this.destination.experiences.find( experience => experience.slug == this.experienceSlug ); } } } </script> <style scoped> </style> <!-- http://programmingnotes.org/ --> |
5. Not Found (404) Page
The example below is the ‘NotFound‘ route page. This page catches all non existing routes.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
<!-- // ============================================================================ // Author: Kenneth Perkins // Date: Dec 25, 2020 // Taken From: http://programmingnotes.org/ // File: NotFound.vue // Description: Not found (404) page // ============================================================================ --> <template> <section> <h1>Not Found</h1> <p>Oops we couldn't find that page. Try going <router-link :to="{name: 'Home'}"> home </router-link> </p> </section> </template> <script> export default { data() { return {} }, methods: {} } </script> <style scoped> </style> <!-- http://programmingnotes.org/ --> |
QUICK NOTES:
The highlighted lines are sections of interest to look out for.
The code is heavily commented, so no further insight is necessary. If you have any questions, feel free to leave a comment below.
Vue || How To Set Up Vue Login Authentication & Route Handling With Vue Router Using Vue
The following is a module which demonstrates how to set up Vue login authentication and route handling using Vue Router.
Note: The examples below assumes your project is already set up and configured. For an overview on how to get started with Vue and Vue Router, visit the official documentation.
1. Router Index File
The example below is a sample router index.js file. This file sets up the routes in the project.
There are 3 routes: a ‘Home‘ page, a ‘User‘ page, and a ‘Login‘ page.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
// ============================================================================ // Author: Kenneth Perkins // Date: Dec 24, 2020 // Taken From: http://programmingnotes.org/ // File: index.js // Description: Vue Router index.js file // ============================================================================ import { createWebHistory, createRouter } from "vue-router"; const routes = [ { path: "/", name: "home", component: () => import(/* webpackChunkName: "home" */ "../views/Home.vue"), }, { path: "/user", name: "user", component: () => import(/* webpackChunkName: "user" */ "../views/User.vue"), meta: {requiresAuth: true} // Indicates that this route requires authentication }, { path: "/login", name: "login", component: () => import(/* webpackChunkName: "login" */ "../views/Login.vue") } ]; const router = createRouter({ history: createWebHistory(), routes }); router.beforeEach((to, from, next) => { // Determine if the route requires authentication if (to.matched.some(record => record.meta.requiresAuth)) { // Get value from somewhere to determine if the user is // logged in or not let isLoggedIn = false; // If user is not logged in, navigate to the named "login" route // with a query string parameter indicating where to navigate to after // successful login if (!isLoggedIn) { // Navigate to login route next({ name: "login", query: {redirect: to.fullPath} }); } else { next(); } } else { next(); } }); export default router; // http://programmingnotes.org/ |
The ‘User‘ route has a meta property that says that it requires authentication.
Next, the route records are iterated over to check if the requested page requires authentication. If it does, the route is redirected to the ‘Login‘ named route, with a query string parameter of the original page to redirect to after successful login.
2. Login Route Page
The example below is the ‘Login‘ route page. It doesn’t do anything special, it just demonstrates how to accept user input and redirect to the specified path after successful login is complete.
Accessing the route redirect path can be done by using the ‘query’ property on the route object.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
<!-- // ============================================================================ // Author: Kenneth Perkins // Date: Dec 24, 2020 // Taken From: http://programmingnotes.org/ // File: Login.vue // Description: Login authentication page // ============================================================================ --> <template> <section> <h1> Login </h1> <div class="form"> <label for="username">Username</label> <input v-model="username" type="text" name="username" class="input" autocomplete="off" /> <label for="password">Password</label> <input v-model="password" type="password" class="input" autocomplete="off" /> <button @click="login" class="btn">Login</button> </div> </section> </template> <script> export default { data() { return { username: null, password: null, } }, methods: { login() { // Authenticate user against API console.log(this.username, this.password); // Set value somewhere to indicate that the user is logged in let isLoggedIn = true; // Redirect to page const redirectPath = this.$route.query.redirect || '/'; this.$router.push(redirectPath); } } } </script> <style scoped> .form { display: flex; flex-direction: column; max-width: 400px; margin: 0 auto; } </style> <!-- http://programmingnotes.org/ --> |
QUICK NOTES:
The highlighted lines are sections of interest to look out for.
The code is heavily commented, so no further insight is necessary. If you have any questions, feel free to leave a comment below.
JavaScript/CSS/HTML || Simple Tic Tac Toe Game With Minimax AI Using Vanilla JavaScript
The following is a module with functions which demonstrates how to create a simple Tic-Tac-Toe game with computer AI using vanilla JavaScript.
This game allows for two or more players, or computer AI vs computer AI. The first player to match 3 pieces horizontally, vertically and diagonally in a row wins!
1. Features
This game allows for two or more players. To add more players, click the “add new” button under the “players” list. To edit a player, click the “edit” button next to a players name.
• Adding and editing a player allows you to change:
1. Name
2. Avatar image url
3. CPU player & difficulty
• To remove a player, click the “remove” button next to the players name.
• A “save game” button allows to save the progress of the game. A file is generated, which consists of the state of the game. This file can be used to reload the game, using the “load game” button.
• Match history is saved, and lets you see the game stats from the previous completed games.
• Player AI uses the minimax algorithm. It has 4 levels of difficulty:
1. Easy
2. Normal
3. Hard
4. Impossible - You will not win!
2. Screenshots
3. Download & Play
QUICK NOTES:
The highlighted lines are sections of interest to look out for.
The code is heavily commented, so no further insight is necessary. If you have any questions, feel free to leave a comment below.
JavaScript || How To Get A Variable Name As A String Using Vanilla JavaScript
The following is a module with functions which demonstrates how to get the name of a variable as a string using vanilla JavaScript.
1. Simple Variable
The example below demonstrates the use of ‘Utils.nameOf‘ to get name of a simple variable.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
// Simple Variable <script> (() => { // Get the name of the variable let simpleString = 'My Programming Notes'; console.log( Utils.nameOf({ simpleString }) ); })(); </script> // expected output: /* simpleString */ |
2. Array
The example below demonstrates the use of ‘Utils.nameOf‘ to get the name of an array.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
// Array <script> (() => { // Mixed array let mixedArray = [ [0, 'Aluminium', 0, 'Francis'], [1, 'Argon', 1, 'Ada'], [2, 'Brom', 2, 'John'], [3, 'Cadmium', 9, 'Marie'], [4, 'Fluor', 12, 'Marie'], [5, 'Gold', 1, 'Ada'], [6, 'Kupfer', 4, 'Ines'], [7, 'Krypton', 4, 'Joe'], [8, 'Sauerstoff', 0, 'Marie'], [9, 'Zink', 5, 'Max'] ]; console.log( Utils.nameOf({ mixedArray }) ); })(); </script> // expected output: /* mixedArray */ |
3. Function
The example below demonstrates the use of ‘Utils.nameOf‘ to get the name of a function.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
// Function <script> (() => { // Function function multiplyFunction(x, y) { return x * y; } console.log( Utils.nameOf({ multiplyFunction }) ); })(); </script> // expected output: /* multiplyFunction */ |
4. Utils Namespace
The following is the Utils.js Namespace. Include this in your project to start using!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
// ============================================================================ // Author: Kenneth Perkins // Date: Oct 31, 2020 // Taken From: http://programmingnotes.org/ // File: Utils.js // Description: Javascript that handles general utility functions // ============================================================================ /** * NAMESPACE: Utils * USE: Handles general utility functions. */ var Utils = Utils || {}; (function(namespace) { 'use strict'; // Property to hold public variables and functions let exposed = namespace; /** * FUNCTION: nameOf * USE: Returns the name of a variable. * @param expression: An object containing the variable to get the name of. * @return: The name of a variable. */ exposed.nameOf = (expression) => { if (expression !== Object(expression) || typeof expression === 'function' || Array.isArray(expression)) { throw new Error(`Unable to determine name. '${expression}' is not an object`); } return Object.keys(expression)[0]; } (function (factory) { if (typeof define === 'function' && define.amd) { define([], factory); } else if (typeof exports === 'object') { module.exports = factory(); } }(function() { return namespace; })); }(Utils)); // http://programmingnotes.org/ |
QUICK NOTES:
The highlighted lines are sections of interest to look out for.
The code is heavily commented, so no further insight is necessary. If you have any questions, feel free to leave a comment below.