Skip to content

Commit

Permalink
Merge branch 'hibbitts-design:main' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
paulhibbitts authored Jun 21, 2024
2 parents 6152e44 + 27af92b commit f561948
Show file tree
Hide file tree
Showing 3 changed files with 109 additions and 20 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

**Improved:**
* Adjusted bottom margin for summary elements
* Improved Search plugin results list presentation, including source page title when appropriate

**Bugfix:**
* Check the global variable 'standalone' when setting externalLinkTarget
Expand Down
126 changes: 107 additions & 19 deletions docs/assets/js/search.js
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,65 @@
return keyword;
}

// Function to convert string to title case and replace hyphens with spaces
// This code was developed with the assistance of ChatGPT, an AI language model by OpenAI
function convertToTitle(str) {
return str
.split('-') // Split the string by hyphens
.map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()) // Capitalize the first letter and lower case the rest
.join(' '); // Join the words with spaces
}

// Function to strip common Markdown markup
// This code was developed with the assistance of ChatGPT, an AI language model by OpenAI
function stripCommonMarkdown(markdown) {
// Regular expressions for common Markdown elements
const regexes = [
{ pattern: /(\*\*|__)(.*?)\1/g, replacement: '$2' }, // Bold: **text** or __text__
{ pattern: /(\*|_)(.*?)\1/g, replacement: '$2' }, // Italic: *text* or _text_
{ pattern: /[-+*]\s+(.*?)/g, replacement: '$1' }, // Unordered lists: - item, + item, * item
{ pattern: /\d+\.\s+(.*?)/g, replacement: '$1' }, // Ordered lists: 1. item
{ pattern: /^#{1,6}\s+(.*)/gm, replacement: '$1' } // Headers: # Header, ## Header, etc.
];

// Apply all regular expressions to the input text
let plainText = markdown;
regexes.forEach(({ pattern, replacement }) => {
plainText = plainText.replace(pattern, replacement);
});

// Trim leading/trailing whitespace and return
return plainText.trim();
}

// Function to replace Markdown links with their titles and remove Markdown images
// This code was developed with the assistance of ChatGPT, an AI language model by OpenAI
function replaceMarkdownLinksWithTitlesandRemoveImages(content) {
// Regular expression to match both Markdown images and links
// Capture images separately to identify and remove them
const markdownLinkRegex = /(!?\[([^\]]+)\]\(([^)]+)\))/g;

return content.replace(markdownLinkRegex, (match, fullMatch, title, url) => {
// Check if it's an image link by the presence of '!' at the start
if (fullMatch.startsWith('!')) {
// Return an empty string to remove the image
return '';
}
// Otherwise, replace the link with its title
return title;
});
}

// Function to strip all HTML tags from a string
// This code was developed with the assistance of ChatGPT, an AI language model by OpenAI
function stripHtmlTags(content) {
// Regular expression to match HTML tags
const htmlTagRegex = /<[^>]*>/g;

// Replace all HTML tags with an empty string
return content.replace(htmlTagRegex, '');
}

/**
* @param {String} query Search query
* @returns {Array} Array of results
Expand All @@ -222,14 +281,16 @@
var handlePostTitle = '';
var handlePostContent = '';
var postTitle = post.title && post.title.trim();
var postContent = post.body && post.body.trim();
const postContent = stripHtmlTags(stripCommonMarkdown(replaceMarkdownLinksWithTitlesandRemoveImages(post.body && post.body.trim())));
var postUrl = post.slug || '';
const postPageSlug = postUrl.split('/')[1].split('?')[0].replace('0', '');
const postPageTitle = convertToTitle(postPageSlug);

// Skip posts that contain iframes, Font Awesome icons, embedly cards, or Markdown images
// Skip posts that contain iframes, Font Awesome icons, or embedly cards
// console.log(postContent);
var isImage = /!\[[^\]]*\]\([^)]*\)/g.test(postContent); // Check if it's a Markdown image
// const isImage = /!\[[^\]]*\]\([^)]*\)/g.test(postContent); // Check if it's a Markdown image

if (postContent.includes('iframe') || postContent.includes(':fas') || postContent.includes(':fab') || postContent.includes('embedly-card') || isImage) {
if (postContent.includes('iframe') || postContent.includes(':fas') || postContent.includes(':fab') || postContent.includes('embedly-card')) {
return;
}

Expand Down Expand Up @@ -270,26 +331,53 @@
if (postContent && end > postContent.length) {
end = postContent.length;
}

var matchContent =
handlePostContent &&
'...' +
handlePostContent
.substring(start, end)
.replace(
regEx,
function (word) { return ("<em class=\"search-keyword\">" + word + "</em>"); }
) +
'...';

resultStr += matchContent;

// This code was developed with the assistance of ChatGPT, an AI language model by OpenAI
const matchContent = handlePostContent && (() => {
// Extract the substring where the match will be applied
const contentSegment = handlePostContent.substring(start, end);

// Find the first occurrence of the word using the regular expression
const match = contentSegment.match(regEx);

if (match) {
// Get the position of the first match
const matchIndex = contentSegment.indexOf(match[0]);

// Split the content segment into before, match, and after parts
const beforeMatch = contentSegment.substring(0, matchIndex);
const firstMatch = contentSegment.substring(matchIndex, matchIndex + match[0].length);
const afterMatch = contentSegment.substring(matchIndex + match[0].length);

// Return the reassembled string with the first match wrapped in <em> tags
return '...' +
beforeMatch +
`<em class="search-keyword">${firstMatch}</em>` +
afterMatch +
'...';
}

// If no match is found, return the original segment surrounded by ellipses
return '...' + contentSegment + '...';
})();

resultStr += matchContent;
}
});

// This code was developed with the assistance of ChatGPT, an AI language model by OpenAI
// Only prepend postPageTitle when it is not empty and not equal to handlePostTitle (case insensitive)
if (matchesScore > 0) {
var matchingPost = {
const matchingPost = {
title: handlePostTitle,
content: postContent ? resultStr : '',
content: (
// Convert both postPageTitle and handlePostTitle to lowercase for case-insensitive comparison
postPageTitle &&
postPageTitle.toLowerCase() !== handlePostTitle.toLowerCase() &&
postPageTitle.toLowerCase() !== 'readme' // Exclude 'ReadMe' from being prepended
? `<strong>${postPageTitle}</strong><br>`
: ''
) + (postContent ? resultStr : ''),
url: postUrl,
score: matchesScore,
};
Expand Down
Loading

0 comments on commit f561948

Please sign in to comment.