Skip to content

Commit

Permalink
Implement editable placeholders (#13)
Browse files Browse the repository at this point in the history
  • Loading branch information
JakeSCahill authored Apr 5, 2023
1 parent daf61e5 commit 9460939
Show file tree
Hide file tree
Showing 6 changed files with 213 additions and 104 deletions.
24 changes: 24 additions & 0 deletions src/css/editable-placeholders.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
span.editable,
span.editable > span {
font-weight: bold;
color: var(--link-font-color);
}

span.cursor::after,
span.cursor > span::after {
content: "|";
display: inline-block;
animation: cursor-blink 1.2s infinite;
font-weight: 100;
color: var(--link-font-color);
}

@keyframes cursor-blink {
from {
opacity: 1;
}

to {
opacity: 0;
}
}
1 change: 1 addition & 0 deletions src/css/site.css
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,4 @@
@import "print.css";
@import "search.css";
@import "banners.css";
@import "editable-placeholders.css";
31 changes: 31 additions & 0 deletions src/partials/docsearch-script.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<script src="https://cdn.jsdelivr.net/npm/@docsearch/js@3"></script>
<script>
docsearch({
container: '#search-field',
appId: '{{{env.ALGOLIA_APP_ID}}}',
indexName: '{{{env.ALGOLIA_INDEX_NAME}}}',
apiKey: '{{{env.ALGOLIA_API_KEY}}}',
getMissingResultsUrl({ query }) {
return `https://github.com/JakeSCahill/redpanda-docs-antora/issues/new?title=${query}`;
},
resultsFooterComponent({ state }) {
return {
// The HTML `tag`
type: 'a',
ref: undefined,
constructor: undefined,
key: state.query,
// Its props
props: {
href: `/search.html?q=${state.query}`,
/*onClick: (event) => {
console.log(JSON.stringify(state,null,2));
},*/
// Raw text rendered in the HTML element
children: `See all ${state.context.nbHits} results`,
},
__v: null,
};
},
});
</script>
82 changes: 82 additions & 0 deletions src/partials/editable-placeholders-script.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
<script>
function createEditablePlaceholders () {
const codeElements = document.querySelectorAll("pre > code");
for (let i = 0; i < codeElements.length; i++) {
const codeElement = codeElements[i];
searchForPlaceholders(codeElement);
}
}
function searchForPlaceholders(element) {
if (element.textContent.match(/<[^>A-Z]*>/)){
addEditableSpan(element)
}
}
function addEditableSpan(element) {
if (!element || !element.textContent) {
return;
}
const html = element.innerHTML;
const regex = /&lt;(?:<[^>]+>)?([a-z-]+)(?:<[^>]+>)?&gt;/g;
const newHtml = html.replace(regex, '<span contenteditable="true" data-type="$1" onclick="removeCursor(event)">&lt;$1&gt;</span><span class="cursor"></span>');
element.innerHTML = newHtml;
}
function removeCursor (element) {
if (element.target) {
element = element.target
}
if (element.contentEditable == 'true') {
element.nextElementSibling.classList.remove('cursor');
} else {
element.parentElement.nextElementSibling.classList.remove('cursor');
}
}
function addClasses () {
const editablePlaceholders = document.querySelectorAll('[contenteditable="true"], [contenteditable="true"] span');
editablePlaceholders.forEach((placeholder) => {
placeholder.classList.add('editable');
placeholder.addEventListener('input', function(event) {
console.log(event.target.textContent)
const dataType = event.target.dataset.type;
const newText = event.target.textContent;
document.querySelectorAll(`[data-type="${dataType}"][contenteditable="true"]`).forEach(span => {
if (span !== event.target) {
span.textContent = newText;
}
});
});
});
}
document.addEventListener('DOMContentLoaded', function() {
try {
createEditablePlaceholders();
addClasses()
} catch (error) {
console.error('An error occurred while making placeholders editable:', error);
}
});
window.onload = function() {
const editablePlaceholders = document.querySelectorAll('[contenteditable="true"], [contenteditable="true"] span');
editablePlaceholders.forEach((placeholder) => {
placeholder.addEventListener('input', function(event) {
const dataType = event.target.dataset.type;
const newText = event.target.textContent;
document.querySelectorAll(`[data-type="${dataType}"][contenteditable="true"]`).forEach(span => {
if (span !== event.target) {
span.textContent = newText;
removeCursor(span)
}
});
});
});
};
</script>
72 changes: 72 additions & 0 deletions src/partials/feedback-form-script.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
<script>
const thumbs = document.querySelectorAll('.thumb');
const positiveModal = document.getElementById('positive');
const negativeModal = document.getElementById('negative');
var currentForm;
thumbs.forEach(function(thumb) {
thumb.addEventListener('click', function() {
if (thumb.id.indexOf('up') !== -1) {
positiveModal.classList.toggle("hidden");
currentForm = positiveModal
} else if (thumb.id.indexOf('down') !== -1) {
negativeModal.classList.toggle("hidden");
currentForm = negativeModal
}
});
});
const handleSubmit = function (e) {
e.preventDefault();
const currentUrl = '{{{ or site.url siteRootPath }}}{{{ page.url }}}'
const beta = {{ is-beta page }}
const version = {{ page.attributes.version }}
const form = event.target;
var formData = new FormData(form);
formData.set('version', version)
formData.set('url', currentUrl)
formData.set('beta', beta)
const formFields = e.target.closest('form')
const feedback = formFields.querySelector('input[name="feedback"]:checked').value
formData.set('positiveFeedback', feedback)
formData.set('otherText', (form.querySelector('textarea[name="otherText"]').value))
formData.set('email', (form.querySelector('input[name="email"]').value))
formData.set('date', new Date().toISOString())
formData.set('navigator', JSON.stringify({
appName: window.navigator.appName,
appVersion: window.navigator.appVersion,
platform: window.navigator.platform,
userAgent: window.navigator.userAgent,
language: window.navigator.language
}))
fetch("/", {
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body: new URLSearchParams(formData).toString(),
}).then(() => {
console.log('Form submission success')
clearFeedbackModal()
})
.catch(error => {
console.error('Form submission error:', error)
})
}
function clearFeedbackModal() {
var modalBody = currentForm.querySelector('.feedback-modal-body');
modalBody.innerHTML = `
{{> feedback-success-modal}}
`;
}
function closeForm(e) {
e.preventDefault()
currentForm.classList.toggle("hidden");
}
</script>
107 changes: 3 additions & 104 deletions src/partials/footer-scripts.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -2,110 +2,9 @@
<script async src="{{{uiRootPath}}}/js/vendor/highlight.js"></script>
<script async src="{{{uiRootPath}}}/js/vendor/tabs.js" data-sync-storage-key="preferred-tab"></script>
{{#if env.ALGOLIA_API_KEY}}
<script src="https://cdn.jsdelivr.net/npm/@docsearch/js@3"></script>
<script>
docsearch({
container: '#search-field',
appId: '{{{env.ALGOLIA_APP_ID}}}',
indexName: '{{{env.ALGOLIA_INDEX_NAME}}}',
apiKey: '{{{env.ALGOLIA_API_KEY}}}',
getMissingResultsUrl({ query }) {
return `https://github.com/JakeSCahill/redpanda-docs-antora/issues/new?title=${query}`;
},
resultsFooterComponent({ state }) {
return {
// The HTML `tag`
type: 'a',
ref: undefined,
constructor: undefined,
key: state.query,
// Its props
props: {
href: `/search.html?q=${state.query}`,
/*onClick: (event) => {
console.log(JSON.stringify(state,null,2));
},*/
// Raw text rendered in the HTML element
children: `See all ${state.context.nbHits} results`,
},
__v: null,
};
},
});
</script>
{{> docsearch-script}}
{{/if}}
{{#if page.version }}
<script>
const thumbs = document.querySelectorAll('.thumb');
const positiveModal = document.getElementById('positive');
const negativeModal = document.getElementById('negative');
var currentForm;
thumbs.forEach(function(thumb) {
thumb.addEventListener('click', function() {
if (thumb.id.indexOf('up') !== -1) {
positiveModal.classList.toggle("hidden");
currentForm = positiveModal
} else if (thumb.id.indexOf('down') !== -1) {
negativeModal.classList.toggle("hidden");
currentForm = negativeModal
}
});
});
</script>
<script>
const handleSubmit = function (e) {
e.preventDefault();
const currentUrl = '{{{ or site.url siteRootPath }}}{{{ page.url }}}'
const beta = {{ is-beta page }}
const version = {{ page.attributes.version }}
const form = event.target;
var formData = new FormData(form);
formData.set('version', version)
formData.set('url', currentUrl)
formData.set('beta', beta)
const formFields = e.target.closest('form')
const feedback = formFields.querySelector('input[name="feedback"]:checked').value
formData.set('positiveFeedback', feedback)
formData.set('otherText', (form.querySelector('textarea[name="otherText"]').value))
formData.set('email', (form.querySelector('input[name="email"]').value))
formData.set('date', new Date().toISOString())
formData.set('navigator', JSON.stringify({
appName: window.navigator.appName,
appVersion: window.navigator.appVersion,
platform: window.navigator.platform,
userAgent: window.navigator.userAgent,
language: window.navigator.language
}))
fetch("/", {
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body: new URLSearchParams(formData).toString(),
}).then(() => {
console.log('Form submission success')
clearFeedbackModal()
})
.catch(error => {
console.error('Form submission error:', error)
})
}
function clearFeedbackModal() {
var modalBody = currentForm.querySelector('.feedback-modal-body');
modalBody.innerHTML = `
{{> feedback-success-modal}}
`;
}
function closeForm(e) {
e.preventDefault()
currentForm.classList.toggle("hidden");
}
</script>
{{> feedback-form-script}}
{{> editable-placeholders-script}}
{{/if}}

0 comments on commit 9460939

Please sign in to comment.