Last active
September 17, 2019 16:16
-
-
Save ninapavlich/8c680361667f17717951f207f16a553c to your computer and use it in GitHub Desktop.
Edit Parenting Item
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
javascript: (async function() { | |
var bookmarkletVersion = "1.0.0"; | |
var apiRoot = "https://parenting.nytimes.com/api/v1"; | |
var cmsRoot = "https://nyt-parentingcms-prd.appspot.com"; | |
console.log("Running Parenting Edit Bookmarlet v" + bookmarkletVersion); | |
/* | |
Generic function for requesting URLs | |
*/ | |
async function makeRequest(method, url) { | |
console.log(method + ":" + url); | |
return new Promise(function(resolve, reject) { | |
let xhr = new XMLHttpRequest(); | |
xhr.open(method, url); | |
xhr.onload = function() { | |
if (this.status >= 200 && this.status < 300) { | |
resolve({ | |
success: true, | |
status: this.status, | |
statusText: xhr.statusText, | |
data: JSON.parse(xhr.response) | |
}); | |
} else { | |
resolve({ | |
success: false, | |
status: this.status, | |
statusText: xhr.statusText | |
}); | |
} | |
}; | |
xhr.onerror = function() { | |
resolve({ | |
success: false, | |
status: this.status, | |
statusText: xhr.statusText | |
}); | |
}; | |
xhr.send(); | |
}); | |
} | |
/* | |
Given a URL path, determine the corresponding admin URL | |
*/ | |
async function getAdminURL(path) { | |
/*const admin_type_paths = { | |
ARTICLE: "/admin/scoop-content/", | |
ESSAY: "/admin/scoop-content/", | |
MILESTONE: "/admin/scoop-content/", | |
LIST: "/admin/scoop-content/", | |
GUIDE: "/admin/guides/", | |
CHILD: "/admin/topics/", | |
PARENT: "/admin/topics/", | |
STAGE: "/admin/topics/", | |
SERIES: "/admin/collections/" | |
};*/ | |
let pathPieces = path.replace(/^\/|\/$/g, "").split("/"); | |
let testAPIURL; | |
if (path.indexOf("archive") >= 0 && pathPieces.length === 3) { | |
/* its a topic */ | |
testAPIURL = "/topics/" + pathPieces[1]; | |
} else if (pathPieces.length == 1) { | |
/* It might be a topic... if not it's a page */ | |
testAPIURL = "/topics/" + pathPieces[0]; | |
} else if (path.indexOf("series") >= 0 && pathPieces.length === 2) { | |
/* its a collection - TODO -- make this not hardcoded */ | |
testAPIURL = "/collections/" + pathPieces[1]; | |
} else if (pathPieces.length == 2) { | |
/* It's either a guide or a story or a collection */ | |
testAPIURL = "/stories/" + pathPieces[1]; | |
} | |
let responseData = await makeRequest("GET", apiRoot + testAPIURL); | |
if (responseData.success) { | |
if (responseData.data.data.topic) { | |
return cmsRoot + "/admin/topics/" + responseData.data.data.topic.id; | |
} else if (responseData.data.data.story) { | |
if (responseData.data.data.story.type === "GUIDE") { | |
return cmsRoot + "/admin/guides/" + responseData.data.data.story.id; | |
} else { | |
return ( | |
cmsRoot + "/admin/scoop-content/" + responseData.data.data.story.id | |
); | |
} | |
} else if (responseData.data.data.collection) { | |
return ( | |
cmsRoot + "/admin/collections/" + responseData.data.data.collection.id | |
); | |
} | |
} else { | |
return null; | |
} | |
} | |
/* | |
Given a URL, return the path portion | |
*/ | |
function getPath(url) { | |
if (url === null) { | |
return null; | |
} | |
var link = document.createElement("a"); | |
link.href = url; | |
return link.pathname; | |
} | |
/* | |
Given a clicked target, work up the element tree until we find an item | |
with an href | |
*/ | |
function getLinkFromTarget(element) { | |
if (element.href) { | |
return element.href; | |
} else if (element.parentElement) { | |
return getLinkFromTarget(element.parentElement); | |
} | |
return null; | |
} | |
/* | |
If the window has already been opened, switch to that tab. | |
Otherwise open a new window with the admin link | |
*/ | |
function openAdminWindow(adminLink) { | |
if ( | |
!window.opened_windows[adminLink] || | |
window.opened_windows[adminLink].closed | |
) { | |
var win = window.open(adminLink, "_blank"); | |
window.opened_windows[adminLink] = win; | |
} | |
window.opened_windows[adminLink].focus(); | |
} | |
/* | |
If we are in edit mode: | |
- get the link path | |
- determine the corresponding admin link | |
- open or focus that link | |
*/ | |
async function handleLinkClick(event) { | |
if (!document.body.classList.contains("editing")) { | |
return; | |
} | |
const path = getPath(getLinkFromTarget(event.target)); | |
if (path) { | |
event.preventDefault(); | |
let adminLink = await getAdminURL(path); | |
if (adminLink) { | |
openAdminWindow(adminLink); | |
} else { | |
alert("Couldn't find edit link for " + path); | |
} | |
} | |
} | |
/* | |
Turn On Edit Mode: | |
Add "editing" class to body | |
Get All Links on the Page: | |
- If a link is in the sitemap: | |
--- add the class "editable" | |
--- add a click listener (only do that once though) | |
*/ | |
function turnOnEditMode() { | |
console.log("-- Turn On Edit Bookmarlet"); | |
document.body.classList.add("editing"); | |
for (var i = 0; i < document.links.length; i++) { | |
var link = document.links[i]; | |
if (window.sitemap_links.indexOf(link.pathname)) { | |
link.classList.add("editable"); | |
if (!link.classList.contains("editable-inited")) { | |
link.classList.add("editable-inited"); | |
link.addEventListener("click", handleLinkClick); | |
} | |
} | |
} | |
var pageLink = document.getElementById("editPageLink"); | |
if (!pageLink) { | |
pageLink = document.createElement("a"); | |
pageLink.id = "editPageLink"; | |
pageLink.innerHTML = "EDIT<br />THIS PAGE"; | |
pageLink.addEventListener("click", handleLinkClick); | |
document.body.appendChild(pageLink); | |
} | |
pageLink.setAttribute("href", window.location.href); | |
} | |
/* | |
Turn Off Edit Mode: | |
Remove "editing" class from body | |
*/ | |
function turnOffEditMode() { | |
console.log("-- Turn Off Edit Bookmarlet"); | |
document.body.classList.remove("editing"); | |
} | |
if (!window.edit_bookmarklet_inited) { | |
/* | |
If not inited, INIT: | |
- Load sitemap | |
- Add dynamic styles to page | |
*/ | |
const sitemapResponse = await makeRequest("GET", apiRoot + "/sitemap"); | |
console.log("-- Sitemap loaded: " + sitemapResponse.success); | |
if (sitemapResponse.success) { | |
window.sitemap_links = sitemapResponse.data.data.map(function callback( | |
currentValue | |
) { | |
return getPath(currentValue.loc); | |
}); | |
} else { | |
window.sitemap_links = []; | |
} | |
var style = document.createElement("style"); | |
var styleContent = document.createTextNode( | |
` | |
.editing:before{ | |
content: "EDIT\\AMODE ON"; | |
white-space: pre-wrap; | |
text-align: center; | |
position: fixed; | |
top: 0; | |
left: 0; | |
font-family: monospace; | |
z-index: 10000; | |
background: #d35f0ae0; | |
color: #fff; | |
padding: 1em; | |
padding: 4em 4em 1em 4em; | |
transform: rotate(-45deg) translate(-21px, -69px); | |
} | |
.editing #editPageLink{ | |
position: fixed; | |
top: 0; | |
right: 0; | |
font-family: monospace; | |
z-index: 10000; | |
background: #d35f0ae0; | |
color: #fff; | |
padding: 1em; | |
text-align: center; | |
padding: 5em 5em 1em 5em; | |
transform: rotate(45deg) translate(28px, -90px); | |
text-decoration:none; | |
display:none; | |
} | |
.editing #editPageLink{ | |
display:block; | |
} | |
.editing .editable:hover{ | |
cursor: url("data:image/svg+xml,%3Csvg version='1.1' id='Layer_1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' width='32px' height='32px' viewBox='0 0 512 512' style='enable-background:new 0 0 512 512;' xml:space='preserve'%3E %3Cpath d='M497.9 142.1l-46.1 46.1c-4.7 4.7-12.3 4.7-17 0l-111-111c-4.7-4.7-4.7-12.3 0-17l46.1-46.1c18.7-18.7 49.1-18.7 67.9 0l60.1 60.1c18.8 18.7 18.8 49.1 0 67.9zM284.2 99.8L21.6 362.4.4 483.9c-2.9 16.4 11.4 30.6 27.8 27.8l121.5-21.3 262.6-262.6c4.7-4.7 4.7-12.3 0-17l-111-111c-4.8-4.7-12.4-4.7-17.1 0zM124.1 339.9c-5.5-5.5-5.5-14.3 0-19.8l154-154c5.5-5.5 14.3-5.5 19.8 0s5.5 14.3 0 19.8l-154 154c-5.5 5.5-14.3 5.5-19.8 0zM88 424h48v36.3l-64.5 11.3-31.1-31.1L51.7 376H88v48z'/%3E %3C/svg%3E") 0 50, auto; | |
} | |
` | |
); | |
style.appendChild(styleContent); | |
var caput = document.getElementsByTagName("head"); | |
caput[0].appendChild(style); | |
window.opened_windows = {}; | |
window.edit_bookmarklet_inited = true; | |
console.log("-- Edit Bookmarlet inited..."); | |
} | |
/* | |
Toggle Edit Mode: | |
- Determine if edit mode is on or off and toggle it | |
*/ | |
if (document.body.classList.contains("editing")) { | |
turnOffEditMode(); | |
} else { | |
turnOnEditMode(); | |
} | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment