Skip to content

Commit

Permalink
Tweak new file creation and metadata loading
Browse files Browse the repository at this point in the history
  • Loading branch information
adamziel committed Dec 27, 2024
1 parent 0d8f88f commit cefacc2
Show file tree
Hide file tree
Showing 5 changed files with 156 additions and 301 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,6 @@ private function convert_markdown_to_blocks() {
);

$parser = new MarkdownParser( $environment );

$document = $parser->parse( $this->markdown );
$this->frontmatter = array();
foreach ( $document->data->export() as $key => $value ) {
Expand Down
31 changes: 18 additions & 13 deletions packages/playground/data-liberation-static-files-editor/plugin.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,9 @@
});
}

require_once __DIR__ . '/WP_Static_File_Sync.php';
require_once __DIR__ . '/secrets.php';
if(file_exists(__DIR__ . '/secrets.php')) {
require_once __DIR__ . '/secrets.php';
}

class WP_Static_Files_Editor_Plugin {

Expand All @@ -58,7 +59,7 @@ static private function get_fs() {

static public function initialize() {
// Register hooks
// register_activation_hook( __FILE__, array(self::class, 'import_static_pages') );
register_activation_hook( __FILE__, array(self::class, 'import_static_pages') );

add_action('init', function() {
self::register_post_type();
Expand Down Expand Up @@ -132,7 +133,7 @@ static public function initialize() {
// Preload the initial files tree
wp_add_inline_script('wp-api-fetch', 'wp.apiFetch.use(wp.apiFetch.createPreloadingMiddleware({
"/static-files-editor/v1/get-files-tree": {
body: '.json_encode(WP_Static_Files_Editor_Plugin::get_files_tree_endpoint()).'
body: '.json_encode(WP_Static_Files_Editor_Plugin::get_files_tree_endpoint()).',
}
}));', 'after');
});
Expand Down Expand Up @@ -254,16 +255,16 @@ static private function refresh_post_from_local_file($post) {
}
$extension = pathinfo($path, PATHINFO_EXTENSION);
switch($extension) {
case 'md':
$converter = new WP_Markdown_To_Blocks( $content );
break;
case 'xhtml':
$converter = new WP_HTML_To_Blocks( WP_XML_Processor::create_from_string( $content ) );
break;
case 'html':
default:
$converter = new WP_HTML_To_Blocks( WP_HTML_Processor::create_fragment( $content ) );
break;
case 'md':
default:
$converter = new WP_Markdown_To_Blocks( $content );
break;
}
$converter->convert();

Expand All @@ -276,6 +277,9 @@ static private function refresh_post_from_local_file($post) {
$updated = wp_update_post(array(
'ID' => $post_id,
'post_content' => $new_content,
'post_title' => $metadata['post_title'] ?? '',
'post_date_gmt' => $metadata['post_date_gmt'] ?? '',
'menu_order' => $metadata['menu_order'] ?? '',
// 'meta_input' => $metadata,
));
if(is_wp_error($updated)) {
Expand Down Expand Up @@ -306,12 +310,13 @@ static private function save_post_data_to_local_file($post) {
$fs = self::get_fs();
$path = get_post_meta($post_id, 'local_file_path', true);
$extension = pathinfo($path, PATHINFO_EXTENSION);
$metadata = get_post_meta($post_id);
$metadata = [];
foreach(['post_date_gmt', 'post_title', 'menu_order'] as $key) {
$metadata[$key] = get_post_field($key, $post_id);
}
// @TODO: Also include actual post_meta. Which ones? All? The
// ones explicitly set by the user in the editor?
// @TODO: Include specific post fields in the stored metadata
// foreach(WP_Imported_Entity::POST_FIELDS as $field) {
// $metadata[$field] = get_post_field($field, $post_id);
// }
$content = get_post_field('post_content', $post_id);
switch($extension) {
// @TODO: Add support for HTML and XHTML
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,16 @@ export type FileNode = {
children?: FileNode[];
};

export type CreatedNode = {
type: 'file' | 'folder';
path: string;
};

export type FilePickerControlProps = {
files: FileNode[];
initialPath?: string;
onSelect?: (path: string, node: FileNode) => void;
onNodeCreated?: (
type: 'file' | 'folder',
path: string,
name: string
) => void;
onNodeCreated?: (node: CreatedNode) => void;
isLoading?: boolean;
error?: string;
};
Expand Down Expand Up @@ -87,10 +88,14 @@ export const FilePickerTree: React.FC<FilePickerControlProps> = ({
};

const handleCreateNode = (type: 'file' | 'folder') => {
if (!selectedPath) return;

// Find selected node
const pathParts = selectedPath.split('/');
if (!selectedPath) {
setTempNode({
type,
parentPath: '',
});
return;
}
const pathParts = selectedPath.split('/') || [];
let currentNode: FileNode | undefined = undefined;
let currentNodes = files;

Expand All @@ -100,28 +105,24 @@ export const FilePickerTree: React.FC<FilePickerControlProps> = ({
currentNodes = currentNode.children || [];
}

if (!currentNode) return;

// If selected node is a file, use its parent path
const parentPath =
currentNode.type === 'file'
? pathParts.slice(0, -1).join('/')
: selectedPath;

console.log({
parentPath,
currentNode,
selectedPath,
pathParts,
});
currentNode?.type === 'folder' && expanded[selectedPath]
? selectedPath
: pathParts.slice(0, -1).join('/');

expandNode(parentPath, true);
setTempNode({ type, parentPath });
};

const handleTempNodeComplete = (name: string) => {
if (!tempNode) return;
onNodeCreated(tempNode.type, tempNode.parentPath, name);
// @TODO: Replace with joinPaths()
const fullPath = `${tempNode.parentPath}/${name}`.replace(/\/+/g, '/');
onNodeCreated({
type: tempNode.type,
path: fullPath,
});
setTempNode(null);
};

Expand All @@ -132,6 +133,11 @@ export const FilePickerTree: React.FC<FilePickerControlProps> = ({
const [searchBuffer, setSearchBuffer] = useState('');
const searchBufferTimeoutRef = useRef<NodeJS.Timeout | null>(null);
function handleKeyDown(event: React.KeyboardEvent<HTMLDivElement>) {
// Don't filter if we're creating a new file or folder –
// this would only blur and hide the filename input.
if (tempNode) {
return;
}
if (event.key.length === 1 && event.key.match(/\S/)) {
const newSearchBuffer = searchBuffer + event.key.toLowerCase();
setSearchBuffer(newSearchBuffer);
Expand Down Expand Up @@ -217,41 +223,48 @@ export const FilePickerTree: React.FC<FilePickerControlProps> = ({

return (
<div onKeyDown={handleKeyDown} ref={thisContainerRef}>
<ButtonGroup className={css['controls']}>
<Button
variant="secondary"
onClick={() => handleCreateNode('file')}
disabled={!selectedPath}
>
New File
</Button>
<Button
variant="secondary"
onClick={() => handleCreateNode('folder')}
disabled={!selectedPath}
>
New Folder
</Button>
</ButtonGroup>
<div
style={{ marginBottom: '1rem', display: 'flex', gap: '0.5rem' }}
>
<ButtonGroup className={css['controls']}>
<Button
variant="secondary"
onClick={() => handleCreateNode('file')}
disabled={!selectedPath}
>
New File
</Button>
<Button
variant="secondary"
onClick={() => handleCreateNode('folder')}
disabled={!selectedPath}
>
New Folder
</Button>
</ButtonGroup>
</div>

<TreeGrid className={css['filePickerTree']}>
{files.map((file, index) => (
<NodeRow
key={file.name}
node={file}
level={0}
position={index + 1}
setSize={files.length}
expandedNodePaths={expanded}
expandNode={expandNode}
selectedNode={selectedPath}
selectPath={selectPath}
generatePath={generatePath}
tempNode={tempNode}
onTempNodeComplete={handleTempNodeComplete}
onTempNodeCancel={handleTempNodeCancel}
/>
))}
<NodeRow
key={'/'}
node={{
name: '',
type: 'folder',
children: files,
}}
isRoot={true}
level={-1}
position={1}
setSize={files.length}
expandedNodePaths={expanded}
expandNode={expandNode}
selectedNode={selectedPath}
selectPath={selectPath}
generatePath={generatePath}
tempNode={tempNode}
onTempNodeComplete={handleTempNodeComplete}
onTempNodeCancel={handleTempNodeCancel}
/>
</TreeGrid>
</div>
);
Expand All @@ -262,6 +275,7 @@ const NodeRow: React.FC<{
level: number;
position: number;
setSize: number;
isRoot: boolean;
expandedNodePaths: ExpandedNodePaths;
expandNode: (path: string, isOpen: boolean) => void;
selectPath: (path: string) => void;
Expand All @@ -277,6 +291,7 @@ const NodeRow: React.FC<{
level,
position,
setSize,
isRoot,
expandedNodePaths,
expandNode,
selectPath,
Expand All @@ -288,7 +303,7 @@ const NodeRow: React.FC<{
onTempNodeCancel,
}) => {
const path = generatePath(node, parentPath);
const isExpanded = expandedNodePaths[path];
const isExpanded = isRoot || expandedNodePaths[path];

const toggleOpen = () => expandNode(path, !isExpanded);

Expand Down Expand Up @@ -334,54 +349,54 @@ const NodeRow: React.FC<{

return (
<>
<TreeGridRow
level={level}
positionInSet={position}
setSize={setSize}
>
<TreeGridCell>
{() => (
<Button
onClick={() => {
toggleOpen();
selectPath(path, node);
}}
onKeyDown={handleKeyDown}
className={classNames(css['fileNodeButton'], {
[css['selected']]: selectedNode === path,
'file-node-button': true,
})}
data-path={path}
>
<FileName
node={node}
isOpen={node.type === 'folder' && isExpanded}
level={level}
{!isRoot && (
<TreeGridRow
level={level}
positionInSet={position}
setSize={setSize}
>
<TreeGridCell>
{() => (
<Button
onClick={() => {
toggleOpen();
selectPath(path, node);
}}
onKeyDown={handleKeyDown}
className={classNames(css['fileNodeButton'], {
[css['selected']]: selectedNode === path,
'file-node-button': true,
})}
data-path={path}
>
<FileName
node={node}
isOpen={
node.type === 'folder' && isExpanded
}
level={level}
/>
</Button>
)}
</TreeGridCell>
</TreeGridRow>
)}
{tempNode && tempNode.parentPath === path && (
<TreeGridRow level={level + 1} positionInSet={1} setSize={1}>
<TreeGridCell>
{() => (
<TempNodeInput
type={tempNode.type}
onComplete={onTempNodeComplete}
onCancel={onTempNodeCancel}
level={level + 1}
/>
</Button>
)}
</TreeGridCell>
</TreeGridRow>
)}
</TreeGridCell>
</TreeGridRow>
)}
{isExpanded && (
<>
{tempNode && tempNode.parentPath === path && (
<TreeGridRow
level={level + 1}
positionInSet={1}
setSize={1}
>
<TreeGridCell>
{() => (
<TempNodeInput
type={tempNode.type}
onComplete={onTempNodeComplete}
onCancel={onTempNodeCancel}
level={level + 1}
/>
)}
</TreeGridCell>
</TreeGridRow>
)}
{node.children &&
node.children.map((child, index) => (
<NodeRow
Expand Down
Loading

0 comments on commit cefacc2

Please sign in to comment.