jenkins-bot has submitted this change and it was merged. ( 
https://gerrit.wikimedia.org/r/392570 )

Change subject: Update: capture wiki link clicks and navigation
......................................................................


Update: capture wiki link clicks and navigation

Extract Link.onClick to link/click#onClick and use in ContentSection
so that internal clicks on content are routed internally instead of
triggering a full page reload.

Additional changes:
* Moved Link to link/
* Added the feature so that the onClick handler works when set on
  containers

Bug: T177367
Change-Id: I5175d9473c128fce87820e9d11788db7b4dd6df1
---
M src/common/components/content-section/content-section.tsx
M src/common/components/header/header.tsx
D src/common/components/link.tsx
A src/common/components/link/link.tsx
A src/common/components/link/on-click.ts
M src/common/components/thumbnail/thumbnail.tsx
M src/common/pages/about.tsx
M src/common/pages/home.tsx
8 files changed, 90 insertions(+), 65 deletions(-)

Approvals:
  Jhernandez: Looks good to me, approved
  jenkins-bot: Verified



diff --git a/src/common/components/content-section/content-section.tsx 
b/src/common/components/content-section/content-section.tsx
index a87ad83..e68912e 100644
--- a/src/common/components/content-section/content-section.tsx
+++ b/src/common/components/content-section/content-section.tsx
@@ -1,16 +1,25 @@
+import { History } from "history";
 import { h } from "preact";
 import { PageSection } from "../../models/page/page";
 import Content from "../content/content";
 import DynamicHeader from "../dynamic-header/dynamic-header";
+import { onClick } from "../link/on-click";
 import "./content-section.css";
 
 export interface Props {
   section: PageSection;
 }
 
-export default function ContentSection({ section }: Props): JSX.Element {
+export default function ContentSection(
+  { section }: Props,
+  context: { history?: History }
+): JSX.Element {
   return (
-    <section class="ContentSection" id={section.fragment}>
+    <section
+      onClick={event => onClick(context, event)}
+      class="ContentSection"
+      id={section.fragment}
+    >
       {section.titleHTML && ( // Omit empty headers such as the lead.
         <DynamicHeader class="ContentSection-header" level={section.level + 1}>
           <Content dangerouslySetInnerHTML={{ __html: section.titleHTML }} />
diff --git a/src/common/components/header/header.tsx 
b/src/common/components/header/header.tsx
index 199d143..979eb96 100644
--- a/src/common/components/header/header.tsx
+++ b/src/common/components/header/header.tsx
@@ -1,6 +1,6 @@
 import { h } from "preact";
 import Wordmark from "../wordmark/wordmark";
-import Link from "../link";
+import Link from "../link/link";
 import { home } from "../../routers/api";
 
 import "./header.css";
diff --git a/src/common/components/link.tsx b/src/common/components/link.tsx
deleted file mode 100644
index 75ec31c..0000000
--- a/src/common/components/link.tsx
+++ /dev/null
@@ -1,59 +0,0 @@
-import { h } from "preact";
-import { History } from "history";
-import { ChildrenProps, classOf, ClassProps } from "./preact-utils";
-
-export interface Props extends ClassProps, ChildrenProps {
-  href: string;
-}
-
-function isModifiedEvent(event: MouseEvent): boolean {
-  return event.metaKey || event.altKey || event.ctrlKey || event.shiftKey;
-}
-
-/**
- * A single page app link that intercepts navigation (click) events and passes
- * control to History. All hyperlinks should use a Link component.
- */
-export default function Link(
-  { href, children, ...props }: Props,
-  context: { history?: History }
-): JSX.Element {
-  return (
-    <a
-      class={classOf("Link", props.class)}
-      href={href}
-      onClick={event => {
-        const origin = window.location.origin;
-        // Use currentTarget as target may be other DOM elements inside the
-        // anchor element
-        const link = event.currentTarget as HTMLAnchorElement;
-        // TODO: Move all the logic to check if an event should be captured to 
a
-        // DOM utilities module and add unit tests
-        if (
-          // Check if the href is internal
-          //
-          // N.B. link.href is used because browsers will transform relative
-          // paths to the full path when set on the HTML anchor, which is what
-          // is used to check against the current origin
-          link.href &&
-          link.href.indexOf(origin) === 0 &&
-          // onClick not prevented default
-          !event.defaultPrevented &&
-          // Ignore everything but left clicks
-          event.button === 0 &&
-          // Let browser handle "target=_blank" etc.
-          !link.target &&
-          // Ignore clicks with modifier keys
-          !isModifiedEvent(event) &&
-          // We have a context history
-          context.history
-        ) {
-          event.preventDefault();
-          context.history.push(href);
-        }
-      }}
-    >
-      {children}
-    </a>
-  );
-}
diff --git a/src/common/components/link/link.tsx 
b/src/common/components/link/link.tsx
new file mode 100644
index 0000000..ea064f3
--- /dev/null
+++ b/src/common/components/link/link.tsx
@@ -0,0 +1,27 @@
+import { History } from "history";
+import { h } from "preact";
+import { ChildrenProps, classOf, ClassProps } from "../preact-utils";
+import { onClick } from "./on-click";
+
+export interface Props extends ClassProps, ChildrenProps {
+  href: string;
+}
+
+/**
+ * A single page app link that intercepts navigation (click) events and passes
+ * control to History. All hyperlinks should use a Link component.
+ */
+export default function Link(
+  { href, children, ...props }: Props,
+  context: { history?: History }
+): JSX.Element {
+  return (
+    <a
+      class={classOf("Link", props.class)}
+      href={href}
+      onClick={event => onClick(context, event)}
+    >
+      {children}
+    </a>
+  );
+}
diff --git a/src/common/components/link/on-click.ts 
b/src/common/components/link/on-click.ts
new file mode 100644
index 0000000..21f827b
--- /dev/null
+++ b/src/common/components/link/on-click.ts
@@ -0,0 +1,48 @@
+import { History } from "history";
+
+function isModifiedEvent(event: MouseEvent): boolean {
+  return event.metaKey || event.altKey || event.ctrlKey || event.shiftKey;
+}
+
+function isInternalLink(link: HTMLAnchorElement) {
+  // N.B. link.href is used because browsers will transform relative paths to
+  // the full path when set on the HTML anchor, which is what is used to check
+  // against the current origin.
+  return link.href && link.href.indexOf(window.location.origin) === 0;
+}
+
+// TODO: add unit tests
+export function onClick(
+  context: { history?: History },
+  event: MouseEvent
+): void {
+  let link = null;
+  if (event.currentTarget instanceof HTMLAnchorElement) {
+    // When set on an anchor, currentTarget is the anchor
+    link = event.currentTarget;
+  } else if (event.target instanceof HTMLAnchorElement) {
+    // When set on a parent to capture all clicks, currentTarget may be
+    // something else. Use target if it is a link, as the handler triggers on
+    // the bubbling phase
+    link = event.target;
+  }
+
+  if (
+    link &&
+    isInternalLink(link) &&
+    // onClick not prevented default
+    !event.defaultPrevented &&
+    // Ignore everything but left clicks
+    event.button === 0 &&
+    // Let browser handle "target=_blank" etc.
+    !link.target &&
+    // Ignore clicks with modifier keys
+    !isModifiedEvent(event) &&
+    // We have a context history
+    context.history
+  ) {
+    event.preventDefault();
+    const path = link.href.replace(window.location.origin, "");
+    context.history.push(path);
+  }
+}
diff --git a/src/common/components/thumbnail/thumbnail.tsx 
b/src/common/components/thumbnail/thumbnail.tsx
index 64dd7a2..8b29c93 100644
--- a/src/common/components/thumbnail/thumbnail.tsx
+++ b/src/common/components/thumbnail/thumbnail.tsx
@@ -1,6 +1,6 @@
 import { h } from "preact";
 import { ClassProps, classOf } from "../preact-utils";
-import Link from "../link";
+import Link from "../link/link";
 import { PageImage } from "../../models/page/image";
 import "./thumbnail.css";
 
diff --git a/src/common/pages/about.tsx b/src/common/pages/about.tsx
index 33a3ba9..24b7440 100644
--- a/src/common/pages/about.tsx
+++ b/src/common/pages/about.tsx
@@ -1,6 +1,6 @@
 import { h, Component as PreactComponent } from "preact";
 import App from "../components/app/app";
-import Link from "../components/link";
+import Link from "../components/link/link";
 import Page from "../components/page/page";
 
 // Fake a type declaration for the global variable VERSION that will be 
replaced
diff --git a/src/common/pages/home.tsx b/src/common/pages/home.tsx
index 20b1a64..3a18729 100644
--- a/src/common/pages/home.tsx
+++ b/src/common/pages/home.tsx
@@ -11,7 +11,7 @@
 } from "../../common/routers/api";
 import Page from "../components/page/page";
 import { PageTitleID } from "../models/page/title";
-import Link from "../components/link";
+import Link from "../components/link/link";
 
 const testSummaries = [
   {

-- 
To view, visit https://gerrit.wikimedia.org/r/392570
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: merged
Gerrit-Change-Id: I5175d9473c128fce87820e9d11788db7b4dd6df1
Gerrit-PatchSet: 3
Gerrit-Project: marvin
Gerrit-Branch: master
Gerrit-Owner: Niedzielski <[email protected]>
Gerrit-Reviewer: Jhernandez <[email protected]>
Gerrit-Reviewer: Sniedzielski <[email protected]>
Gerrit-Reviewer: jenkins-bot <>

_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to