diff --git a/content/00-welcome/05-todos.md b/content/00-welcome/05-todos.md index ee4956c..9e88093 100644 --- a/content/00-welcome/05-todos.md +++ b/content/00-welcome/05-todos.md @@ -9,6 +9,8 @@ * DONE: License feature * ToDo: Enhance with plugins +---- + ## Visual Editor * DONE: Refactor and redesign diff --git a/content/02-folder/index.yaml b/content/02-folder/index.yaml new file mode 100644 index 0000000..4acaa3f --- /dev/null +++ b/content/02-folder/index.yaml @@ -0,0 +1,2 @@ +meta: + navtitle: folder diff --git a/data/navigation/navi-draft.txt b/data/navigation/navi-draft.txt index fa2b493..e16f672 100644 --- a/data/navigation/navi-draft.txt +++ b/data/navigation/navi-draft.txt @@ -1 +1 @@ -a:2:{i:0;O:8:"stdClass":22:{s:12:"originalName";s:10:"00-welcome";s:11:"elementType";s:6:"folder";s:8:"contains";s:5:"pages";s:6:"status";s:9:"published";s:8:"fileType";s:2:"md";s:5:"order";s:2:"00";s:4:"name";s:7:"welcome";s:4:"slug";s:7:"welcome";s:4:"path";s:11:"/00-welcome";s:15:"pathWithoutType";s:17:"/00-welcome/index";s:9:"urlRelWoF";s:8:"/welcome";s:6:"urlRel";s:17:"/typemill/welcome";s:6:"urlAbs";s:33:"http://localhost/typemill/welcome";s:3:"key";i:0;s:7:"keyPath";i:0;s:12:"keyPathArray";a:1:{i:0;s:1:"0";}s:7:"chapter";i:1;s:6:"active";b:0;s:12:"activeParent";b:0;s:4:"hide";b:0;s:13:"folderContent";a:6:{i:0;O:8:"stdClass":20:{s:12:"originalName";s:24:"00-setup-your-website.md";s:11:"elementType";s:4:"file";s:6:"status";s:9:"published";s:8:"fileType";s:2:"md";s:5:"order";s:2:"00";s:4:"name";s:18:"setup your website";s:4:"slug";s:18:"setup-your-website";s:4:"path";s:36:"/00-welcome/00-setup-your-website.md";s:15:"pathWithoutType";s:33:"/00-welcome/00-setup-your-website";s:3:"key";i:0;s:7:"keyPath";s:3:"0.0";s:12:"keyPathArray";a:2:{i:0;s:1:"0";i:1;s:1:"0";}s:7:"chapter";s:3:"1.1";s:9:"urlRelWoF";s:27:"/welcome/setup-your-website";s:6:"urlRel";s:36:"/typemill/welcome/setup-your-website";s:6:"urlAbs";s:52:"http://localhost/typemill/welcome/setup-your-website";s:6:"active";b:0;s:12:"activeParent";b:0;s:4:"hide";b:0;s:7:"noindex";b:0;}i:1;O:8:"stdClass":20:{s:12:"originalName";s:19:"01-manage-access.md";s:11:"elementType";s:4:"file";s:6:"status";s:9:"published";s:8:"fileType";s:2:"md";s:5:"order";s:2:"01";s:4:"name";s:13:"manage access";s:4:"slug";s:13:"manage-access";s:4:"path";s:31:"/00-welcome/01-manage-access.md";s:15:"pathWithoutType";s:28:"/00-welcome/01-manage-access";s:3:"key";i:1;s:7:"keyPath";s:3:"0.1";s:12:"keyPathArray";a:2:{i:0;s:1:"0";i:1;s:1:"1";}s:7:"chapter";s:3:"1.2";s:9:"urlRelWoF";s:22:"/welcome/manage-access";s:6:"urlRel";s:31:"/typemill/welcome/manage-access";s:6:"urlAbs";s:47:"http://localhost/typemill/welcome/manage-access";s:6:"active";b:0;s:12:"activeParent";b:0;s:4:"hide";b:0;s:7:"noindex";b:0;}i:2;O:8:"stdClass":20:{s:12:"originalName";s:19:"02-write-content.md";s:11:"elementType";s:4:"file";s:6:"status";s:9:"published";s:8:"fileType";s:2:"md";s:5:"order";s:2:"02";s:4:"name";s:13:"write content";s:4:"slug";s:13:"write-content";s:4:"path";s:31:"/00-welcome/02-write-content.md";s:15:"pathWithoutType";s:28:"/00-welcome/02-write-content";s:3:"key";i:2;s:7:"keyPath";s:3:"0.2";s:12:"keyPathArray";a:2:{i:0;s:1:"0";i:1;s:1:"2";}s:7:"chapter";s:3:"1.3";s:9:"urlRelWoF";s:22:"/welcome/write-content";s:6:"urlRel";s:31:"/typemill/welcome/write-content";s:6:"urlAbs";s:47:"http://localhost/typemill/welcome/write-content";s:6:"active";b:0;s:12:"activeParent";b:0;s:4:"hide";b:0;s:7:"noindex";b:0;}i:3;O:8:"stdClass":20:{s:12:"originalName";s:14:"03-get-help.md";s:11:"elementType";s:4:"file";s:6:"status";s:9:"published";s:8:"fileType";s:2:"md";s:5:"order";s:2:"03";s:4:"name";s:8:"get help";s:4:"slug";s:8:"get-help";s:4:"path";s:26:"/00-welcome/03-get-help.md";s:15:"pathWithoutType";s:23:"/00-welcome/03-get-help";s:3:"key";i:3;s:7:"keyPath";s:3:"0.3";s:12:"keyPathArray";a:2:{i:0;s:1:"0";i:1;s:1:"3";}s:7:"chapter";s:3:"1.4";s:9:"urlRelWoF";s:17:"/welcome/get-help";s:6:"urlRel";s:26:"/typemill/welcome/get-help";s:6:"urlAbs";s:42:"http://localhost/typemill/welcome/get-help";s:6:"active";b:0;s:12:"activeParent";b:0;s:4:"hide";b:0;s:7:"noindex";b:0;}i:4;O:8:"stdClass":20:{s:12:"originalName";s:19:"04-markdown-test.md";s:11:"elementType";s:4:"file";s:6:"status";s:9:"published";s:8:"fileType";s:2:"md";s:5:"order";s:2:"04";s:4:"name";s:13:"markdown test";s:4:"slug";s:13:"markdown-test";s:4:"path";s:31:"/00-welcome/04-markdown-test.md";s:15:"pathWithoutType";s:28:"/00-welcome/04-markdown-test";s:3:"key";i:4;s:7:"keyPath";s:3:"0.4";s:12:"keyPathArray";a:2:{i:0;s:1:"0";i:1;s:1:"4";}s:7:"chapter";s:3:"1.5";s:9:"urlRelWoF";s:22:"/welcome/markdown-test";s:6:"urlRel";s:31:"/typemill/welcome/markdown-test";s:6:"urlAbs";s:47:"http://localhost/typemill/welcome/markdown-test";s:6:"active";b:0;s:12:"activeParent";b:0;s:4:"hide";b:0;s:7:"noindex";b:0;}i:5;O:8:"stdClass":20:{s:12:"originalName";s:11:"05-todos.md";s:11:"elementType";s:4:"file";s:6:"status";s:9:"published";s:8:"fileType";s:2:"md";s:5:"order";s:2:"05";s:4:"name";s:6:"To Dos";s:4:"slug";s:5:"todos";s:4:"path";s:23:"/00-welcome/05-todos.md";s:15:"pathWithoutType";s:20:"/00-welcome/05-todos";s:3:"key";i:5;s:7:"keyPath";s:3:"0.5";s:12:"keyPathArray";a:2:{i:0;s:1:"0";i:1;s:1:"5";}s:7:"chapter";s:3:"1.6";s:9:"urlRelWoF";s:14:"/welcome/todos";s:6:"urlRel";s:23:"/typemill/welcome/todos";s:6:"urlAbs";s:39:"http://localhost/typemill/welcome/todos";s:6:"active";b:0;s:12:"activeParent";b:0;s:4:"hide";b:0;s:7:"noindex";b:0;}}s:7:"noindex";b:0;}i:1;O:8:"stdClass":22:{s:12:"originalName";s:16:"01-cyanine-theme";s:11:"elementType";s:6:"folder";s:8:"contains";s:5:"pages";s:6:"status";s:9:"published";s:8:"fileType";s:2:"md";s:5:"order";s:2:"01";s:4:"name";s:13:"cyanine theme";s:4:"slug";s:13:"cyanine-theme";s:4:"path";s:17:"/01-cyanine-theme";s:15:"pathWithoutType";s:23:"/01-cyanine-theme/index";s:9:"urlRelWoF";s:14:"/cyanine-theme";s:6:"urlRel";s:23:"/typemill/cyanine-theme";s:6:"urlAbs";s:39:"http://localhost/typemill/cyanine-theme";s:3:"key";i:1;s:7:"keyPath";i:1;s:12:"keyPathArray";a:1:{i:0;s:1:"1";}s:7:"chapter";i:2;s:6:"active";b:0;s:12:"activeParent";b:0;s:4:"hide";b:0;s:13:"folderContent";a:4:{i:0;O:8:"stdClass":20:{s:12:"originalName";s:17:"00-landingpage.md";s:11:"elementType";s:4:"file";s:6:"status";s:9:"published";s:8:"fileType";s:2:"md";s:5:"order";s:2:"00";s:4:"name";s:11:"landingpage";s:4:"slug";s:11:"landingpage";s:4:"path";s:35:"/01-cyanine-theme/00-landingpage.md";s:15:"pathWithoutType";s:32:"/01-cyanine-theme/00-landingpage";s:3:"key";i:0;s:7:"keyPath";s:3:"1.0";s:12:"keyPathArray";a:2:{i:0;s:1:"1";i:1;s:1:"0";}s:7:"chapter";s:3:"2.1";s:9:"urlRelWoF";s:26:"/cyanine-theme/landingpage";s:6:"urlRel";s:35:"/typemill/cyanine-theme/landingpage";s:6:"urlAbs";s:51:"http://localhost/typemill/cyanine-theme/landingpage";s:6:"active";b:0;s:12:"activeParent";b:0;s:4:"hide";b:0;s:7:"noindex";b:1;}i:1;O:8:"stdClass":20:{s:12:"originalName";s:22:"01-colors-and-fonts.md";s:11:"elementType";s:4:"file";s:6:"status";s:9:"published";s:8:"fileType";s:2:"md";s:5:"order";s:2:"01";s:4:"name";s:16:"colors and fonts";s:4:"slug";s:16:"colors-and-fonts";s:4:"path";s:40:"/01-cyanine-theme/01-colors-and-fonts.md";s:15:"pathWithoutType";s:37:"/01-cyanine-theme/01-colors-and-fonts";s:3:"key";i:1;s:7:"keyPath";s:3:"1.1";s:12:"keyPathArray";a:2:{i:0;s:1:"1";i:1;s:1:"1";}s:7:"chapter";s:3:"2.2";s:9:"urlRelWoF";s:31:"/cyanine-theme/colors-and-fonts";s:6:"urlRel";s:40:"/typemill/cyanine-theme/colors-and-fonts";s:6:"urlAbs";s:56:"http://localhost/typemill/cyanine-theme/colors-and-fonts";s:6:"active";b:0;s:12:"activeParent";b:0;s:4:"hide";b:0;s:7:"noindex";b:0;}i:2;O:8:"stdClass":20:{s:12:"originalName";s:12:"02-footer.md";s:11:"elementType";s:4:"file";s:6:"status";s:9:"published";s:8:"fileType";s:2:"md";s:5:"order";s:2:"02";s:4:"name";s:6:"footer";s:4:"slug";s:6:"footer";s:4:"path";s:30:"/01-cyanine-theme/02-footer.md";s:15:"pathWithoutType";s:27:"/01-cyanine-theme/02-footer";s:3:"key";i:2;s:7:"keyPath";s:3:"1.2";s:12:"keyPathArray";a:2:{i:0;s:1:"1";i:1;s:1:"2";}s:7:"chapter";s:3:"2.3";s:9:"urlRelWoF";s:21:"/cyanine-theme/footer";s:6:"urlRel";s:30:"/typemill/cyanine-theme/footer";s:6:"urlAbs";s:46:"http://localhost/typemill/cyanine-theme/footer";s:6:"active";b:0;s:12:"activeParent";b:0;s:4:"hide";b:0;s:7:"noindex";b:0;}i:3;O:8:"stdClass":20:{s:12:"originalName";s:22:"03-content-elements.md";s:11:"elementType";s:4:"file";s:6:"status";s:9:"published";s:8:"fileType";s:2:"md";s:5:"order";s:2:"03";s:4:"name";s:16:"content elements";s:4:"slug";s:16:"content-elements";s:4:"path";s:40:"/01-cyanine-theme/03-content-elements.md";s:15:"pathWithoutType";s:37:"/01-cyanine-theme/03-content-elements";s:3:"key";i:3;s:7:"keyPath";s:3:"1.3";s:12:"keyPathArray";a:2:{i:0;s:1:"1";i:1;s:1:"3";}s:7:"chapter";s:3:"2.4";s:9:"urlRelWoF";s:31:"/cyanine-theme/content-elements";s:6:"urlRel";s:40:"/typemill/cyanine-theme/content-elements";s:6:"urlAbs";s:56:"http://localhost/typemill/cyanine-theme/content-elements";s:6:"active";b:0;s:12:"activeParent";b:0;s:4:"hide";b:0;s:7:"noindex";b:0;}}s:7:"noindex";b:0;}} \ No newline at end of file +a:3:{i:0;O:8:"stdClass":22:{s:12:"originalName";s:10:"00-welcome";s:11:"elementType";s:6:"folder";s:8:"contains";s:5:"pages";s:6:"status";s:9:"published";s:8:"fileType";s:2:"md";s:5:"order";s:2:"00";s:4:"name";s:7:"welcome";s:4:"slug";s:7:"welcome";s:4:"path";s:11:"/00-welcome";s:15:"pathWithoutType";s:17:"/00-welcome/index";s:9:"urlRelWoF";s:8:"/welcome";s:6:"urlRel";s:17:"/typemill/welcome";s:6:"urlAbs";s:33:"http://localhost/typemill/welcome";s:3:"key";i:0;s:7:"keyPath";i:0;s:12:"keyPathArray";a:1:{i:0;s:1:"0";}s:7:"chapter";i:1;s:6:"active";b:0;s:12:"activeParent";b:0;s:4:"hide";b:0;s:13:"folderContent";a:6:{i:0;O:8:"stdClass":20:{s:12:"originalName";s:24:"00-setup-your-website.md";s:11:"elementType";s:4:"file";s:6:"status";s:9:"published";s:8:"fileType";s:2:"md";s:5:"order";s:2:"00";s:4:"name";s:18:"setup your website";s:4:"slug";s:18:"setup-your-website";s:4:"path";s:36:"/00-welcome/00-setup-your-website.md";s:15:"pathWithoutType";s:33:"/00-welcome/00-setup-your-website";s:3:"key";i:0;s:7:"keyPath";s:3:"0.0";s:12:"keyPathArray";a:2:{i:0;s:1:"0";i:1;s:1:"0";}s:7:"chapter";s:3:"1.1";s:9:"urlRelWoF";s:27:"/welcome/setup-your-website";s:6:"urlRel";s:36:"/typemill/welcome/setup-your-website";s:6:"urlAbs";s:52:"http://localhost/typemill/welcome/setup-your-website";s:6:"active";b:0;s:12:"activeParent";b:0;s:4:"hide";b:0;s:7:"noindex";b:0;}i:1;O:8:"stdClass":20:{s:12:"originalName";s:19:"01-manage-access.md";s:11:"elementType";s:4:"file";s:6:"status";s:9:"published";s:8:"fileType";s:2:"md";s:5:"order";s:2:"01";s:4:"name";s:13:"manage access";s:4:"slug";s:13:"manage-access";s:4:"path";s:31:"/00-welcome/01-manage-access.md";s:15:"pathWithoutType";s:28:"/00-welcome/01-manage-access";s:3:"key";i:1;s:7:"keyPath";s:3:"0.1";s:12:"keyPathArray";a:2:{i:0;s:1:"0";i:1;s:1:"1";}s:7:"chapter";s:3:"1.2";s:9:"urlRelWoF";s:22:"/welcome/manage-access";s:6:"urlRel";s:31:"/typemill/welcome/manage-access";s:6:"urlAbs";s:47:"http://localhost/typemill/welcome/manage-access";s:6:"active";b:0;s:12:"activeParent";b:0;s:4:"hide";b:0;s:7:"noindex";b:0;}i:2;O:8:"stdClass":20:{s:12:"originalName";s:19:"02-write-content.md";s:11:"elementType";s:4:"file";s:6:"status";s:9:"published";s:8:"fileType";s:2:"md";s:5:"order";s:2:"02";s:4:"name";s:13:"write content";s:4:"slug";s:13:"write-content";s:4:"path";s:31:"/00-welcome/02-write-content.md";s:15:"pathWithoutType";s:28:"/00-welcome/02-write-content";s:3:"key";i:2;s:7:"keyPath";s:3:"0.2";s:12:"keyPathArray";a:2:{i:0;s:1:"0";i:1;s:1:"2";}s:7:"chapter";s:3:"1.3";s:9:"urlRelWoF";s:22:"/welcome/write-content";s:6:"urlRel";s:31:"/typemill/welcome/write-content";s:6:"urlAbs";s:47:"http://localhost/typemill/welcome/write-content";s:6:"active";b:0;s:12:"activeParent";b:0;s:4:"hide";b:0;s:7:"noindex";b:0;}i:3;O:8:"stdClass":20:{s:12:"originalName";s:14:"03-get-help.md";s:11:"elementType";s:4:"file";s:6:"status";s:9:"published";s:8:"fileType";s:2:"md";s:5:"order";s:2:"03";s:4:"name";s:8:"get help";s:4:"slug";s:8:"get-help";s:4:"path";s:26:"/00-welcome/03-get-help.md";s:15:"pathWithoutType";s:23:"/00-welcome/03-get-help";s:3:"key";i:3;s:7:"keyPath";s:3:"0.3";s:12:"keyPathArray";a:2:{i:0;s:1:"0";i:1;s:1:"3";}s:7:"chapter";s:3:"1.4";s:9:"urlRelWoF";s:17:"/welcome/get-help";s:6:"urlRel";s:26:"/typemill/welcome/get-help";s:6:"urlAbs";s:42:"http://localhost/typemill/welcome/get-help";s:6:"active";b:0;s:12:"activeParent";b:0;s:4:"hide";b:0;s:7:"noindex";b:0;}i:4;O:8:"stdClass":20:{s:12:"originalName";s:19:"04-markdown-test.md";s:11:"elementType";s:4:"file";s:6:"status";s:9:"published";s:8:"fileType";s:2:"md";s:5:"order";s:2:"04";s:4:"name";s:13:"markdown test";s:4:"slug";s:13:"markdown-test";s:4:"path";s:31:"/00-welcome/04-markdown-test.md";s:15:"pathWithoutType";s:28:"/00-welcome/04-markdown-test";s:3:"key";i:4;s:7:"keyPath";s:3:"0.4";s:12:"keyPathArray";a:2:{i:0;s:1:"0";i:1;s:1:"4";}s:7:"chapter";s:3:"1.5";s:9:"urlRelWoF";s:22:"/welcome/markdown-test";s:6:"urlRel";s:31:"/typemill/welcome/markdown-test";s:6:"urlAbs";s:47:"http://localhost/typemill/welcome/markdown-test";s:6:"active";b:0;s:12:"activeParent";b:0;s:4:"hide";b:0;s:7:"noindex";b:0;}i:5;O:8:"stdClass":20:{s:12:"originalName";s:11:"05-todos.md";s:11:"elementType";s:4:"file";s:6:"status";s:9:"published";s:8:"fileType";s:2:"md";s:5:"order";s:2:"05";s:4:"name";s:6:"To Dos";s:4:"slug";s:5:"todos";s:4:"path";s:23:"/00-welcome/05-todos.md";s:15:"pathWithoutType";s:20:"/00-welcome/05-todos";s:3:"key";i:5;s:7:"keyPath";s:3:"0.5";s:12:"keyPathArray";a:2:{i:0;s:1:"0";i:1;s:1:"5";}s:7:"chapter";s:3:"1.6";s:9:"urlRelWoF";s:14:"/welcome/todos";s:6:"urlRel";s:23:"/typemill/welcome/todos";s:6:"urlAbs";s:39:"http://localhost/typemill/welcome/todos";s:6:"active";b:0;s:12:"activeParent";b:0;s:4:"hide";b:0;s:7:"noindex";b:0;}}s:7:"noindex";b:0;}i:1;O:8:"stdClass":22:{s:12:"originalName";s:16:"01-cyanine-theme";s:11:"elementType";s:6:"folder";s:8:"contains";s:5:"pages";s:6:"status";s:9:"published";s:8:"fileType";s:2:"md";s:5:"order";s:2:"01";s:4:"name";s:13:"cyanine theme";s:4:"slug";s:13:"cyanine-theme";s:4:"path";s:17:"/01-cyanine-theme";s:15:"pathWithoutType";s:23:"/01-cyanine-theme/index";s:9:"urlRelWoF";s:14:"/cyanine-theme";s:6:"urlRel";s:23:"/typemill/cyanine-theme";s:6:"urlAbs";s:39:"http://localhost/typemill/cyanine-theme";s:3:"key";i:1;s:7:"keyPath";i:1;s:12:"keyPathArray";a:1:{i:0;s:1:"1";}s:7:"chapter";i:2;s:6:"active";b:0;s:12:"activeParent";b:0;s:4:"hide";b:0;s:13:"folderContent";a:4:{i:0;O:8:"stdClass":20:{s:12:"originalName";s:17:"00-landingpage.md";s:11:"elementType";s:4:"file";s:6:"status";s:9:"published";s:8:"fileType";s:2:"md";s:5:"order";s:2:"00";s:4:"name";s:11:"landingpage";s:4:"slug";s:11:"landingpage";s:4:"path";s:35:"/01-cyanine-theme/00-landingpage.md";s:15:"pathWithoutType";s:32:"/01-cyanine-theme/00-landingpage";s:3:"key";i:0;s:7:"keyPath";s:3:"1.0";s:12:"keyPathArray";a:2:{i:0;s:1:"1";i:1;s:1:"0";}s:7:"chapter";s:3:"2.1";s:9:"urlRelWoF";s:26:"/cyanine-theme/landingpage";s:6:"urlRel";s:35:"/typemill/cyanine-theme/landingpage";s:6:"urlAbs";s:51:"http://localhost/typemill/cyanine-theme/landingpage";s:6:"active";b:0;s:12:"activeParent";b:0;s:4:"hide";b:0;s:7:"noindex";b:1;}i:1;O:8:"stdClass":20:{s:12:"originalName";s:22:"01-colors-and-fonts.md";s:11:"elementType";s:4:"file";s:6:"status";s:9:"published";s:8:"fileType";s:2:"md";s:5:"order";s:2:"01";s:4:"name";s:16:"colors and fonts";s:4:"slug";s:16:"colors-and-fonts";s:4:"path";s:40:"/01-cyanine-theme/01-colors-and-fonts.md";s:15:"pathWithoutType";s:37:"/01-cyanine-theme/01-colors-and-fonts";s:3:"key";i:1;s:7:"keyPath";s:3:"1.1";s:12:"keyPathArray";a:2:{i:0;s:1:"1";i:1;s:1:"1";}s:7:"chapter";s:3:"2.2";s:9:"urlRelWoF";s:31:"/cyanine-theme/colors-and-fonts";s:6:"urlRel";s:40:"/typemill/cyanine-theme/colors-and-fonts";s:6:"urlAbs";s:56:"http://localhost/typemill/cyanine-theme/colors-and-fonts";s:6:"active";b:0;s:12:"activeParent";b:0;s:4:"hide";b:0;s:7:"noindex";b:0;}i:2;O:8:"stdClass":20:{s:12:"originalName";s:12:"02-footer.md";s:11:"elementType";s:4:"file";s:6:"status";s:9:"published";s:8:"fileType";s:2:"md";s:5:"order";s:2:"02";s:4:"name";s:6:"footer";s:4:"slug";s:6:"footer";s:4:"path";s:30:"/01-cyanine-theme/02-footer.md";s:15:"pathWithoutType";s:27:"/01-cyanine-theme/02-footer";s:3:"key";i:2;s:7:"keyPath";s:3:"1.2";s:12:"keyPathArray";a:2:{i:0;s:1:"1";i:1;s:1:"2";}s:7:"chapter";s:3:"2.3";s:9:"urlRelWoF";s:21:"/cyanine-theme/footer";s:6:"urlRel";s:30:"/typemill/cyanine-theme/footer";s:6:"urlAbs";s:46:"http://localhost/typemill/cyanine-theme/footer";s:6:"active";b:0;s:12:"activeParent";b:0;s:4:"hide";b:0;s:7:"noindex";b:0;}i:3;O:8:"stdClass":20:{s:12:"originalName";s:22:"03-content-elements.md";s:11:"elementType";s:4:"file";s:6:"status";s:9:"published";s:8:"fileType";s:2:"md";s:5:"order";s:2:"03";s:4:"name";s:16:"content elements";s:4:"slug";s:16:"content-elements";s:4:"path";s:40:"/01-cyanine-theme/03-content-elements.md";s:15:"pathWithoutType";s:37:"/01-cyanine-theme/03-content-elements";s:3:"key";i:3;s:7:"keyPath";s:3:"1.3";s:12:"keyPathArray";a:2:{i:0;s:1:"1";i:1;s:1:"3";}s:7:"chapter";s:3:"2.4";s:9:"urlRelWoF";s:31:"/cyanine-theme/content-elements";s:6:"urlRel";s:40:"/typemill/cyanine-theme/content-elements";s:6:"urlAbs";s:56:"http://localhost/typemill/cyanine-theme/content-elements";s:6:"active";b:0;s:12:"activeParent";b:0;s:4:"hide";b:0;s:7:"noindex";b:0;}}s:7:"noindex";b:0;}i:2;O:8:"stdClass":22:{s:12:"originalName";s:9:"02-folder";s:11:"elementType";s:6:"folder";s:8:"contains";s:5:"pages";s:6:"status";s:9:"published";s:8:"fileType";s:0:"";s:5:"order";s:2:"02";s:4:"name";s:6:"folder";s:4:"slug";s:6:"folder";s:4:"path";s:10:"/02-folder";s:15:"pathWithoutType";s:16:"/02-folder/index";s:9:"urlRelWoF";s:7:"/folder";s:6:"urlRel";s:16:"/typemill/folder";s:6:"urlAbs";s:32:"http://localhost/typemill/folder";s:3:"key";i:2;s:7:"keyPath";i:2;s:12:"keyPathArray";a:1:{i:0;s:1:"2";}s:7:"chapter";i:3;s:6:"active";b:0;s:12:"activeParent";b:0;s:4:"hide";b:0;s:13:"folderContent";a:0:{}s:7:"noindex";b:0;}} \ No newline at end of file diff --git a/data/navigation/navi-extended.txt b/data/navigation/navi-extended.txt index 7497497..cc60e92 100644 --- a/data/navigation/navi-extended.txt +++ b/data/navigation/navi-extended.txt @@ -70,3 +70,9 @@ noindex: false path: /01-cyanine-theme/03-content-elements.md keyPath: '1.3' +/folder: + navtitle: folder + hide: false + noindex: false + path: /02-folder + keyPath: 2 diff --git a/data/navigation/navi-live.txt b/data/navigation/navi-live.txt new file mode 100644 index 0000000..fa2b493 --- /dev/null +++ b/data/navigation/navi-live.txt @@ -0,0 +1 @@ +a:2:{i:0;O:8:"stdClass":22:{s:12:"originalName";s:10:"00-welcome";s:11:"elementType";s:6:"folder";s:8:"contains";s:5:"pages";s:6:"status";s:9:"published";s:8:"fileType";s:2:"md";s:5:"order";s:2:"00";s:4:"name";s:7:"welcome";s:4:"slug";s:7:"welcome";s:4:"path";s:11:"/00-welcome";s:15:"pathWithoutType";s:17:"/00-welcome/index";s:9:"urlRelWoF";s:8:"/welcome";s:6:"urlRel";s:17:"/typemill/welcome";s:6:"urlAbs";s:33:"http://localhost/typemill/welcome";s:3:"key";i:0;s:7:"keyPath";i:0;s:12:"keyPathArray";a:1:{i:0;s:1:"0";}s:7:"chapter";i:1;s:6:"active";b:0;s:12:"activeParent";b:0;s:4:"hide";b:0;s:13:"folderContent";a:6:{i:0;O:8:"stdClass":20:{s:12:"originalName";s:24:"00-setup-your-website.md";s:11:"elementType";s:4:"file";s:6:"status";s:9:"published";s:8:"fileType";s:2:"md";s:5:"order";s:2:"00";s:4:"name";s:18:"setup your website";s:4:"slug";s:18:"setup-your-website";s:4:"path";s:36:"/00-welcome/00-setup-your-website.md";s:15:"pathWithoutType";s:33:"/00-welcome/00-setup-your-website";s:3:"key";i:0;s:7:"keyPath";s:3:"0.0";s:12:"keyPathArray";a:2:{i:0;s:1:"0";i:1;s:1:"0";}s:7:"chapter";s:3:"1.1";s:9:"urlRelWoF";s:27:"/welcome/setup-your-website";s:6:"urlRel";s:36:"/typemill/welcome/setup-your-website";s:6:"urlAbs";s:52:"http://localhost/typemill/welcome/setup-your-website";s:6:"active";b:0;s:12:"activeParent";b:0;s:4:"hide";b:0;s:7:"noindex";b:0;}i:1;O:8:"stdClass":20:{s:12:"originalName";s:19:"01-manage-access.md";s:11:"elementType";s:4:"file";s:6:"status";s:9:"published";s:8:"fileType";s:2:"md";s:5:"order";s:2:"01";s:4:"name";s:13:"manage access";s:4:"slug";s:13:"manage-access";s:4:"path";s:31:"/00-welcome/01-manage-access.md";s:15:"pathWithoutType";s:28:"/00-welcome/01-manage-access";s:3:"key";i:1;s:7:"keyPath";s:3:"0.1";s:12:"keyPathArray";a:2:{i:0;s:1:"0";i:1;s:1:"1";}s:7:"chapter";s:3:"1.2";s:9:"urlRelWoF";s:22:"/welcome/manage-access";s:6:"urlRel";s:31:"/typemill/welcome/manage-access";s:6:"urlAbs";s:47:"http://localhost/typemill/welcome/manage-access";s:6:"active";b:0;s:12:"activeParent";b:0;s:4:"hide";b:0;s:7:"noindex";b:0;}i:2;O:8:"stdClass":20:{s:12:"originalName";s:19:"02-write-content.md";s:11:"elementType";s:4:"file";s:6:"status";s:9:"published";s:8:"fileType";s:2:"md";s:5:"order";s:2:"02";s:4:"name";s:13:"write content";s:4:"slug";s:13:"write-content";s:4:"path";s:31:"/00-welcome/02-write-content.md";s:15:"pathWithoutType";s:28:"/00-welcome/02-write-content";s:3:"key";i:2;s:7:"keyPath";s:3:"0.2";s:12:"keyPathArray";a:2:{i:0;s:1:"0";i:1;s:1:"2";}s:7:"chapter";s:3:"1.3";s:9:"urlRelWoF";s:22:"/welcome/write-content";s:6:"urlRel";s:31:"/typemill/welcome/write-content";s:6:"urlAbs";s:47:"http://localhost/typemill/welcome/write-content";s:6:"active";b:0;s:12:"activeParent";b:0;s:4:"hide";b:0;s:7:"noindex";b:0;}i:3;O:8:"stdClass":20:{s:12:"originalName";s:14:"03-get-help.md";s:11:"elementType";s:4:"file";s:6:"status";s:9:"published";s:8:"fileType";s:2:"md";s:5:"order";s:2:"03";s:4:"name";s:8:"get help";s:4:"slug";s:8:"get-help";s:4:"path";s:26:"/00-welcome/03-get-help.md";s:15:"pathWithoutType";s:23:"/00-welcome/03-get-help";s:3:"key";i:3;s:7:"keyPath";s:3:"0.3";s:12:"keyPathArray";a:2:{i:0;s:1:"0";i:1;s:1:"3";}s:7:"chapter";s:3:"1.4";s:9:"urlRelWoF";s:17:"/welcome/get-help";s:6:"urlRel";s:26:"/typemill/welcome/get-help";s:6:"urlAbs";s:42:"http://localhost/typemill/welcome/get-help";s:6:"active";b:0;s:12:"activeParent";b:0;s:4:"hide";b:0;s:7:"noindex";b:0;}i:4;O:8:"stdClass":20:{s:12:"originalName";s:19:"04-markdown-test.md";s:11:"elementType";s:4:"file";s:6:"status";s:9:"published";s:8:"fileType";s:2:"md";s:5:"order";s:2:"04";s:4:"name";s:13:"markdown test";s:4:"slug";s:13:"markdown-test";s:4:"path";s:31:"/00-welcome/04-markdown-test.md";s:15:"pathWithoutType";s:28:"/00-welcome/04-markdown-test";s:3:"key";i:4;s:7:"keyPath";s:3:"0.4";s:12:"keyPathArray";a:2:{i:0;s:1:"0";i:1;s:1:"4";}s:7:"chapter";s:3:"1.5";s:9:"urlRelWoF";s:22:"/welcome/markdown-test";s:6:"urlRel";s:31:"/typemill/welcome/markdown-test";s:6:"urlAbs";s:47:"http://localhost/typemill/welcome/markdown-test";s:6:"active";b:0;s:12:"activeParent";b:0;s:4:"hide";b:0;s:7:"noindex";b:0;}i:5;O:8:"stdClass":20:{s:12:"originalName";s:11:"05-todos.md";s:11:"elementType";s:4:"file";s:6:"status";s:9:"published";s:8:"fileType";s:2:"md";s:5:"order";s:2:"05";s:4:"name";s:6:"To Dos";s:4:"slug";s:5:"todos";s:4:"path";s:23:"/00-welcome/05-todos.md";s:15:"pathWithoutType";s:20:"/00-welcome/05-todos";s:3:"key";i:5;s:7:"keyPath";s:3:"0.5";s:12:"keyPathArray";a:2:{i:0;s:1:"0";i:1;s:1:"5";}s:7:"chapter";s:3:"1.6";s:9:"urlRelWoF";s:14:"/welcome/todos";s:6:"urlRel";s:23:"/typemill/welcome/todos";s:6:"urlAbs";s:39:"http://localhost/typemill/welcome/todos";s:6:"active";b:0;s:12:"activeParent";b:0;s:4:"hide";b:0;s:7:"noindex";b:0;}}s:7:"noindex";b:0;}i:1;O:8:"stdClass":22:{s:12:"originalName";s:16:"01-cyanine-theme";s:11:"elementType";s:6:"folder";s:8:"contains";s:5:"pages";s:6:"status";s:9:"published";s:8:"fileType";s:2:"md";s:5:"order";s:2:"01";s:4:"name";s:13:"cyanine theme";s:4:"slug";s:13:"cyanine-theme";s:4:"path";s:17:"/01-cyanine-theme";s:15:"pathWithoutType";s:23:"/01-cyanine-theme/index";s:9:"urlRelWoF";s:14:"/cyanine-theme";s:6:"urlRel";s:23:"/typemill/cyanine-theme";s:6:"urlAbs";s:39:"http://localhost/typemill/cyanine-theme";s:3:"key";i:1;s:7:"keyPath";i:1;s:12:"keyPathArray";a:1:{i:0;s:1:"1";}s:7:"chapter";i:2;s:6:"active";b:0;s:12:"activeParent";b:0;s:4:"hide";b:0;s:13:"folderContent";a:4:{i:0;O:8:"stdClass":20:{s:12:"originalName";s:17:"00-landingpage.md";s:11:"elementType";s:4:"file";s:6:"status";s:9:"published";s:8:"fileType";s:2:"md";s:5:"order";s:2:"00";s:4:"name";s:11:"landingpage";s:4:"slug";s:11:"landingpage";s:4:"path";s:35:"/01-cyanine-theme/00-landingpage.md";s:15:"pathWithoutType";s:32:"/01-cyanine-theme/00-landingpage";s:3:"key";i:0;s:7:"keyPath";s:3:"1.0";s:12:"keyPathArray";a:2:{i:0;s:1:"1";i:1;s:1:"0";}s:7:"chapter";s:3:"2.1";s:9:"urlRelWoF";s:26:"/cyanine-theme/landingpage";s:6:"urlRel";s:35:"/typemill/cyanine-theme/landingpage";s:6:"urlAbs";s:51:"http://localhost/typemill/cyanine-theme/landingpage";s:6:"active";b:0;s:12:"activeParent";b:0;s:4:"hide";b:0;s:7:"noindex";b:1;}i:1;O:8:"stdClass":20:{s:12:"originalName";s:22:"01-colors-and-fonts.md";s:11:"elementType";s:4:"file";s:6:"status";s:9:"published";s:8:"fileType";s:2:"md";s:5:"order";s:2:"01";s:4:"name";s:16:"colors and fonts";s:4:"slug";s:16:"colors-and-fonts";s:4:"path";s:40:"/01-cyanine-theme/01-colors-and-fonts.md";s:15:"pathWithoutType";s:37:"/01-cyanine-theme/01-colors-and-fonts";s:3:"key";i:1;s:7:"keyPath";s:3:"1.1";s:12:"keyPathArray";a:2:{i:0;s:1:"1";i:1;s:1:"1";}s:7:"chapter";s:3:"2.2";s:9:"urlRelWoF";s:31:"/cyanine-theme/colors-and-fonts";s:6:"urlRel";s:40:"/typemill/cyanine-theme/colors-and-fonts";s:6:"urlAbs";s:56:"http://localhost/typemill/cyanine-theme/colors-and-fonts";s:6:"active";b:0;s:12:"activeParent";b:0;s:4:"hide";b:0;s:7:"noindex";b:0;}i:2;O:8:"stdClass":20:{s:12:"originalName";s:12:"02-footer.md";s:11:"elementType";s:4:"file";s:6:"status";s:9:"published";s:8:"fileType";s:2:"md";s:5:"order";s:2:"02";s:4:"name";s:6:"footer";s:4:"slug";s:6:"footer";s:4:"path";s:30:"/01-cyanine-theme/02-footer.md";s:15:"pathWithoutType";s:27:"/01-cyanine-theme/02-footer";s:3:"key";i:2;s:7:"keyPath";s:3:"1.2";s:12:"keyPathArray";a:2:{i:0;s:1:"1";i:1;s:1:"2";}s:7:"chapter";s:3:"2.3";s:9:"urlRelWoF";s:21:"/cyanine-theme/footer";s:6:"urlRel";s:30:"/typemill/cyanine-theme/footer";s:6:"urlAbs";s:46:"http://localhost/typemill/cyanine-theme/footer";s:6:"active";b:0;s:12:"activeParent";b:0;s:4:"hide";b:0;s:7:"noindex";b:0;}i:3;O:8:"stdClass":20:{s:12:"originalName";s:22:"03-content-elements.md";s:11:"elementType";s:4:"file";s:6:"status";s:9:"published";s:8:"fileType";s:2:"md";s:5:"order";s:2:"03";s:4:"name";s:16:"content elements";s:4:"slug";s:16:"content-elements";s:4:"path";s:40:"/01-cyanine-theme/03-content-elements.md";s:15:"pathWithoutType";s:37:"/01-cyanine-theme/03-content-elements";s:3:"key";i:3;s:7:"keyPath";s:3:"1.3";s:12:"keyPathArray";a:2:{i:0;s:1:"1";i:1;s:1:"3";}s:7:"chapter";s:3:"2.4";s:9:"urlRelWoF";s:31:"/cyanine-theme/content-elements";s:6:"urlRel";s:40:"/typemill/cyanine-theme/content-elements";s:6:"urlAbs";s:56:"http://localhost/typemill/cyanine-theme/content-elements";s:6:"active";b:0;s:12:"activeParent";b:0;s:4:"hide";b:0;s:7:"noindex";b:0;}}s:7:"noindex";b:0;}} \ No newline at end of file diff --git a/system/typemill/Controllers/ControllerApiAuthorArticle.php b/system/typemill/Controllers/ControllerApiAuthorArticle.php index d67945a..0981a18 100644 --- a/system/typemill/Controllers/ControllerApiAuthorArticle.php +++ b/system/typemill/Controllers/ControllerApiAuthorArticle.php @@ -54,7 +54,15 @@ class ControllerApiAuthorArticle extends Controller # publish content $content = new Content($urlinfo['baseurl']); $draftMarkdown = $content->getDraftMarkdown($item); - $content->publishMarkdown($item, $draftMarkdown); + $publish = $content->publishMarkdown($item, $draftMarkdown); + if($publish !== true) + { + $response->getBody()->write(json_encode([ + 'message' => $publish, + ])); + + return $response->withHeader('Content-Type', 'application/json')->withStatus(404); + } # refresh navigation and item $navigation->clearNavigation(); @@ -848,12 +856,12 @@ class ControllerApiAuthorArticle extends Controller } # check if it is a folder and if the folder has published pages. - if($item->elementType == 'folder' && isset($item->folderContent)) + if($item->elementType == 'folder') { - if(count($item->folderContent > 0)) + if($this->folderHasPublishedPages($item)) { $response->getBody()->write(json_encode([ - 'message' => 'This folder contains pages, please delete the pages first.', + 'message' => 'The folder contains published pages. Please unpublish or delete the pages first.', ])); return $response->withHeader('Content-Type', 'application/json')->withStatus(422); @@ -889,4 +897,21 @@ class ControllerApiAuthorArticle extends Controller return $response->withHeader('Content-Type', 'application/json'); } + + + private function folderHasPublishedPages($folder) + { + if(isset($folder->folderContent) && is_array($folder->folderContent) && count($folder->folderContent) > 0 ) + { + foreach($folder->folderContent as $page) + { + if($page->status == 'published') + { + return true; + } + } + } + + return false; + } } \ No newline at end of file diff --git a/system/typemill/Controllers/ControllerWebFrontend.php b/system/typemill/Controllers/ControllerWebFrontend.php index bb72454..c19a8ad 100644 --- a/system/typemill/Controllers/ControllerWebFrontend.php +++ b/system/typemill/Controllers/ControllerWebFrontend.php @@ -360,385 +360,4 @@ class ControllerWebFrontend extends Controller return $restrictionNotice; } - - - - - - - - - - - - - - - - - - -/* - # Initiate Variables - $contentHTML = false; - $item = false; - $home = false; - $breadcrumb = false; - $currentpage = false; - $this->pathToContent = $this->settings['rootPath'] . $this->settings['contentFolder']; - $this->uri = $request->getUri()->withUserInfo(''); - $this->base_url = $this->uri->getBaseUrl(); - - # if there is no structure at all, the content folder is probably empty - if(!$this->setStructureLive()) - { - return $this->render($response, '/index.twig', array( 'content' => '

No Content

Your content folder is empty.

' )); - } - - # we can create an initial sitemap here, but makes no sense for every pagecall. Sitemap will be created on first author interaction (publish/delete/channge page). - # $this->checkSitemap(); - - # if the admin activated to refresh the cache automatically each 10 minutes (e.g. use without admin area) - if(isset($this->settings['refreshcache']) && $this->settings['refreshcache'] && !$this->writeCache->validate('cache', 'lastCache.txt', 600)) - { - # delete the cache - $dir = $this->settings['basePath'] . 'cache'; - $this->writeCache->deleteCacheFiles($dir); - - # update the internal structure - $this->setFreshStructureDraft(); - - # update the public structure - $this->setFreshStructureLive(); - - # update the navigation - $this->setFreshNavigation(); - - # update the sitemap - $this->updateSitemap(); - } - - # dispatch event and let others manipulate the structure - $this->structureLive = $this->c->dispatcher->dispatch('onPagetreeLoaded', new OnPagetreeLoaded($this->structureLive))->getData(); - - # check if there is a custom theme css - $theme = $this->settings['theme']; - $customcss = $this->writeCache->checkFile('cache', $theme . '-custom.css'); - if($customcss) - { - $this->c->assets->addCSS($this->base_url . '/cache/' . $theme . '-custom.css'); - } - - $logo = false; - if(isset($this->settings['logo']) && $this->settings['logo'] != '') - { - # check if logo exists - if(file_exists($this->settings['rootPath'] . 'media/live/' . $this->settings['logo'])) - { - $logo = 'media/live/' . $this->settings['logo']; - } - elseif(file_exists($this->settings['rootPath'] . 'media/files/' . $this->settings['logo'])) - { - $logo = 'media/files/' . $this->settings['logo']; - } - } - - $favicon = false; - if(isset($this->settings['favicon']) && $this->settings['favicon'] != '') - { - $favicon = true; - $this->c->assets->addMeta('tilecolor',''); - $this->c->assets->addMeta('tileimage',''); - $this->c->assets->addMeta('icon16',''); - $this->c->assets->addMeta('icon32',''); - $this->c->assets->addMeta('icon72',''); - $this->c->assets->addMeta('icon114',''); - $this->c->assets->addMeta('icon144',''); - $this->c->assets->addMeta('icon180',''); - } - - # the navigation is a copy of the structure without the hidden pages - # hint: if the navigation has been deleted from the cache, then we do not recreate it here to save performace. - # Instead you have to recreate cache in admin or change a page (publish/unpublish/delete/move) - $navigation = $this->writeCache->getCache('cache', 'navigation.txt'); - if(!$navigation) - { - # use the structure if there is no cached navigation - $navigation = $this->structureLive; - } - - # start pagination - if(isset($args['params'])) - { - $argSegments = explode("/", $args['params']); - - # check if the last url segment is a number - $pageNumber = array_pop($argSegments); - if(is_numeric($pageNumber) && $pageNumber < 10000) - { - # then check if the segment before the page is a "p" that indicates a paginator - $pageIndicator = array_pop($argSegments); - if($pageIndicator == "p") - { - # use page number as current page variable - $currentpage = $pageNumber; - - # set empty args for startpage - $args = []; - - # if there are still params - if(!empty($argSegments)) - { - # add them to the args again - $args['params'] = implode("/", $argSegments); - } - } - } - } - - # if the user is on startpage - $home = false; - if(empty($args)) - { - $home = true; - $item = Folder::getItemForUrl($navigation, $this->uri->getBasePath(), $this->uri->getBaseUrl(), NULL, $home); - $urlRel = $this->uri->getBasePath(); - } - else - { - # get the request url, trim args so physical folders have no trailing slash - $urlRel = $this->uri->getBasePath() . '/' . trim($args['params'], "/"); - - # find the url in the content-item-tree and return the item-object for the file - # important to use the structure here so it is found, even if the item is hidden. - $item = Folder::getItemForUrl($this->structureLive, $urlRel, $this->uri->getBasePath()); - - # if the item is a folder and if that folder is not hidden - if($item && $item->elementType == 'folder' && isset($item->hide) && !$item->hide) - { - # use the navigation instead of the structure so that hidden elements are erased - $item = Folder::getItemForUrl($navigation, $urlRel, $this->uri->getBaseUrl(), NULL, $home); - } - - # if there is still no item, return a 404-page - if(!$item) - { - return $this->render404($response, array( - 'navigation' => $navigation, - 'settings' => $this->settings, - 'base_url' => $this->base_url, - 'title' => false, - 'content' => false, - 'item' => false, - 'breadcrumb' => false, - 'metatabs' => false, - 'image' => false, - 'logo' => $logo, - 'favicon' => $favicon - )); - } - } - - - - -### - if(isset($item->hide)) - { - # if it is a hidden page - if($item->hide) - { - # get breadcrumb for page and set pages active - # use structure here because the hidden item is not part of the navigation - $breadcrumb = Folder::getBreadcrumb($this->structureLive, $item->keyPathArray); - $breadcrumb = $this->c->dispatcher->dispatch('onBreadcrumbLoaded', new OnBreadcrumbLoaded($breadcrumb))->getData(); - - # add the paging to the item - $item = Folder::getPagingForItem($this->structureLive, $item); - } - else - { - # get breadcrumb for page and set pages active - # use navigation, because it is used for frontend - $breadcrumb = Folder::getBreadcrumb($navigation, $item->keyPathArray); - $breadcrumb = $this->c->dispatcher->dispatch('onBreadcrumbLoaded', new OnBreadcrumbLoaded($breadcrumb))->getData(); - - # add the paging to the item - $item = Folder::getPagingForItem($navigation, $item); - } - } -### - - - - # dispatch the item - $item = $this->c->dispatcher->dispatch('onItemLoaded', new OnItemLoaded($item))->getData(); - - # set the filepath - $filePath = $this->pathToContent . $item->path; - - # check if url is a folder and add index.md - if($item->elementType == 'folder') - { - $filePath = $filePath . DIRECTORY_SEPARATOR . 'index.md'; - } - - # read the content of the file - $contentMD = file_exists($filePath) ? file_get_contents($filePath) : false; - - # dispatch the original content without plugin-manipulations for case anyone wants to use it - $this->c->dispatcher->dispatch('onOriginalLoaded', new OnOriginalLoaded($contentMD)); - - # initiate object for metadata - $writeMeta = new WriteMeta(); - - # makes sure that you always have the full meta with title, description and all the rest. - $metatabs = $writeMeta->completePageMeta($contentMD, $this->settings, $item); - - # write meta - if(isset($metatabs['meta']['noindex']) && $metatabs['meta']['noindex']) - { - $this->c->assets->addMeta('noindex',''); - } - - $this->c->assets->addMeta('og_site_name',''); - $this->c->assets->addMeta('og_title',''); - $this->c->assets->addMeta('og_description',''); - $this->c->assets->addMeta('og_type',''); - $this->c->assets->addMeta('og_url',''); - - # dispatch meta - $metatabs = $this->c->dispatcher->dispatch('onMetaLoaded', new OnMetaLoaded($metatabs))->getData(); - - # dispatch content - $contentMD = $this->c->dispatcher->dispatch('onMarkdownLoaded', new OnMarkdownLoaded($contentMD))->getData(); - - $itemUrl = isset($item->urlRel) ? $item->urlRel : false; - - /* initialize parsedown - $parsedown = new ParsedownExtension($this->base_url, $this->settings, $this->c->dispatcher); - - /* set safe mode to escape javascript and html in markdown - $parsedown->setSafeMode(true); - - - -#### - # check access restriction here - $restricted = $this->checkRestrictions($metatabs['meta']); - if($restricted) - { - # convert markdown into array of markdown block-elements - $markdownBlocks = $parsedown->markdownToArrayBlocks($contentMD); - - # infos that plugins need to add restriction content - $restrictions = [ - 'restricted' => $restricted, - 'defaultContent' => true, - 'markdownBlocks' => $markdownBlocks, - ]; - - # dispatch the data - $restrictions = $this->c->dispatcher->dispatch('onRestrictionsLoaded', new OnRestrictionsLoaded( $restrictions ))->getData(); - - # use the returned markdown - $markdownBlocks = $restrictions['markdownBlocks']; - - # if no plugin has disabled the default behavior - if($restrictions['defaultContent']) - { - # cut the restricted content - $shortenedPage = $this->cutRestrictedContent($markdownBlocks); - - # check if there is customized content - $restrictionnotice = $this->prepareRestrictionNotice(); - - # add notice to shortened content - $shortenedPage[] = $restrictionnotice; - - # Use the shortened page - $markdownBlocks = $shortenedPage; - } - - # finally transform the markdown blocks back to pure markdown text - $contentMD = $parsedown->arrayBlocksToMarkdown($markdownBlocks); - } -### - - - - /* parse markdown-file to content-array - $contentArray = $parsedown->text($contentMD); - $contentArray = $this->c->dispatcher->dispatch('onContentArrayLoaded', new OnContentArrayLoaded($contentArray))->getData(); - - /* parse markdown-content-array to content-string - $contentHTML = $parsedown->markup($contentArray); - $contentHTML = $this->c->dispatcher->dispatch('onHtmlLoaded', new OnHtmlLoaded($contentHTML))->getData(); - - /* extract the h1 headline - $contentParts = explode("", $contentHTML, 2); - $title = isset($contentParts[0]) ? strip_tags($contentParts[0]) : $this->settings['title']; - - $contentHTML = isset($contentParts[1]) ? $contentParts[1] : $contentHTML; - - # get the first image from content array - $img_url = isset($metatabs['meta']['heroimage']) ? $metatabs['meta']['heroimage'] : false; - $img_alt = isset($metatabs['meta']['heroimagealt']) ? $metatabs['meta']['heroimagealt'] : false; - - # get url and alt-tag for first image, if exists - if(!$img_url OR $img_url == '') - { - # extract first image from content - $firstImageMD = $this->getFirstImage($contentArray); - - if($firstImageMD) - { - preg_match('#\((.*?)\)#', $firstImageMD, $img_url_result); - $img_url = isset($img_url_result[1]) ? $img_url_result[1] : false; - - if($img_url) - { - preg_match('#\[(.*?)\]#', $firstImageMD, $img_alt_result); - $img_alt = isset($img_alt_result[1]) ? $img_alt_result[1] : false; - } - } - elseif($logo) - { - $img_url = $logo; - $pathinfo = pathinfo($this->settings['logo']); - $img_alt = $pathinfo['filename']; - } - } - - $firstImage = false; - if($img_url) - { - $firstImage = array('img_url' => $this->base_url . '/' . $img_url, 'img_alt' => $img_alt); - - $this->c->assets->addMeta('og_image',''); - $this->c->assets->addMeta('twitter_image_alt',''); - $this->c->assets->addMeta('twitter_card',''); - } - - $route = empty($args) && isset($this->settings['themes'][$theme]['cover']) ? '/cover.twig' : '/index.twig'; - - return $this->render($response, $route, [ - 'home' => $home, - 'navigation' => $navigation, - 'title' => $title, - 'content' => $contentHTML, - 'item' => $item, - 'breadcrumb' => $breadcrumb, - 'settings' => $this->settings, - 'base_url' => $this->base_url, - 'metatabs' => $metatabs, - 'image' => $firstImage, - 'logo' => $logo, - 'favicon' => $favicon, - 'currentpage' => $currentpage - ]); - } - - */ - } \ No newline at end of file diff --git a/system/typemill/Controllers/ControllerWebSystem.php b/system/typemill/Controllers/ControllerWebSystem.php index d38c46f..200da08 100644 --- a/system/typemill/Controllers/ControllerWebSystem.php +++ b/system/typemill/Controllers/ControllerWebSystem.php @@ -2,6 +2,8 @@ namespace Typemill\Controllers; +use Psr\Http\Message\ServerRequestInterface as Request; +use Psr\Http\Message\ResponseInterface as Response; use Typemill\Models\Navigation; use Typemill\Models\Extension; use Typemill\Models\User; @@ -10,7 +12,7 @@ use Typemill\Models\Settings; class ControllerWebSystem extends Controller { - public function showSettings($request, $response, $args) + public function showSettings(Request $request, Response $response, $args) { $navigation = new Navigation(); $mainNavigation = $navigation->getMainNavigation( @@ -49,7 +51,7 @@ class ControllerWebSystem extends Controller ]); } - public function showThemes($request, $response, $args) + public function showThemes(Request $request, Response $response, $args) { $navigation = new Navigation(); $mainNavigation = $navigation->getMainNavigation( @@ -101,7 +103,7 @@ class ControllerWebSystem extends Controller ]); } - public function showPlugins($request, $response, $args) + public function showPlugins(Request $request, Response $response, $args) { $navigation = new Navigation(); $mainNavigation = $navigation->getMainNavigation( @@ -152,7 +154,7 @@ class ControllerWebSystem extends Controller ]); } - public function showLicense($request, $response, $args) + public function showLicense(Request $request, Response $response, $args) { $navigation = new Navigation(); $mainNavigation = $navigation->getMainNavigation( @@ -192,7 +194,7 @@ class ControllerWebSystem extends Controller ]); } - public function showAccount($request, $response, $args) + public function showAccount(Request $request, Response $response, $args) { $navigation = new Navigation(); $mainNavigation = $navigation->getMainNavigation( @@ -230,7 +232,7 @@ class ControllerWebSystem extends Controller ]); } - public function showUsers($request, $response, $args) + public function showUsers(Request $request, Response $response, $args) { $navigation = new Navigation(); $mainNavigation = $navigation->getMainNavigation( @@ -274,7 +276,7 @@ class ControllerWebSystem extends Controller ]); } - public function showUser($request, $response, $args) + public function showUser(Request $request, Response $response, $args) { $navigation = new Navigation(); $mainNavigation = $navigation->getMainNavigation( @@ -316,7 +318,7 @@ class ControllerWebSystem extends Controller ]); } - public function newUser($request, $response, $args) + public function newUser(Request $request, Response $response, $args) { $navigation = new Navigation(); $mainNavigation = $navigation->getMainNavigation( @@ -345,24 +347,37 @@ class ControllerWebSystem extends Controller ]); } - -/* - public function showBlank($request, $response, $args) + public function blankSystemPage(Request $request, Response $response, $args) { - $user = new User(); - $settings = $this->c->get('settings'); - $route = $request->getAttribute('route'); - $navigation = $this->getMainNavigation(); + $navigation = new Navigation(); + $mainNavigation = $navigation->getMainNavigation( + $userrole = $request->getAttribute('c_userrole'), + $acl = $this->c->get('acl'), + $urlinfo = $this->c->get('urlinfo'), + $editor = $this->settings['editor'] + ); + $userrole = $request->getAttribute('c_userrole'); + $acl = $this->c->get('acl'); + $urlinfo = $this->c->get('urlinfo'); + $editor = $this->settings['editor']; - $content = '

Hello

I am the showBlank method from the settings controller

In most cases I have been called from a plugin. But if you see this content, then the plugin does not work or has forgotten to inject its own content.

'; + $systemNavigation = $navigation->getSystemNavigation( + $userrole = $request->getAttribute('c_userrole'), + $acl = $this->c->get('acl'), + $urlinfo = $this->c->get('urlinfo'), + $dispatcher = $this->c->get('dispatcher') + ); - return $this->render($response, 'settings/blank.twig', array( - 'settings' => $settings, - 'acl' => $this->c->acl, - 'navigation' => $navigation, - 'content' => $content, - 'route' => $route->getName() - )); - } -*/ + return $this->c->get('view')->render($response, 'layouts/layoutSystemBlank.twig', [ + 'settings' => $this->settings, + 'mainnavi' => $mainNavigation, + 'systemnavi' => $systemNavigation, + 'jsdata' => [ + 'settings' => $this->settings, + 'labels' => $this->c->get('translations'), + 'urlinfo' => $this->c->get('urlinfo'), + 'acl' => $this->c->get('acl'), + ] + ]); + } } \ No newline at end of file diff --git a/system/typemill/Models/Content.php b/system/typemill/Models/Content.php index c54258a..254d925 100644 --- a/system/typemill/Models/Content.php +++ b/system/typemill/Models/Content.php @@ -113,22 +113,31 @@ class Content return $this->storage->getError(); } - public function deletePage($item) + public function deletePage($item, $result = NULL) { $extensions = ['.md', '.txt', '.yaml']; - $result = true; + if($item->elementType == 'folder' && isset($item->folderContent) && is_array($item->folderContent)) + { + foreach($item->folderContent as $content) + { + $result = $this->deletePage($content); + + if($result !== true){ break; } + } + } + foreach($extensions as $extension) { $result = $this->storage->deleteFile('contentFolder', '', $item->pathWithoutType . $extension); } - if($result) + if($result !== true) { - return true; + return $this->storage->getError(); } - - return $this->storage->getError(); + + return true; } public function addDraftHtml($markdownArray) diff --git a/system/typemill/Models/Storage.php b/system/typemill/Models/Storage.php index f219cab..ae21407 100644 --- a/system/typemill/Models/Storage.php +++ b/system/typemill/Models/Storage.php @@ -37,6 +37,10 @@ class Storage protected $translationFolder = false; protected $systemSettings = false; + + protected $isReadable = []; + + protected $isWrtiable = []; public function __construct() { @@ -69,6 +73,19 @@ class Storage $this->translationFolder = $this->basepath . 'system' . DIRECTORY_SEPARATOR . 'typemill' . DIRECTORY_SEPARATOR . 'author' . DIRECTORY_SEPARATOR . 'translations' . DIRECTORY_SEPARATOR; $this->systemSettings = $this->basepath . 'system' . DIRECTORY_SEPARATOR . 'typemill' . DIRECTORY_SEPARATOR . 'settings'; + + $this->isWritable = [ + 'tmpFolder' => true, + 'originalFolder' => true, + 'liveFolder' => true, + 'thumbsFolder' => true, + 'customFolder' => true, + 'fileFolder' => true, + 'contentFolder' => true, + 'dataFolder' => true, + 'cacheFolder' => true, + 'settingsFolder' => true + ]; } public function getError() @@ -78,26 +95,31 @@ class Storage public function getFolderPath($location, $folder = NULL) { - # security: remove ../ from location - # security: make sure user does not write into basepath - # security: write only into certain folders - if(isset($this->$location)) { $path = rtrim($this->$location, DIRECTORY_SEPARATOR); $path .= DIRECTORY_SEPARATOR; - if($folder && $folder != '') + + # check if folder is no hack like "../" + if($folder && $folder != '' && preg_match('/^(?:[\/\\a-z0-9_-]|\.(?!\.))+$/iD', $folder)) { $folder = trim($folder, DIRECTORY_SEPARATOR); $path .= $folder . DIRECTORY_SEPARATOR; } -# echo '
';
-#			echo $path;
+			elseif($location == 'basepath')
+			{
+				# do not allow direct access to basepath files
+
+				$this->error = "Access to basepath is not allowed.";
+				
+				return false;
+			}
 
 			return $path;
 		}
 
 		$this->error = "We could not find a folderPath for $location";
+		
 		return false;
 	}
 
@@ -152,7 +174,7 @@ class Storage
 	{
 		if($this->checkFile($location, $folder, $filename))
 		{
-			$filepath = $this->getFolderPath($location) . $folder . DIRECTORY_SEPARATOR . $filename;
+			$filepath = $this->getFolderPath($location, $folder) . $filename;
 
 			$fileContent = file_get_contents($filepath);
 		
@@ -184,6 +206,13 @@ class Storage
 
 	public function writeFile($location, $folder, $filename, $data, $method = NULL)
 	{
+		if(!isset($this->isWritable[$location]))
+		{
+			$this->error = "It is not allowed to write into $location";
+
+			return false;
+		}
+
 		# CLEAN EVERYTHING UP FUNCTION
 		$folder 	= trim($folder, DIRECTORY_SEPARATOR);
 		$folder 	= ($folder == '') ? '' : $folder . DIRECTORY_SEPARATOR;
@@ -197,8 +226,8 @@ class Storage
 			}
 		}
 
-		$filepath = $this->getFolderPath($location) . $folder . $filename;
-			
+		$filepath = $this->getFolderPath($location, $folder) . $filename;
+
 		$openfile = @fopen($filepath, "w");
 		if(!$openfile)
 		{
@@ -228,6 +257,13 @@ class Storage
 
 	public function renameFile($location, $folder, $oldname, $newname)
 	{
+		if(!isset($this->isWritable[$location]))
+		{
+			$this->error = "It is not allowed to write into $location";
+
+			return false;
+		}
+
 		$folder = trim($folder, DIRECTORY_SEPARATOR);
 
 		$oldFilePath = $this->getFolderPath($location) . $folder . DIRECTORY_SEPARATOR . $oldname;
@@ -249,12 +285,47 @@ class Storage
 		return true;
 	}
 
+	public function deleteFolder($location, $folder, $filename)
+	{
+		if(!isset($this->isWritable[$location]))
+		{
+			$this->error = "It is not allowed to write into $location";
+
+			return false;
+		}
+
+		$filepath = $this->getFolderPath($location, $folder) . $filename;
+
+		if(is_dir($filepath))
+		{
+			if(rmdir($dir))
+			{
+				return true;
+			}
+
+			$this->error = "We found the folder but could not delete $filepath";
+
+			return false;
+		}
+		
+		$this->error = "The path $filepath is not a folder.";
+
+		return false;
+	}
+
 	public function deleteFile($location, $folder, $filename)
 	{
+		if(!isset($this->isWritable[$location]))
+		{
+			$this->error = "It is not allowed to write into $location";
+
+			return false;
+		}
+
 		if($this->checkFile($location, $folder, $filename))
 		{
 			$filepath = $this->getFolderPath($location) . $folder . DIRECTORY_SEPARATOR . $filename;
-
+	
 			if(unlink($filepath))
 			{
 				return true;
@@ -329,6 +400,13 @@ class Storage
 
 	public function updateYaml($location, $folder, $filename, $contentArray)
 	{
+		if(!isset($this->isWritable[$location]))
+		{
+			$this->error = "It is not allowed to write into $location";
+
+			return false;
+		}
+
 		$yaml = \Symfony\Component\Yaml\Yaml::dump($contentArray,6);
 		if($this->writeFile($location, $folder, $filename, $yaml))
 		{
diff --git a/system/typemill/Static/Plugins.php b/system/typemill/Static/Plugins.php
index 9c631bb..6273314 100644
--- a/system/typemill/Static/Plugins.php
+++ b/system/typemill/Static/Plugins.php
@@ -45,28 +45,16 @@ class Plugins
 		{
 			# add the routes
 			$pluginRoutes = $className::addNewRoutes();
-			
-			# multi-dimensional or simple array of routes
-			if(isset($pluginRoutes[0]))
+
+			foreach($pluginRoutes as $pluginRoute)
 			{
-				# if they are properly formatted, add them to routes array
-				foreach($pluginRoutes as $pluginRoute)
+				if(self::checkRouteArray($routes,$pluginRoute))
 				{
-					if(self::checkRouteArray($routes,$pluginRoute))
-					{
-						$pluginRoute['route'] 	= strtolower($pluginRoute['route']);
-						$routes[] 				= $pluginRoute;
-					}
+					$routeType  			= (substr($pluginRoute['route'], 0,5) == '/api/') ? 'api' : 'web';
+					$pluginRoute['route'] 	= strtolower($pluginRoute['route']);
+					$routes[$routeType][] 	= $pluginRoute;
 				}
-			}
-			elseif(is_array($routes))
-			{
-				if(self::checkRouteArray($routes,$pluginRoutes))
-				{
-					$pluginRoutes['route'] 		= strtolower($pluginRoutes['route']);
-					$routes[] 					= $pluginRoutes;
-				}
-			}
+			}			
 		}
 		
 		return $routes;
@@ -113,7 +101,9 @@ class Plugins
 		if( 
 			isset($route['httpMethod']) AND in_array($route['httpMethod'], array('get','post','put','delete','head','patch','options'))
 			AND isset($route['route']) AND is_string($route['route'])
-			AND isset($route['class']) AND is_string($route['class']))
+			AND isset($route['class']) AND is_string($route['class'])
+			AND isset($route['name']) AND is_string($route['name'])
+		)
 		{
 			return true;
 		}
diff --git a/system/typemill/author/js/vue-publisher.js b/system/typemill/author/js/vue-publisher.js
index a4694c2..12480d0 100644
--- a/system/typemill/author/js/vue-publisher.js
+++ b/system/typemill/author/js/vue-publisher.js
@@ -265,7 +265,8 @@ const publisher = Vue.createApp({
 			{
 				if(error.response)
 				{
-					alert(error.response);
+					self.message = error.response.data.message;
+					self.messageClass = "bg-rose-500";
 				}
 			});
 		},
@@ -301,7 +302,8 @@ const publisher = Vue.createApp({
 			{
 				if(error.response)
 				{
-					alert(error.response);
+					self.message = error.response.data.message;
+					self.messageClass = "bg-rose-500";
 				}
 			});
 		},
@@ -326,7 +328,8 @@ const publisher = Vue.createApp({
 			{
 				if(error.response)
 				{
-					alert(error.response);
+					self.message = error.response.data.message;
+					self.messageClass = "bg-rose-500";
 				}
 			});
 		},
@@ -356,8 +359,10 @@ const publisher = Vue.createApp({
 			{
 				if(error.response)
 				{
-					alert(error.response);
-				}				
+					self.showModal = false;
+					self.message = error.response.data.message;
+					self.messageClass = "bg-rose-500";
+				}
 			});
 		},
 	},
diff --git a/system/typemill/author/layouts/layoutSystem.twig b/system/typemill/author/layouts/layoutSystem.twig
index 8fd5f50..54a0b12 100644
--- a/system/typemill/author/layouts/layoutSystem.twig
+++ b/system/typemill/author/layouts/layoutSystem.twig
@@ -43,10 +43,6 @@
 			
 		
 		
-		
-
 
 
 		
+		
+		
+		
+		
+		
+		
+		
+		
+
+		{% block javascript %}{% endblock %}
+
+		{{ assets.renderJS() }}
+
+		
+	
+	
+
\ No newline at end of file
diff --git a/system/typemill/routes/api.php b/system/typemill/routes/api.php
index 1daa3ba..92d334c 100644
--- a/system/typemill/routes/api.php
+++ b/system/typemill/routes/api.php
@@ -82,4 +82,26 @@ $app->group('/api/v1', function (RouteCollectorProxy $group) use ($acl) {
 	$group->get('/meta', ControllerApiAuthorMeta::class . ':getMeta')->setName('api.meta.get')->add(new ApiAuthorization($acl, 'mycontent', 'view'));
 	$group->post('/meta', ControllerApiAuthorMeta::class . ':updateMeta')->setName('api.metadata.update')->add(new ApiAuthorization($acl, 'mycontent', 'update'));
 
-})->add(new ApiAuthentication());
\ No newline at end of file
+})->add(new ApiAuthentication());
+
+# api-routes from plugins
+foreach($routes['api'] as $pluginRoute)
+{	
+	$method 	= $pluginRoute['httpMethod'] ?? false;
+	$route		= $pluginRoute['route'] ?? false;
+	$class		= $pluginRoute['class'] ?? false;
+	$name 		= $pluginRoute['name'] ?? false;
+	$resource 	= $pluginRoute['resource'] ?? false;
+	$privilege 	= $pluginRoute['privilege'] ?? false;
+
+	if($resources && $privilege)
+	{
+		# protected api requires authentication and authorization
+		$app->{$method}($route, $class)->setName($name)->add(new ApiAuthorization($acl, $resource, $privilege))->add(new ApiAuthentication());
+	}
+	else
+	{
+		# public api routes
+		$app->{$method}($route, $class)->setName($name);
+	}
+}
diff --git a/system/typemill/routes/web.php b/system/typemill/routes/web.php
index eed8914..ed2e5c6 100644
--- a/system/typemill/routes/web.php
+++ b/system/typemill/routes/web.php
@@ -54,34 +54,24 @@ $app->redirect('/tm/', $routeParser->urlFor('auth.show'), 302);
 # downloads
 $app->get('/media/files[/{params:.*}]', ControllerWebDownload::class . ':download')->setName('download.file');
 
-foreach($routes as $pluginRoute)
+# web-routes from plugins
+foreach($routes['web'] as $pluginRoute)
 {	
-	$method 	= $pluginRoute['httpMethod'];
-	$route		= $pluginRoute['route'];
-	$class		= $pluginRoute['class'];
-	# $resource 	= isset($pluginRoute['resource']) ? $pluginRoute['resource'] : NULL;
-	# $privilege 	= isset($pluginRoute['privilege']) ? $pluginRoute['privilege'] : NULL;
+	$method 	= $pluginRoute['httpMethod'] ?? false;
+	$route		= $pluginRoute['route'] ?? false;
+	$class		= $pluginRoute['class'] ?? false;
+	$name 		= $pluginRoute['name'] ?? false;
+	$resource 	= $pluginRoute['resource'] ?? false;
+	$privilege 	= $pluginRoute['privilege'] ?? false;
 
-#	echo '
'; -# echo 'method: ' . $method . ' -> route: ' . $route . ' -> class: ' . $class; - - if(isset($pluginRoute['name'])) + if($resources && $privilege) { -# $app->{$method}($route, $class)->setName($pluginRoute['name'])->add(new accessMiddleware($container['router'], $container['acl'], $resource, $privilege)); - $app->{$method}($route, $class)->setName($pluginRoute['name']); + $app->{$method}($route, $class)->setName($name)->add(new WebAuthorization($routeParser, $acl, $resource, $privilege))->add(new WebRedirectIfUnauthenticated($routeParser)); } else { -# $app->{$method}($route, $class)->add(new accessMiddleware($container['router'], $container['acl'], $resource, $privilege)); - $app->{$method}($route, $class); + $app->{$method}($route, $class)->setName($name); } - - # if api and if authorization - # ->add(new ApiAuthorization($acl, 'account', 'view')); - - # if web and if authorization - # ->add(new WebAuthorization($acl, 'account', 'view')); } -# die(); -# website + $app->get('/[{route:.*}]', ControllerWebFrontend::class . ':index')->setName('home'); \ No newline at end of file