Skip to content

Commit

Permalink
Further fixes to material-dashboard.js and other minor fixes (#46)
Browse files Browse the repository at this point in the history
    Adding selects as elements to be added onkeyup, focus and focusout listeners, alongside inputs
    Adding a Mutation Observer to check for new elements being added to the DOM and if they are select, input or .btn, re-execute onWindowLoadFunction to attach the listeners
    Adding an if condition to each listener so we don't attach them twice to those elements.
    Some other minor fixes
  • Loading branch information
lotif authored May 23, 2024
1 parent 5b64bd9 commit 8483f52
Show file tree
Hide file tree
Showing 5 changed files with 105 additions and 57 deletions.
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ brew install yarn

Then install the project dependencies in development mode:
```shell
yarn
yarn -D
```

Install Redis by following [these instructions](README.md#pulling-redis-docker).
Expand Down
145 changes: 96 additions & 49 deletions florist/app/assets/js/material-dashboard.js
Original file line number Diff line number Diff line change
Expand Up @@ -592,72 +592,119 @@ function getEventTarget(e) {
// End tabs navigation
function onWindowLoadFunction() {
// Material Design Input function
var inputs = document.querySelectorAll("input");
const textFields = document.querySelectorAll("input");
const selects = document.querySelectorAll("select");
const allResults = [textFields, selects];

for (var i = 0; i < inputs.length; i++) {
inputs[i].addEventListener(
"focus",
function (e) {
this.parentElement.classList.add("is-focused");
this.parentElement.classList.add("focused");
},
false,
);
const inputs = [];
for (var i = 0; i < allResults.length; i++) {
for (var j = 0; j < allResults[i].length; j++) {
inputs.push(allResults[i][j]);
}
}

inputs[i].onkeyup = function (e) {
if (this.value != "") {
this.parentElement.classList.add("is-filled");
} else {
this.parentElement.classList.remove("is-filled");
}
};
for (var i = 0; i < inputs.length; i++) {
if (inputs[i].getAttribute("hasFocusListener") !== "true") {
inputs[i].addEventListener(
"focus",
function (e) {
this.parentElement.classList.add("is-focused");
this.parentElement.classList.add("focused");
},
false,
);
inputs[i].setAttribute("hasFocusListener", "true");
}

inputs[i].addEventListener(
"focusout",
function (e) {
if (inputs[i].getAttribute("hasOnKeyUp") !== "true") {
inputs[i].onkeyup = function (e) {
if (this.value != "") {
this.parentElement.classList.add("is-filled");
} else {
this.parentElement.classList.remove("is-filled");
}
this.parentElement.classList.remove("is-focused");
this.parentElement.classList.remove("focused");
},
false,
);
};
inputs[i].setAttribute("hasOnKeyUp", "true");
}

if (inputs[i].getAttribute("hasFocusOutListener") !== "true") {
inputs[i].addEventListener(
"focusout",
function (e) {
if (this.value != "") {
this.parentElement.classList.add("is-filled");
}
this.parentElement.classList.remove("is-focused");
this.parentElement.classList.remove("focused");
},
false,
);
inputs[i].setAttribute("hasFocusOutListener", "true");
}
}

// Ripple Effect
var ripples = document.querySelectorAll(".btn");

for (var i = 0; i < ripples.length; i++) {
ripples[i].addEventListener(
"click",
function (e) {
var targetEl = e.target;
var rippleDiv = targetEl.querySelector(".ripple");

rippleDiv = document.createElement("span");
rippleDiv.classList.add("ripple");
rippleDiv.style.width = rippleDiv.style.height =
Math.max(targetEl.offsetWidth, targetEl.offsetHeight) +
"px";
targetEl.appendChild(rippleDiv);

rippleDiv.style.left =
e.offsetX - rippleDiv.offsetWidth / 2 + "px";
rippleDiv.style.top =
e.offsetY - rippleDiv.offsetHeight / 2 + "px";
rippleDiv.classList.add("ripple");
setTimeout(function () {
rippleDiv.parentElement.removeChild(rippleDiv);
}, 600);
},
false,
);
if (ripples[i].getAttribute("hasClickListener") !== "true") {
ripples[i].addEventListener(
"click",
function (e) {
var targetEl = e.target;
var rippleDiv = targetEl.querySelector(".ripple");

rippleDiv = document.createElement("span");
rippleDiv.classList.add("ripple");
rippleDiv.style.width = rippleDiv.style.height =
Math.max(targetEl.offsetWidth, targetEl.offsetHeight) +
"px";
targetEl.appendChild(rippleDiv);

rippleDiv.style.left =
e.offsetX - rippleDiv.offsetWidth / 2 + "px";
rippleDiv.style.top =
e.offsetY - rippleDiv.offsetHeight / 2 + "px";
rippleDiv.classList.add("ripple");
setTimeout(function () {
rippleDiv.parentElement.removeChild(rippleDiv);
}, 600);
},
false,
);
}
ripples[i].setAttribute("hasClickListener", "true");
}
}

onWindowLoadFunction();

const observer = new MutationObserver((mutationList) => {
var hasTargetElementTypes = false;

// Check if any select, input or .btn has been added to the DOM
for (var i = 0; i < mutationList.length; i++) {
if (mutationList[i].type === "childList") {
for (var j = 0; j < mutationList[i].addedNodes.length; j++) {
const addedNode = mutationList[i].addedNodes[j];
const inputs = addedNode.querySelectorAll("select");
const selects = addedNode.querySelectorAll("input");
const btns = addedNode.querySelectorAll(".btn");

hasTargetElementTypes =
inputs.length > 0 || selects.length > 0 || btns.length > 0;
}
}
}

// If so, execute the onWindowLoadFunction to attach listeners
// to those new elements
if (hasTargetElementTypes) {
onWindowLoadFunction();
}
});
observer.observe(document, { childList: true, subtree: true });

// Toggle Sidenav
const iconNavbarSidenav = document.getElementById("iconNavbarSidenav");
const iconSidenav = document.getElementById("iconSidenav");
Expand Down
2 changes: 1 addition & 1 deletion florist/app/jobs/hooks.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import useSWR from "swr";
import { fetcher } from "../client_imports";

export default function useGetJobsByJobStatus(status: string) {
export function useGetJobsByJobStatus(status: string) {
const endpoint = "/api/server/job/".concat(status);
const { data, error, isLoading } = useSWR(endpoint, fetcher, {
refresh_interval: 1000,
Expand Down
7 changes: 4 additions & 3 deletions florist/app/jobs/page.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
"use client";

import { ReactElement } from "react/React";
import useGetJobsByStatus from "./hooks";
import useGetJobsByJobStatus from "./hooks";

import { useGetJobsByJobStatus } from "./hooks";

export const validStatuses = {
NOT_STARTED: "Not Started",
Expand Down Expand Up @@ -38,7 +39,7 @@ export default function Page(): ReactElement {
));
return (
<div className="mx-4">
<h1> Job Status </h1>
<h1> Jobs By Status </h1>
{statusComponents}
</div>
);
Expand Down
6 changes: 3 additions & 3 deletions florist/tests/unit/app/jobs/page.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { getByText, render, cleanup } from "@testing-library/react";
import { describe, afterEach, it, expect } from "@jest/globals";

import Page, { validStatuses } from "../../../../app/jobs/page";
import useGetJobsByStatus from "../../../../app/jobs/hooks";
import { useGetJobsByJobStatus } from "../../../../app/jobs/hooks";

jest.mock("../../../../app/jobs/hooks");

Expand Down Expand Up @@ -33,7 +33,7 @@ function setupMock(
error: boolean,
isLoading: boolean,
) {
useGetJobsByStatus.mockImplementation((status: string) => {
useGetJobsByJobStatus.mockImplementation((status: string) => {
if (validStatuses.includes(status)) {
return {
data,
Expand All @@ -56,7 +56,7 @@ describe("List Jobs Page", () => {
const { container } = render(<Page />);
const h1 = container.querySelector("h1");
expect(h1).toBeInTheDocument();
expect(h1).toHaveTextContent("Job Status");
expect(h1).toHaveTextContent("Jobs By Status");
});

it("Renders Status Components Headers", () => {
Expand Down

0 comments on commit 8483f52

Please sign in to comment.