Files
skill-lib/skills/zhihu-navigate/scripts/open_creator_entry.js
木炎 51913555ad feat: add initial skill authoring workspace
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-02 18:34:56 +08:00

138 lines
3.3 KiB
JavaScript

function cleanText(value) {
return String(value || '')
.replace(/\s+/g, ' ')
.replace(/\u200b/g, '')
.trim();
}
function bodyText() {
const body = document.body;
return cleanText(body && (body.innerText || body.textContent || ''));
}
function isLoginBlocked(url, text) {
return /\/signin\b|\/signup\b/.test(url) ||
/登录|注册|验证码|安全验证|验证后继续|请先登录/.test(text);
}
function hasEditorSignals() {
return !!document.querySelector(
"textarea[placeholder*='标题'], input[placeholder*='标题'], div[contenteditable='true'][role='textbox']"
);
}
function isVisible(node) {
if (!node) {
return false;
}
const rect = typeof node.getBoundingClientRect === 'function' ? node.getBoundingClientRect() : null;
return !rect || rect.width > 0 || rect.height > 0;
}
function isWriteEntryText(text) {
return !!text && (text.includes('写文章') || text.includes('发文章'));
}
function extractHref(node) {
if (!node) {
return '';
}
if (typeof node.href === 'string' && node.href) {
return node.href;
}
if (typeof node.getAttribute === 'function') {
return node.getAttribute('href') || '';
}
return '';
}
function findClickableAncestor(node) {
let current = node;
while (current) {
const tagName = String(current.tagName || '').toUpperCase();
const role = typeof current.getAttribute === 'function' ? cleanText(current.getAttribute('role')) : '';
const tabindex = typeof current.getAttribute === 'function' ? current.getAttribute('tabindex') : null;
const href = extractHref(current);
if (
tagName === 'A' ||
tagName === 'BUTTON' ||
role === 'button' ||
href ||
(tabindex !== null && tabindex !== '')
) {
return current;
}
current = current.parentElement || null;
}
return null;
}
function findWriteEntry() {
const directCandidates = Array.from(
document.querySelectorAll("a[href], button, [role='button']")
);
const directMatch = directCandidates.find((node) => {
const text = cleanText(node.textContent);
if (!isWriteEntryText(text)) {
return false;
}
return isVisible(node);
});
if (directMatch) {
return directMatch;
}
const textNodes = Array.from(
document.querySelectorAll("div, span, [tabindex]")
);
for (const node of textNodes) {
if (!isVisible(node)) {
continue;
}
const text = cleanText(node.textContent);
if (!isWriteEntryText(text)) {
continue;
}
const clickableAncestor = findClickableAncestor(node);
if (clickableAncestor && isVisible(clickableAncestor)) {
return clickableAncestor;
}
}
return null;
}
const currentUrl = location.href;
const text = bodyText();
if (isLoginBlocked(currentUrl, text)) {
return {
status: 'login_required',
current_url: currentUrl,
};
}
if (hasEditorSignals()) {
return {
status: 'editor_ready',
current_url: currentUrl,
};
}
const writeEntry = findWriteEntry();
if (writeEntry) {
writeEntry.click();
const href = extractHref(writeEntry);
return {
status: 'creator_entry_clicked',
current_url: currentUrl,
next_url: href || undefined,
};
}
return {
status: 'creator_home',
current_url: currentUrl,
desired_target: String(args.desired_target || 'creator_home'),
};