diff --git a/Attachments/Anatomy-of-a-theme/Orchard.Theme.CustomLayoutMachine.1.0.nupkg b/Attachments/Anatomy-of-a-theme/Orchard.Theme.CustomLayoutMachine.1.0.nupkg new file mode 100644 index 00000000..f49cf7ad Binary files /dev/null and b/Attachments/Anatomy-of-a-theme/Orchard.Theme.CustomLayoutMachine.1.0.nupkg differ diff --git a/Attachments/Anatomy-of-a-theme/Orchard.Themes.CustomLayoutMachine.1.0.nupkg b/Attachments/Anatomy-of-a-theme/Orchard.Themes.CustomLayoutMachine.1.0.nupkg new file mode 100644 index 00000000..0c58251a Binary files /dev/null and b/Attachments/Anatomy-of-a-theme/Orchard.Themes.CustomLayoutMachine.1.0.nupkg differ diff --git a/Attachments/Anatomy-of-a-theme/OverridingWidgetRendering.PNG b/Attachments/Anatomy-of-a-theme/OverridingWidgetRendering.PNG new file mode 100644 index 00000000..d2dd0925 Binary files /dev/null and b/Attachments/Anatomy-of-a-theme/OverridingWidgetRendering.PNG differ diff --git a/Attachments/Anatomy-of-a-theme/TheThemeMachine.PNG b/Attachments/Anatomy-of-a-theme/TheThemeMachine.PNG new file mode 100644 index 00000000..995544f6 Binary files /dev/null and b/Attachments/Anatomy-of-a-theme/TheThemeMachine.PNG differ diff --git a/Attachments/Anatomy-of-a-theme/TheThemeMachineZoneScreenshot.PNG b/Attachments/Anatomy-of-a-theme/TheThemeMachineZoneScreenshot.PNG new file mode 100644 index 00000000..29e5f6ec Binary files /dev/null and b/Attachments/Anatomy-of-a-theme/TheThemeMachineZoneScreenshot.PNG differ diff --git a/Attachments/Anatomy-of-a-theme/WidgetZonePreview.PNG b/Attachments/Anatomy-of-a-theme/WidgetZonePreview.PNG new file mode 100644 index 00000000..cb033ea7 Binary files /dev/null and b/Attachments/Anatomy-of-a-theme/WidgetZonePreview.PNG differ diff --git a/Attachments/Basic-Orchard-Concepts/Adminpanel.PNG b/Attachments/Basic-Orchard-Concepts/Adminpanel.PNG new file mode 100644 index 00000000..d4db3031 Binary files /dev/null and b/Attachments/Basic-Orchard-Concepts/Adminpanel.PNG differ diff --git a/Attachments/Basic-Orchard-Concepts/ContentParts.PNG b/Attachments/Basic-Orchard-Concepts/ContentParts.PNG new file mode 100644 index 00000000..4b508d0a Binary files /dev/null and b/Attachments/Basic-Orchard-Concepts/ContentParts.PNG differ diff --git a/Attachments/Basic-Orchard-Concepts/Features.PNG b/Attachments/Basic-Orchard-Concepts/Features.PNG new file mode 100644 index 00000000..d893e3b0 Binary files /dev/null and b/Attachments/Basic-Orchard-Concepts/Features.PNG differ diff --git a/Attachments/Basic-Orchard-Concepts/FrontEnd.PNG b/Attachments/Basic-Orchard-Concepts/FrontEnd.PNG new file mode 100644 index 00000000..7cec2169 Binary files /dev/null and b/Attachments/Basic-Orchard-Concepts/FrontEnd.PNG differ diff --git a/Attachments/Basic-Orchard-Concepts/Modules.PNG b/Attachments/Basic-Orchard-Concepts/Modules.PNG new file mode 100644 index 00000000..63749406 Binary files /dev/null and b/Attachments/Basic-Orchard-Concepts/Modules.PNG differ diff --git a/Attachments/Basic-Orchard-Concepts/Permissions.PNG b/Attachments/Basic-Orchard-Concepts/Permissions.PNG new file mode 100644 index 00000000..533a6422 Binary files /dev/null and b/Attachments/Basic-Orchard-Concepts/Permissions.PNG differ diff --git a/Attachments/Basic-Orchard-Concepts/Setup.PNG b/Attachments/Basic-Orchard-Concepts/Setup.PNG new file mode 100644 index 00000000..f3f38b3b Binary files /dev/null and b/Attachments/Basic-Orchard-Concepts/Setup.PNG differ diff --git a/Attachments/Basic-Orchard-Concepts/ThemeComparison.png b/Attachments/Basic-Orchard-Concepts/ThemeComparison.png new file mode 100644 index 00000000..c8e2043e Binary files /dev/null and b/Attachments/Basic-Orchard-Concepts/ThemeComparison.png differ diff --git a/Attachments/Basic-Orchard-Concepts/Widget.PNG b/Attachments/Basic-Orchard-Concepts/Widget.PNG new file mode 100644 index 00000000..766f2853 Binary files /dev/null and b/Attachments/Basic-Orchard-Concepts/Widget.PNG differ diff --git a/Attachments/Building-a-hello-world-module/HelloWorld.PNG b/Attachments/Building-a-hello-world-module/HelloWorld.PNG new file mode 100644 index 00000000..8f199909 Binary files /dev/null and b/Attachments/Building-a-hello-world-module/HelloWorld.PNG differ diff --git a/Attachments/Building-a-hello-world-module/HelloWorld.zip b/Attachments/Building-a-hello-world-module/HelloWorld.zip new file mode 100644 index 00000000..44fcdeda Binary files /dev/null and b/Attachments/Building-a-hello-world-module/HelloWorld.zip differ diff --git a/Attachments/Command-line-scaffolding/CodeGenerationFeature.PNG b/Attachments/Command-line-scaffolding/CodeGenerationFeature.PNG new file mode 100644 index 00000000..4e9369d8 Binary files /dev/null and b/Attachments/Command-line-scaffolding/CodeGenerationFeature.PNG differ diff --git a/Attachments/Creating-1-n-and-n-n-relations/AddressDiagram.PNG b/Attachments/Creating-1-n-and-n-n-relations/AddressDiagram.PNG new file mode 100644 index 00000000..d7b9bdae Binary files /dev/null and b/Attachments/Creating-1-n-and-n-n-relations/AddressDiagram.PNG differ diff --git a/Attachments/Creating-1-n-and-n-n-relations/CreateCustomer.PNG b/Attachments/Creating-1-n-and-n-n-relations/CreateCustomer.PNG new file mode 100644 index 00000000..09105001 Binary files /dev/null and b/Attachments/Creating-1-n-and-n-n-relations/CreateCustomer.PNG differ diff --git a/Attachments/Creating-1-n-and-n-n-relations/CustomerFrontEnd.PNG b/Attachments/Creating-1-n-and-n-n-relations/CustomerFrontEnd.PNG new file mode 100644 index 00000000..5af6aa42 Binary files /dev/null and b/Attachments/Creating-1-n-and-n-n-relations/CustomerFrontEnd.PNG differ diff --git a/Attachments/Creating-1-n-and-n-n-relations/CustomerType.PNG b/Attachments/Creating-1-n-and-n-n-relations/CustomerType.PNG new file mode 100644 index 00000000..86f2fcf8 Binary files /dev/null and b/Attachments/Creating-1-n-and-n-n-relations/CustomerType.PNG differ diff --git a/Attachments/Creating-1-n-and-n-n-relations/CustomerTypeAddress.PNG b/Attachments/Creating-1-n-and-n-n-relations/CustomerTypeAddress.PNG new file mode 100644 index 00000000..e1c6931f Binary files /dev/null and b/Attachments/Creating-1-n-and-n-n-relations/CustomerTypeAddress.PNG differ diff --git a/Attachments/Creating-1-n-and-n-n-relations/CustomerWithRewards.PNG b/Attachments/Creating-1-n-and-n-n-relations/CustomerWithRewards.PNG new file mode 100644 index 00000000..0c788845 Binary files /dev/null and b/Attachments/Creating-1-n-and-n-n-relations/CustomerWithRewards.PNG differ diff --git a/Attachments/Creating-1-n-and-n-n-relations/CustomerWithSponsor.PNG b/Attachments/Creating-1-n-and-n-n-relations/CustomerWithSponsor.PNG new file mode 100644 index 00000000..0c7eadc2 Binary files /dev/null and b/Attachments/Creating-1-n-and-n-n-relations/CustomerWithSponsor.PNG differ diff --git a/Attachments/Creating-1-n-and-n-n-relations/EditCustomerRewards.PNG b/Attachments/Creating-1-n-and-n-n-relations/EditCustomerRewards.PNG new file mode 100644 index 00000000..ad8ecd0e Binary files /dev/null and b/Attachments/Creating-1-n-and-n-n-relations/EditCustomerRewards.PNG differ diff --git a/Attachments/Creating-1-n-and-n-n-relations/EditCustomerWithSponsor.PNG b/Attachments/Creating-1-n-and-n-n-relations/EditCustomerWithSponsor.PNG new file mode 100644 index 00000000..f982811d Binary files /dev/null and b/Attachments/Creating-1-n-and-n-n-relations/EditCustomerWithSponsor.PNG differ diff --git a/Attachments/Creating-1-n-and-n-n-relations/Orchard.Module.RelationSample.0.5.0.nupkg b/Attachments/Creating-1-n-and-n-n-relations/Orchard.Module.RelationSample.0.5.0.nupkg new file mode 100644 index 00000000..c22a7da7 Binary files /dev/null and b/Attachments/Creating-1-n-and-n-n-relations/Orchard.Module.RelationSample.0.5.0.nupkg differ diff --git a/Attachments/Creating-1-n-and-n-n-relations/RewardDiagram.PNG b/Attachments/Creating-1-n-and-n-n-relations/RewardDiagram.PNG new file mode 100644 index 00000000..893dfaef Binary files /dev/null and b/Attachments/Creating-1-n-and-n-n-relations/RewardDiagram.PNG differ diff --git a/Attachments/Creating-a-custom-field-type/ConfiguringTheField.PNG b/Attachments/Creating-a-custom-field-type/ConfiguringTheField.PNG new file mode 100644 index 00000000..7186c389 Binary files /dev/null and b/Attachments/Creating-a-custom-field-type/ConfiguringTheField.PNG differ diff --git a/Attachments/Creating-a-custom-field-type/CustomFields-0.5.0.zip b/Attachments/Creating-a-custom-field-type/CustomFields-0.5.0.zip new file mode 100644 index 00000000..d7cfe60c Binary files /dev/null and b/Attachments/Creating-a-custom-field-type/CustomFields-0.5.0.zip differ diff --git a/Attachments/Creating-a-custom-field-type/CustomFields.zip b/Attachments/Creating-a-custom-field-type/CustomFields.zip new file mode 100644 index 00000000..2fc7ee34 Binary files /dev/null and b/Attachments/Creating-a-custom-field-type/CustomFields.zip differ diff --git a/Attachments/Creating-a-custom-field-type/Dinner.PNG b/Attachments/Creating-a-custom-field-type/Dinner.PNG new file mode 100644 index 00000000..d4dc717d Binary files /dev/null and b/Attachments/Creating-a-custom-field-type/Dinner.PNG differ diff --git a/Attachments/Creating-a-custom-field-type/EventEditor.PNG b/Attachments/Creating-a-custom-field-type/EventEditor.PNG new file mode 100644 index 00000000..3d557455 Binary files /dev/null and b/Attachments/Creating-a-custom-field-type/EventEditor.PNG differ diff --git a/Attachments/Creating-a-module-with-a-simple-text-editor/01_NewWebSite.PNG b/Attachments/Creating-a-module-with-a-simple-text-editor/01_NewWebSite.PNG new file mode 100644 index 00000000..d651bbf0 Binary files /dev/null and b/Attachments/Creating-a-module-with-a-simple-text-editor/01_NewWebSite.PNG differ diff --git a/Attachments/Creating-a-module-with-a-simple-text-editor/02_NewSiteSettings.PNG b/Attachments/Creating-a-module-with-a-simple-text-editor/02_NewSiteSettings.PNG new file mode 100644 index 00000000..8d656c85 Binary files /dev/null and b/Attachments/Creating-a-module-with-a-simple-text-editor/02_NewSiteSettings.PNG differ diff --git a/Attachments/Creating-a-module-with-a-simple-text-editor/03_AddWebPIFeed.PNG b/Attachments/Creating-a-module-with-a-simple-text-editor/03_AddWebPIFeed.PNG new file mode 100644 index 00000000..64546393 Binary files /dev/null and b/Attachments/Creating-a-module-with-a-simple-text-editor/03_AddWebPIFeed.PNG differ diff --git a/Attachments/Creating-a-module-with-a-simple-text-editor/04_WebPIOrchard.PNG b/Attachments/Creating-a-module-with-a-simple-text-editor/04_WebPIOrchard.PNG new file mode 100644 index 00000000..5bfa0f08 Binary files /dev/null and b/Attachments/Creating-a-module-with-a-simple-text-editor/04_WebPIOrchard.PNG differ diff --git a/Attachments/Creating-a-module-with-a-simple-text-editor/05_WebPIInstall.PNG b/Attachments/Creating-a-module-with-a-simple-text-editor/05_WebPIInstall.PNG new file mode 100644 index 00000000..ffcbf071 Binary files /dev/null and b/Attachments/Creating-a-module-with-a-simple-text-editor/05_WebPIInstall.PNG differ diff --git a/Attachments/Creating-a-module-with-a-simple-text-editor/07_OrchardCLI.PNG b/Attachments/Creating-a-module-with-a-simple-text-editor/07_OrchardCLI.PNG new file mode 100644 index 00000000..899032bc Binary files /dev/null and b/Attachments/Creating-a-module-with-a-simple-text-editor/07_OrchardCLI.PNG differ diff --git a/Attachments/Creating-a-module-with-a-simple-text-editor/08_OurProductEditor.PNG b/Attachments/Creating-a-module-with-a-simple-text-editor/08_OurProductEditor.PNG new file mode 100644 index 00000000..b37f2590 Binary files /dev/null and b/Attachments/Creating-a-module-with-a-simple-text-editor/08_OurProductEditor.PNG differ diff --git a/Attachments/Creating-a-module-with-a-simple-text-editor/Orchard.Module.SimpleCommerce.0.5.0.nupkg b/Attachments/Creating-a-module-with-a-simple-text-editor/Orchard.Module.SimpleCommerce.0.5.0.nupkg new file mode 100644 index 00000000..50f56078 Binary files /dev/null and b/Attachments/Creating-a-module-with-a-simple-text-editor/Orchard.Module.SimpleCommerce.0.5.0.nupkg differ diff --git a/Attachments/Creating-a-module-with-a-simple-text-editor/s_02_NewSiteSettings.png b/Attachments/Creating-a-module-with-a-simple-text-editor/s_02_NewSiteSettings.png new file mode 100644 index 00000000..9a8f76a8 Binary files /dev/null and b/Attachments/Creating-a-module-with-a-simple-text-editor/s_02_NewSiteSettings.png differ diff --git a/Attachments/Creating-a-module-with-a-simple-text-editor/s_03_AddWebPIFeed.png b/Attachments/Creating-a-module-with-a-simple-text-editor/s_03_AddWebPIFeed.png new file mode 100644 index 00000000..0500d99b Binary files /dev/null and b/Attachments/Creating-a-module-with-a-simple-text-editor/s_03_AddWebPIFeed.png differ diff --git a/Attachments/Creating-a-module-with-a-simple-text-editor/s_05_WebPIInstall.png b/Attachments/Creating-a-module-with-a-simple-text-editor/s_05_WebPIInstall.png new file mode 100644 index 00000000..39f6c40b Binary files /dev/null and b/Attachments/Creating-a-module-with-a-simple-text-editor/s_05_WebPIInstall.png differ diff --git a/Attachments/Creating-a-module-with-a-simple-text-editor/s_07_OrchardCLI.png b/Attachments/Creating-a-module-with-a-simple-text-editor/s_07_OrchardCLI.png new file mode 100644 index 00000000..9fc5060d Binary files /dev/null and b/Attachments/Creating-a-module-with-a-simple-text-editor/s_07_OrchardCLI.png differ diff --git a/Attachments/Creating-a-module-with-a-simple-text-editor/s_08_OurProductEditor.png b/Attachments/Creating-a-module-with-a-simple-text-editor/s_08_OurProductEditor.png new file mode 100644 index 00000000..104f2168 Binary files /dev/null and b/Attachments/Creating-a-module-with-a-simple-text-editor/s_08_OurProductEditor.png differ diff --git a/Attachments/Creating-global-ready-applications/LocalizationChooseFile.PNG b/Attachments/Creating-global-ready-applications/LocalizationChooseFile.PNG new file mode 100644 index 00000000..553d8946 Binary files /dev/null and b/Attachments/Creating-global-ready-applications/LocalizationChooseFile.PNG differ diff --git a/Attachments/Creating-global-ready-applications/LocalizationDelete.PNG b/Attachments/Creating-global-ready-applications/LocalizationDelete.PNG new file mode 100644 index 00000000..af7f7866 Binary files /dev/null and b/Attachments/Creating-global-ready-applications/LocalizationDelete.PNG differ diff --git a/Attachments/Creating-global-ready-applications/LocalizationEdit.PNG b/Attachments/Creating-global-ready-applications/LocalizationEdit.PNG new file mode 100644 index 00000000..d2dccba3 Binary files /dev/null and b/Attachments/Creating-global-ready-applications/LocalizationEdit.PNG differ diff --git a/Attachments/Creating-global-ready-applications/LocalizationStrings.PNG b/Attachments/Creating-global-ready-applications/LocalizationStrings.PNG new file mode 100644 index 00000000..f8582df8 Binary files /dev/null and b/Attachments/Creating-global-ready-applications/LocalizationStrings.PNG differ diff --git a/Attachments/Creating-lists/AdingWidget.PNG b/Attachments/Creating-lists/AdingWidget.PNG new file mode 100644 index 00000000..3f62966a Binary files /dev/null and b/Attachments/Creating-lists/AdingWidget.PNG differ diff --git a/Attachments/Creating-lists/BookReviewContentType.PNG b/Attachments/Creating-lists/BookReviewContentType.PNG new file mode 100644 index 00000000..1f1f5daf Binary files /dev/null and b/Attachments/Creating-lists/BookReviewContentType.PNG differ diff --git a/Attachments/Creating-lists/BookReviewDetails.PNG b/Attachments/Creating-lists/BookReviewDetails.PNG new file mode 100644 index 00000000..cab55745 Binary files /dev/null and b/Attachments/Creating-lists/BookReviewDetails.PNG differ diff --git a/Attachments/Creating-lists/BookReviewList.PNG b/Attachments/Creating-lists/BookReviewList.PNG new file mode 100644 index 00000000..cdb6d7ac Binary files /dev/null and b/Attachments/Creating-lists/BookReviewList.PNG differ diff --git a/Attachments/Creating-lists/BookReviewListNoPagination.PNG b/Attachments/Creating-lists/BookReviewListNoPagination.PNG new file mode 100644 index 00000000..91dc74d0 Binary files /dev/null and b/Attachments/Creating-lists/BookReviewListNoPagination.PNG differ diff --git a/Attachments/Creating-lists/FeaturedReviewsWidget.PNG b/Attachments/Creating-lists/FeaturedReviewsWidget.PNG new file mode 100644 index 00000000..23e81f38 Binary files /dev/null and b/Attachments/Creating-lists/FeaturedReviewsWidget.PNG differ diff --git a/Attachments/Creating-lists/HomePageWithBookReviews.PNG b/Attachments/Creating-lists/HomePageWithBookReviews.PNG new file mode 100644 index 00000000..c8b98de2 Binary files /dev/null and b/Attachments/Creating-lists/HomePageWithBookReviews.PNG differ diff --git a/Attachments/Creating-lists/NewBookReviewMenuEntry.PNG b/Attachments/Creating-lists/NewBookReviewMenuEntry.PNG new file mode 100644 index 00000000..21bbab33 Binary files /dev/null and b/Attachments/Creating-lists/NewBookReviewMenuEntry.PNG differ diff --git a/Attachments/Creating-lists/NewList.PNG b/Attachments/Creating-lists/NewList.PNG new file mode 100644 index 00000000..25eec29a Binary files /dev/null and b/Attachments/Creating-lists/NewList.PNG differ diff --git a/Attachments/Creating-lists/ResizedEditor.png b/Attachments/Creating-lists/ResizedEditor.png new file mode 100644 index 00000000..120b0ecd Binary files /dev/null and b/Attachments/Creating-lists/ResizedEditor.png differ diff --git a/Attachments/Creating-lists/UnformattedList.PNG b/Attachments/Creating-lists/UnformattedList.PNG new file mode 100644 index 00000000..5531f3d7 Binary files /dev/null and b/Attachments/Creating-lists/UnformattedList.PNG differ diff --git a/Attachments/Customizing-the-default-theme/ThemeMachine_structure.PNG b/Attachments/Customizing-the-default-theme/ThemeMachine_structure.PNG new file mode 100644 index 00000000..1d4e7cb5 Binary files /dev/null and b/Attachments/Customizing-the-default-theme/ThemeMachine_structure.PNG differ diff --git a/Attachments/Deploying-Orchard-to-Windows-Azure/azure_module_project.png b/Attachments/Deploying-Orchard-to-Windows-Azure/azure_module_project.png new file mode 100644 index 00000000..0d8186f9 Binary files /dev/null and b/Attachments/Deploying-Orchard-to-Windows-Azure/azure_module_project.png differ diff --git a/Attachments/Deploying-Orchard-to-Windows-Azure/azure_module_solution.png b/Attachments/Deploying-Orchard-to-Windows-Azure/azure_module_solution.png new file mode 100644 index 00000000..a91b1229 Binary files /dev/null and b/Attachments/Deploying-Orchard-to-Windows-Azure/azure_module_solution.png differ diff --git a/Attachments/Deploying-Orchard-to-Windows-Azure/azure_module_source.png b/Attachments/Deploying-Orchard-to-Windows-Azure/azure_module_source.png new file mode 100644 index 00000000..671f8b5f Binary files /dev/null and b/Attachments/Deploying-Orchard-to-Windows-Azure/azure_module_source.png differ diff --git a/Attachments/Deploying-Orchard-to-Windows-Azure/azure_setup.png b/Attachments/Deploying-Orchard-to-Windows-Azure/azure_setup.png new file mode 100644 index 00000000..ce19a173 Binary files /dev/null and b/Attachments/Deploying-Orchard-to-Windows-Azure/azure_setup.png differ diff --git a/Attachments/Deploying-Orchard-to-Windows-Azure/azure_theme_solution.png b/Attachments/Deploying-Orchard-to-Windows-Azure/azure_theme_solution.png new file mode 100644 index 00000000..be83c670 Binary files /dev/null and b/Attachments/Deploying-Orchard-to-Windows-Azure/azure_theme_solution.png differ diff --git a/Attachments/Deploying-Orchard-to-Windows-Azure/azure_theme_source.png b/Attachments/Deploying-Orchard-to-Windows-Azure/azure_theme_source.png new file mode 100644 index 00000000..25ab0436 Binary files /dev/null and b/Attachments/Deploying-Orchard-to-Windows-Azure/azure_theme_source.png differ diff --git a/Attachments/Deploying-Orchard-to-Windows-Azure/developer_portal_deploy.png b/Attachments/Deploying-Orchard-to-Windows-Azure/developer_portal_deploy.png new file mode 100644 index 00000000..a270fa1d Binary files /dev/null and b/Attachments/Deploying-Orchard-to-Windows-Azure/developer_portal_deploy.png differ diff --git a/Attachments/Deploying-Orchard-to-Windows-Azure/developer_portal_deploy2.png b/Attachments/Deploying-Orchard-to-Windows-Azure/developer_portal_deploy2.png new file mode 100644 index 00000000..1112102e Binary files /dev/null and b/Attachments/Deploying-Orchard-to-Windows-Azure/developer_portal_deploy2.png differ diff --git a/Attachments/Deploying-Orchard-to-Windows-Azure/developer_portal_deploy3.png b/Attachments/Deploying-Orchard-to-Windows-Azure/developer_portal_deploy3.png new file mode 100644 index 00000000..96f40d50 Binary files /dev/null and b/Attachments/Deploying-Orchard-to-Windows-Azure/developer_portal_deploy3.png differ diff --git a/Attachments/Deploying-Orchard-to-Windows-Azure/developer_portal_home.png b/Attachments/Deploying-Orchard-to-Windows-Azure/developer_portal_home.png new file mode 100644 index 00000000..b1afd530 Binary files /dev/null and b/Attachments/Deploying-Orchard-to-Windows-Azure/developer_portal_home.png differ diff --git a/Attachments/Deploying-Orchard-to-Windows-Azure/developer_portal_sqlazure.png b/Attachments/Deploying-Orchard-to-Windows-Azure/developer_portal_sqlazure.png new file mode 100644 index 00000000..bdaacb19 Binary files /dev/null and b/Attachments/Deploying-Orchard-to-Windows-Azure/developer_portal_sqlazure.png differ diff --git a/Attachments/Deploying-Orchard-to-Windows-Azure/developer_portal_storage.png b/Attachments/Deploying-Orchard-to-Windows-Azure/developer_portal_storage.png new file mode 100644 index 00000000..4a5417b7 Binary files /dev/null and b/Attachments/Deploying-Orchard-to-Windows-Azure/developer_portal_storage.png differ diff --git a/Attachments/Deploying-Orchard-to-Windows-Azure/myazurestorage_delete.png b/Attachments/Deploying-Orchard-to-Windows-Azure/myazurestorage_delete.png new file mode 100644 index 00000000..4c9020a0 Binary files /dev/null and b/Attachments/Deploying-Orchard-to-Windows-Azure/myazurestorage_delete.png differ diff --git a/Attachments/Deploying-Orchard-to-Windows-Azure/sqlazure_create_db.png b/Attachments/Deploying-Orchard-to-Windows-Azure/sqlazure_create_db.png new file mode 100644 index 00000000..62532376 Binary files /dev/null and b/Attachments/Deploying-Orchard-to-Windows-Azure/sqlazure_create_db.png differ diff --git a/Attachments/Manually-installing-Orchard-zip-file/OpenSolution.PNG b/Attachments/Manually-installing-Orchard-zip-file/OpenSolution.PNG new file mode 100644 index 00000000..c94495da Binary files /dev/null and b/Attachments/Manually-installing-Orchard-zip-file/OpenSolution.PNG differ diff --git a/Attachments/Modifying-site-settings/SiteSettings.PNG b/Attachments/Modifying-site-settings/SiteSettings.PNG new file mode 100644 index 00000000..a388e8bf Binary files /dev/null and b/Attachments/Modifying-site-settings/SiteSettings.PNG differ diff --git a/Attachments/Optimizing-Performance-of-Orchard-with-Shared-Hosting/AppPoolRecycle.PNG b/Attachments/Optimizing-Performance-of-Orchard-with-Shared-Hosting/AppPoolRecycle.PNG new file mode 100644 index 00000000..2da4b3a9 Binary files /dev/null and b/Attachments/Optimizing-Performance-of-Orchard-with-Shared-Hosting/AppPoolRecycle.PNG differ diff --git a/Attachments/Setting-up-a-machine-key/IisManagerMachineKey.PNG b/Attachments/Setting-up-a-machine-key/IisManagerMachineKey.PNG new file mode 100644 index 00000000..823604b7 Binary files /dev/null and b/Attachments/Setting-up-a-machine-key/IisManagerMachineKey.PNG differ diff --git a/Attachments/Setting-up-a-machine-key/UncheckAutoMachineKey.PNG b/Attachments/Setting-up-a-machine-key/UncheckAutoMachineKey.PNG new file mode 100644 index 00000000..45e5d2dd Binary files /dev/null and b/Attachments/Setting-up-a-machine-key/UncheckAutoMachineKey.PNG differ diff --git a/Attachments/Upgrading-a-site-to-a-new-version-of-Orchard/AzureDeployConnectionString.PNG b/Attachments/Upgrading-a-site-to-a-new-version-of-Orchard/AzureDeployConnectionString.PNG new file mode 100644 index 00000000..443f0071 Binary files /dev/null and b/Attachments/Upgrading-a-site-to-a-new-version-of-Orchard/AzureDeployConnectionString.PNG differ diff --git a/Attachments/Upgrading-a-site-to-a-new-version-of-Orchard/AzureDeployNewPackage.PNG b/Attachments/Upgrading-a-site-to-a-new-version-of-Orchard/AzureDeployNewPackage.PNG new file mode 100644 index 00000000..2d0739df Binary files /dev/null and b/Attachments/Upgrading-a-site-to-a-new-version-of-Orchard/AzureDeployNewPackage.PNG differ diff --git a/Attachments/Upgrading-a-site-to-a-new-version-of-Orchard/AzureDeployNewPackageDialog.PNG b/Attachments/Upgrading-a-site-to-a-new-version-of-Orchard/AzureDeployNewPackageDialog.PNG new file mode 100644 index 00000000..eca99e3d Binary files /dev/null and b/Attachments/Upgrading-a-site-to-a-new-version-of-Orchard/AzureDeployNewPackageDialog.PNG differ diff --git a/Attachments/Upgrading-a-site-to-a-new-version-of-Orchard/Upgrade.From.1.0.zip b/Attachments/Upgrading-a-site-to-a-new-version-of-Orchard/Upgrade.From.1.0.zip new file mode 100644 index 00000000..c1936fa2 Binary files /dev/null and b/Attachments/Upgrading-a-site-to-a-new-version-of-Orchard/Upgrade.From.1.0.zip differ diff --git a/Attachments/Writing-a-content-part/Orchard.Module.Maps.1.0.0.nupkg b/Attachments/Writing-a-content-part/Orchard.Module.Maps.1.0.0.nupkg new file mode 100644 index 00000000..91e92b89 Binary files /dev/null and b/Attachments/Writing-a-content-part/Orchard.Module.Maps.1.0.0.nupkg differ diff --git a/Attachments/Writing-a-content-part/vs_sol_migration.PNG b/Attachments/Writing-a-content-part/vs_sol_migration.PNG new file mode 100644 index 00000000..73c1136b Binary files /dev/null and b/Attachments/Writing-a-content-part/vs_sol_migration.PNG differ diff --git a/Attachments/media-management/1.png b/Attachments/media-management/1.png new file mode 100644 index 00000000..9058c487 Binary files /dev/null and b/Attachments/media-management/1.png differ diff --git a/Attachments/media-management/10.png b/Attachments/media-management/10.png new file mode 100644 index 00000000..70969255 Binary files /dev/null and b/Attachments/media-management/10.png differ diff --git a/Attachments/media-management/10_s.png b/Attachments/media-management/10_s.png new file mode 100644 index 00000000..8d13609a Binary files /dev/null and b/Attachments/media-management/10_s.png differ diff --git a/Attachments/media-management/11.png b/Attachments/media-management/11.png new file mode 100644 index 00000000..53fc0949 Binary files /dev/null and b/Attachments/media-management/11.png differ diff --git a/Attachments/media-management/11_s.png b/Attachments/media-management/11_s.png new file mode 100644 index 00000000..fa1445c2 Binary files /dev/null and b/Attachments/media-management/11_s.png differ diff --git a/Attachments/media-management/12.png b/Attachments/media-management/12.png new file mode 100644 index 00000000..e8907e83 Binary files /dev/null and b/Attachments/media-management/12.png differ diff --git a/Attachments/media-management/12_s.png b/Attachments/media-management/12_s.png new file mode 100644 index 00000000..30a1cd30 Binary files /dev/null and b/Attachments/media-management/12_s.png differ diff --git a/Attachments/media-management/1_s.png b/Attachments/media-management/1_s.png new file mode 100644 index 00000000..49e8a069 Binary files /dev/null and b/Attachments/media-management/1_s.png differ diff --git a/Attachments/media-management/2.1.png b/Attachments/media-management/2.1.png new file mode 100644 index 00000000..0a9b2c09 Binary files /dev/null and b/Attachments/media-management/2.1.png differ diff --git a/Attachments/media-management/2.1_s.png b/Attachments/media-management/2.1_s.png new file mode 100644 index 00000000..8172bf43 Binary files /dev/null and b/Attachments/media-management/2.1_s.png differ diff --git a/Attachments/media-management/2.2.png b/Attachments/media-management/2.2.png new file mode 100644 index 00000000..0073eec7 Binary files /dev/null and b/Attachments/media-management/2.2.png differ diff --git a/Attachments/media-management/2.2_s.png b/Attachments/media-management/2.2_s.png new file mode 100644 index 00000000..209c652b Binary files /dev/null and b/Attachments/media-management/2.2_s.png differ diff --git a/Attachments/media-management/2.3.png b/Attachments/media-management/2.3.png new file mode 100644 index 00000000..abce2771 Binary files /dev/null and b/Attachments/media-management/2.3.png differ diff --git a/Attachments/media-management/2.3_s.png b/Attachments/media-management/2.3_s.png new file mode 100644 index 00000000..4b3194dc Binary files /dev/null and b/Attachments/media-management/2.3_s.png differ diff --git a/Attachments/media-management/2.4.png b/Attachments/media-management/2.4.png new file mode 100644 index 00000000..d4393b94 Binary files /dev/null and b/Attachments/media-management/2.4.png differ diff --git a/Attachments/media-management/2.4_s.png b/Attachments/media-management/2.4_s.png new file mode 100644 index 00000000..3dfbd446 Binary files /dev/null and b/Attachments/media-management/2.4_s.png differ diff --git a/Attachments/media-management/2.png b/Attachments/media-management/2.png new file mode 100644 index 00000000..6ec1cfa4 Binary files /dev/null and b/Attachments/media-management/2.png differ diff --git a/Attachments/media-management/2_s.png b/Attachments/media-management/2_s.png new file mode 100644 index 00000000..b789361f Binary files /dev/null and b/Attachments/media-management/2_s.png differ diff --git a/Attachments/media-management/3.png b/Attachments/media-management/3.png new file mode 100644 index 00000000..4333e439 Binary files /dev/null and b/Attachments/media-management/3.png differ diff --git a/Attachments/media-management/3_s.png b/Attachments/media-management/3_s.png new file mode 100644 index 00000000..a836add4 Binary files /dev/null and b/Attachments/media-management/3_s.png differ diff --git a/Attachments/media-management/4.png b/Attachments/media-management/4.png new file mode 100644 index 00000000..c213ee11 Binary files /dev/null and b/Attachments/media-management/4.png differ diff --git a/Attachments/media-management/4_s.png b/Attachments/media-management/4_s.png new file mode 100644 index 00000000..6ed82f2e Binary files /dev/null and b/Attachments/media-management/4_s.png differ diff --git a/Attachments/media-management/5.png b/Attachments/media-management/5.png new file mode 100644 index 00000000..f830b003 Binary files /dev/null and b/Attachments/media-management/5.png differ diff --git a/Attachments/media-management/5_s.png b/Attachments/media-management/5_s.png new file mode 100644 index 00000000..09b47283 Binary files /dev/null and b/Attachments/media-management/5_s.png differ diff --git a/Attachments/media-management/6.png b/Attachments/media-management/6.png new file mode 100644 index 00000000..460349a9 Binary files /dev/null and b/Attachments/media-management/6.png differ diff --git a/Attachments/media-management/6_s.png b/Attachments/media-management/6_s.png new file mode 100644 index 00000000..f41c4c8b Binary files /dev/null and b/Attachments/media-management/6_s.png differ diff --git a/Attachments/media-management/7.png b/Attachments/media-management/7.png new file mode 100644 index 00000000..673ab053 Binary files /dev/null and b/Attachments/media-management/7.png differ diff --git a/Attachments/media-management/7_s.png b/Attachments/media-management/7_s.png new file mode 100644 index 00000000..1c809e86 Binary files /dev/null and b/Attachments/media-management/7_s.png differ diff --git a/Attachments/media-management/8.png b/Attachments/media-management/8.png new file mode 100644 index 00000000..7c1f8efc Binary files /dev/null and b/Attachments/media-management/8.png differ diff --git a/Attachments/media-management/8_s.png b/Attachments/media-management/8_s.png new file mode 100644 index 00000000..165155fe Binary files /dev/null and b/Attachments/media-management/8_s.png differ diff --git a/Attachments/media-management/9.png b/Attachments/media-management/9.png new file mode 100644 index 00000000..b82a79fb Binary files /dev/null and b/Attachments/media-management/9.png differ diff --git a/Attachments/media-management/9_s.png b/Attachments/media-management/9_s.png new file mode 100644 index 00000000..8909cac4 Binary files /dev/null and b/Attachments/media-management/9_s.png differ diff --git a/Attachments/users/1.png b/Attachments/users/1.png new file mode 100644 index 00000000..a5b6061c Binary files /dev/null and b/Attachments/users/1.png differ diff --git a/Attachments/users/1_s.png b/Attachments/users/1_s.png new file mode 100644 index 00000000..0e5b3630 Binary files /dev/null and b/Attachments/users/1_s.png differ diff --git a/Attachments/users/2.1.png b/Attachments/users/2.1.png new file mode 100644 index 00000000..18a59c1e Binary files /dev/null and b/Attachments/users/2.1.png differ diff --git a/Attachments/users/2.1_s.png b/Attachments/users/2.1_s.png new file mode 100644 index 00000000..2a8c3d49 Binary files /dev/null and b/Attachments/users/2.1_s.png differ diff --git a/Attachments/users/2.2.png b/Attachments/users/2.2.png new file mode 100644 index 00000000..d901a2fa Binary files /dev/null and b/Attachments/users/2.2.png differ diff --git a/Attachments/users/2.2_s.png b/Attachments/users/2.2_s.png new file mode 100644 index 00000000..9a5cbc0c Binary files /dev/null and b/Attachments/users/2.2_s.png differ diff --git a/Attachments/users/2.3.png b/Attachments/users/2.3.png new file mode 100644 index 00000000..7ec42f08 Binary files /dev/null and b/Attachments/users/2.3.png differ diff --git a/Attachments/users/2.3_s.png b/Attachments/users/2.3_s.png new file mode 100644 index 00000000..3d8fdc08 Binary files /dev/null and b/Attachments/users/2.3_s.png differ diff --git a/Attachments/users/2.png b/Attachments/users/2.png new file mode 100644 index 00000000..e28e2bce Binary files /dev/null and b/Attachments/users/2.png differ diff --git a/Attachments/users/2_s.png b/Attachments/users/2_s.png new file mode 100644 index 00000000..58c105f1 Binary files /dev/null and b/Attachments/users/2_s.png differ diff --git a/Attachments/users/3.1.png b/Attachments/users/3.1.png new file mode 100644 index 00000000..3220ecea Binary files /dev/null and b/Attachments/users/3.1.png differ diff --git a/Attachments/users/3.1_s.png b/Attachments/users/3.1_s.png new file mode 100644 index 00000000..7326260c Binary files /dev/null and b/Attachments/users/3.1_s.png differ diff --git a/Attachments/users/3.2.png b/Attachments/users/3.2.png new file mode 100644 index 00000000..345a240a Binary files /dev/null and b/Attachments/users/3.2.png differ diff --git a/Attachments/users/3.2_s.png b/Attachments/users/3.2_s.png new file mode 100644 index 00000000..317c76c6 Binary files /dev/null and b/Attachments/users/3.2_s.png differ diff --git a/Attachments/users/3.3.png b/Attachments/users/3.3.png new file mode 100644 index 00000000..7742a657 Binary files /dev/null and b/Attachments/users/3.3.png differ diff --git a/Attachments/users/3.3_s.png b/Attachments/users/3.3_s.png new file mode 100644 index 00000000..b54fb96b Binary files /dev/null and b/Attachments/users/3.3_s.png differ diff --git a/Attachments/users/3.4.png b/Attachments/users/3.4.png new file mode 100644 index 00000000..6825a557 Binary files /dev/null and b/Attachments/users/3.4.png differ diff --git a/Attachments/users/3.4_s.png b/Attachments/users/3.4_s.png new file mode 100644 index 00000000..f3671771 Binary files /dev/null and b/Attachments/users/3.4_s.png differ diff --git a/Attachments/users/3.png b/Attachments/users/3.png new file mode 100644 index 00000000..60c43e21 Binary files /dev/null and b/Attachments/users/3.png differ diff --git a/Attachments/users/3_s.png b/Attachments/users/3_s.png new file mode 100644 index 00000000..ccd01608 Binary files /dev/null and b/Attachments/users/3_s.png differ diff --git a/Attachments/users/4.1.png b/Attachments/users/4.1.png new file mode 100644 index 00000000..33a6fd55 Binary files /dev/null and b/Attachments/users/4.1.png differ diff --git a/Attachments/users/4.1_s.png b/Attachments/users/4.1_s.png new file mode 100644 index 00000000..d612b63c Binary files /dev/null and b/Attachments/users/4.1_s.png differ diff --git a/Attachments/users/4.2.png b/Attachments/users/4.2.png new file mode 100644 index 00000000..7e9eb875 Binary files /dev/null and b/Attachments/users/4.2.png differ diff --git a/Attachments/users/4.2_s.png b/Attachments/users/4.2_s.png new file mode 100644 index 00000000..3b754ac6 Binary files /dev/null and b/Attachments/users/4.2_s.png differ diff --git a/Attachments/users/4.3.png b/Attachments/users/4.3.png new file mode 100644 index 00000000..eae1ae81 Binary files /dev/null and b/Attachments/users/4.3.png differ diff --git a/Attachments/users/4.3_s.png b/Attachments/users/4.3_s.png new file mode 100644 index 00000000..f129791d Binary files /dev/null and b/Attachments/users/4.3_s.png differ diff --git a/Attachments/users/4.4.png b/Attachments/users/4.4.png new file mode 100644 index 00000000..cdd044e1 Binary files /dev/null and b/Attachments/users/4.4.png differ diff --git a/Attachments/users/4.4_s.png b/Attachments/users/4.4_s.png new file mode 100644 index 00000000..731eda88 Binary files /dev/null and b/Attachments/users/4.4_s.png differ diff --git a/Attachments/users/5.1.png b/Attachments/users/5.1.png new file mode 100644 index 00000000..0da21651 Binary files /dev/null and b/Attachments/users/5.1.png differ diff --git a/Attachments/users/5.1_s.png b/Attachments/users/5.1_s.png new file mode 100644 index 00000000..a80941d7 Binary files /dev/null and b/Attachments/users/5.1_s.png differ diff --git a/Attachments/users/5.2.png b/Attachments/users/5.2.png new file mode 100644 index 00000000..19d028c1 Binary files /dev/null and b/Attachments/users/5.2.png differ diff --git a/Attachments/users/5.2_s.png b/Attachments/users/5.2_s.png new file mode 100644 index 00000000..cc77dc8a Binary files /dev/null and b/Attachments/users/5.2_s.png differ diff --git a/Attachments/users/5.3.png b/Attachments/users/5.3.png new file mode 100644 index 00000000..4fdca88e Binary files /dev/null and b/Attachments/users/5.3.png differ diff --git a/Attachments/users/5.3_s.png b/Attachments/users/5.3_s.png new file mode 100644 index 00000000..93aa5727 Binary files /dev/null and b/Attachments/users/5.3_s.png differ diff --git a/Attachments/users/5.4.png b/Attachments/users/5.4.png new file mode 100644 index 00000000..3d67c033 Binary files /dev/null and b/Attachments/users/5.4.png differ diff --git a/Attachments/users/5.4_s.png b/Attachments/users/5.4_s.png new file mode 100644 index 00000000..9e14654c Binary files /dev/null and b/Attachments/users/5.4_s.png differ diff --git a/Attachments/vstemplate/VSTemplateInstall.PNG b/Attachments/vstemplate/VSTemplateInstall.PNG new file mode 100644 index 00000000..be1edbc5 Binary files /dev/null and b/Attachments/vstemplate/VSTemplateInstall.PNG differ diff --git a/Attachments/walkthroughs/OrchardLogos.zip b/Attachments/walkthroughs/OrchardLogos.zip new file mode 100644 index 00000000..027e1851 Binary files /dev/null and b/Attachments/walkthroughs/OrchardLogos.zip differ diff --git a/Bin/MarkdownSharp.dll b/Bin/MarkdownSharp.dll new file mode 100644 index 00000000..b779a466 Binary files /dev/null and b/Bin/MarkdownSharp.dll differ diff --git a/Bin/MarkdownSharp.pdb b/Bin/MarkdownSharp.pdb new file mode 100644 index 00000000..a6695c63 Binary files /dev/null and b/Bin/MarkdownSharp.pdb differ diff --git a/Bin/MarkdownSharp.xml b/Bin/MarkdownSharp.xml new file mode 100644 index 00000000..b0c77065 --- /dev/null +++ b/Bin/MarkdownSharp.xml @@ -0,0 +1,433 @@ + + + + MarkdownSharp + + + + + when true, (most) bare plain URLs are auto-hyperlinked + WARNING: this is a significant deviation from the markdown spec + + + + + when true, RETURN becomes a literal newline + WARNING: this is a significant deviation from the markdown spec + + + + + use ">" for HTML output, or " />" for XHTML output + + + + + when true, problematic URL characters like [, ], (, and so forth will be encoded + WARNING: this is a significant deviation from the markdown spec + + + + + when false, email addresses will never be auto-linked + WARNING: this is a significant deviation from the markdown spec + + + + + when true, bold and italic require non-word characters on either side + WARNING: this is a significant deviation from the markdown spec + + + + + Markdown is a text-to-HTML conversion tool for web writers. + Markdown allows you to write using an easy-to-read, easy-to-write plain text format, + then convert it to structurally valid XHTML (or HTML). + + + + + maximum nested depth of [] and () supported by the transform; implementation detail + + + + + Tabs are automatically converted to spaces as part of the transform + this constant determines how "wide" those tabs become in spaces + + + + + Create a new Markdown instance using default options + + + + + Create a new Markdown instance and optionally load options from the supplied options parameter. + + + + + Create a new Markdown instance and optionally load options from a configuration + file. There they should be stored in the appSettings section, available options are: + + Markdown.StrictBoldItalic (true/false) + Markdown.EmptyElementSuffix (">" or " />" without the quotes) + Markdown.LinkEmails (true/false) + Markdown.AutoNewLines (true/false) + Markdown.AutoHyperlink (true/false) + Markdown.EncodeProblemUrlCharacters (true/false) + + + + + In the static constuctor we'll initialize what stays the same across all transforms. + + + + + Transforms the provided Markdown-formatted text to HTML; + see http://en.wikipedia.org/wiki/Markdown + + + The order in which other subs are called here is + essential. Link and image substitutions need to happen before + EscapeSpecialChars(), so that any *'s or _'s in the a + and img tags get encoded. + + + + + Perform transformations that form block-level tags like paragraphs, headers, and list items. + + + + + Perform transformations that occur *within* block-level tags like paragraphs, headers, and list items. + + + + + splits on two or more newlines, to form "paragraphs"; + each paragraph is then unhashed (if it is a hash) or wrapped in HTML p tag + + + + + Reusable pattern to match balanced [brackets]. See Friedl's + "Mastering Regular Expressions", 2nd Ed., pp. 328-331. + + + + + Reusable pattern to match balanced (parens). See Friedl's + "Mastering Regular Expressions", 2nd Ed., pp. 328-331. + + + + + Strips link definitions from text, stores the URLs and titles in hash references. + + + ^[id]: url "optional title" + + + + + derived pretty much verbatim from PHP Markdown + + + + + replaces any block-level HTML blocks with hash entries + + + + + returns an array of HTML tokens comprising the input string. Each token is + either a tag (possibly with nested, tags contained therein, such + as <a href="<MTFoo>">, or a run of text between tags. Each element of the + array is a two-element array; the first is either 'tag' or 'text'; the second is + the actual value. + + + + + Turn Markdown link shortcuts into HTML anchor tags + + + [link text](url "title") + [link text][id] + [id] + + + + + Turn Markdown image shortcuts into HTML img tags. + + + ![alt text][id] + ![alt text](url "optional title") + + + + + Turn Markdown headers into HTML header tags + + + Header 1 + ======== + + Header 2 + -------- + + # Header 1 + ## Header 2 + ## Header 2 with closing hashes ## + ... + ###### Header 6 + + + + + Turn Markdown horizontal rules into HTML hr tags + + + *** + * * * + --- + - - - + + + + + Turn Markdown lists into HTML ul and ol and li tags + + + + + Process the contents of a single ordered or unordered list, splitting it + into individual list items. + + + + + /// Turn Markdown 4-space indented code into HTML pre code blocks + + + + + Turn Markdown `code spans` into HTML code tags + + + + + Turn Markdown *italics* and **bold** into HTML strong and em tags + + + + + Turn markdown line breaks (two space at end of line) into HTML break tags + + + + + Turn Markdown > quoted blocks into HTML blockquote blocks + + + + + Turn angle-delimited URLs into HTML anchor tags + + + <http://www.example.com> + + + + + Remove one level of line-leading spaces + + + + + encodes email address randomly + roughly 10% raw, 45% hex, 45% dec + note that @ is always encoded and : never is + + + + + Encode/escape certain Markdown characters inside code blocks and spans where they are literals + + + + + Encode any ampersands (that aren't part of an HTML entity) and left or right angle brackets + + + + + Encodes any escaped characters such as \`, \*, \[ etc + + + + + swap back in all the special characters we've hidden + + + + + escapes Bold [ * ] and Italic [ _ ] characters + + + + + hex-encodes some unusual "problem" chars in URLs to avoid URL detection problems + + + + + Within tags -- meaning between < and > -- encode [\ ` * _] so they + don't conflict with their use in Markdown for code, italics and strong. + We're replacing each such character with its corresponding hash + value; this is likely overkill, but it should prevent us from colliding + with the escape values by accident. + + + + + convert all tabs to _tabWidth spaces; + standardizes line endings from DOS (CR LF) or Mac (CR) to UNIX (LF); + makes sure text ends with a couple of newlines; + removes any blank lines (only spaces) in the text + + + + + this is to emulate what's evailable in PHP + + + + + current version of MarkdownSharp; + see http://code.google.com/p/markdownsharp/ for the latest code or to contribute + + + + + Static constructor + + + In the static constuctor we'll initialize what stays the same across all transforms. + + + + + + Strips link definitions from text, stores the URLs and titles in hash references. + + Link defs are in the form: ^[id]: url "optional title" + + + + Hashify HTML blocks + + + + + These are all the transformations that form block-level + tags like paragraphs, headers, and list items. + + + + + These are all the transformations that occur *within* block-level + tags like paragraphs, headers, and list items. + + + + + + + + Process the contents of a single ordered or unordered list, splitting it + into individual list items. + + + + + Encode/escape certain characters inside Markdown code runs. + + + The point is that in code, these characters are literals, and lose their + special Markdown meanings. + + + + + Smart processing for ampersands and angle brackets that need to be encoded. + + + + + Swap back in all the special characters we've hidden. + + + + + Remove one level of line-leading tabs or spaces + + + + + This is to emulate what's evailable in PHP + + + + + + + + Calculate an MD5 hash of an arbitrary string + + + + + + + when true, (most) bare plain URLs are auto-hyperlinked + WARNING: this is a significant deviation from the markdown spec + + + + + when true, RETURN becomes a literal newline + WARNING: this is a significant deviation from the markdown spec + + + + + use ">" for HTML output, or " />" for XHTML output + + + + + when true, problematic URL characters like [, ], (, and so forth will be encoded + WARNING: this is a significant deviation from the markdown spec + + + + + when false, email addresses will never be auto-linked + WARNING: this is a significant deviation from the markdown spec + + + + + when true, bold and italic require non-word characters on either side + WARNING: this is a significant deviation from the markdown spec + + + + diff --git a/Bin/MarkdownWebPages.dll b/Bin/MarkdownWebPages.dll new file mode 100644 index 00000000..0562df31 Binary files /dev/null and b/Bin/MarkdownWebPages.dll differ diff --git a/Bin/MarkdownWebPages.pdb b/Bin/MarkdownWebPages.pdb new file mode 100644 index 00000000..bfab9d59 Binary files /dev/null and b/Bin/MarkdownWebPages.pdb differ diff --git a/README b/Documentation/A-few-interesting-extensibility-points.markdown similarity index 100% rename from README rename to Documentation/A-few-interesting-extensibility-points.markdown diff --git a/Documentation/Accessing-and-rendering-shapes.markdown b/Documentation/Accessing-and-rendering-shapes.markdown new file mode 100644 index 00000000..33375007 --- /dev/null +++ b/Documentation/Accessing-and-rendering-shapes.markdown @@ -0,0 +1,250 @@ +> This topic was updated for the Orchard 1.1 release. + +A _shape_ is a dynamic data model. The purpose of a shape is to replace the static view model of ASP.NET MVC by using a model that can be updated at run time—that is, by using a dynamic shape. + +This article introduces the concept of shapes and explains how to work with them. It's intended for module and theme developers who have at least a basic understanding of Orchard modules. For information about creating modules, see [Building a Hello World Module](Building-a-hello-world-module). For information about dynamic objects, see [Creating and Using Dynamic Objects](http://msdn.microsoft.com/en-us/library/ee461504.aspx). + + +# Introducing Shapes +Shapes are dynamic data models that use shape templates to make the data visible to the user in the way you want. Shape templates are fragments of markup for rendering shapes. Examples of shapes include menus, menu items, content items, documents, and messages. + +A shape is a data model object that derives from the `Orchard.DisplayManagement.Shapes.Shape` class. The `Shape` class is never instantiated. Instead, shapes are created at run time by a shape factory. The default shape factory is `Orchard.DisplayManagement.Implementation.DefaultShapeFactory`. The shapes created by the shape factory are dynamic objects. + +> **Note**` `Dynamic objects are new to the .NET Framework 4. As a dynamic object, a shape exposes its members at run time instead of at compile time. By contrast, an ASP.NET MVC model object is a static object that's defined at compile time. + +Information about the shape is contained in the `ShapeMetadata` property of the shape itself. This information includes the shape's type, display type, position, prefix, wrappers, alternates, child content, and a `WasExecuted` Boolean value. + +You can access the shape's metadata as shown in the following example: + + var shapeType = shapeName.Metadata.Type; + + +After the shape object is created, the shape is rendered with the help of a shape template. A shape template is a piece of HTML markup (partial view) that is responsible for displaying the shape. Alternatively, you can use a shape attribute (`Orchard.DisplayManagement.ShapeAttribute`) that enables you to write code that creates and displays the shape without using a template. + +# Creating Shapes +For module developers, the most common need for shapes is to transport data from a driver to a template for rendering. A driver derives from the `Orchard.ContentManagement.Drivers.ContentPartDriver` class and typically overrides that class's `Display` and `Editor` methods. The `Display` and `Editor` methods return a `ContentShapeResult` object, which is analogous to the `ActionResult` object returned by action methods in ASP.NET MVC. The `ContentShape` method helps you create the shape and return it in a `ContentShapeResult` object. + +Although the `ContentShape` method is overloaded, the most typical use is to pass it two parameters—the shape type and a dynamic function expression that defines the shape. The shape type names the shape and binds the shape to the template that will be used to render it. The naming conventions for shape types are discussed later in [Naming Shapes and Templates](Accessing-and-rendering-shapes#NamingShapeTypes). + +The function expression can be described best by using an example. The following example shows a driver's `Display` method that returns a shape result, which will be used to display a `Map` part. + + + protected override DriverResult Display( + MapPart part, string displayType, dynamic shapeHelper) + { + return ContentShape("Parts_Map", + () => shapeHelper.Parts_Map( + Longitude: part.Longitude, + Latitude: part.Latitude)); + } + + +The expression uses a dynamic object (`shapeHelper`) to define a `Parts_Map` shape and its attributes. The expression adds a `Longitude` property to the shape and sets it equal to the part's `Longitude` property. The expression also adds a `Latitude` property to the shape and sets it equal to the part's `Latitude` property. The `ContentShape` method creates the results object that is returned by the `Display` method. + +The following example shows the entire driver class that sends a shape result to a template either to be displayed or edited in a `Map` part. The `Display` method is used to display the map. The `Editor` method marked "GET" is used to display the shape result in editing view for user input. The `Editor` method marked "POST" is used to redisplay the editor view using the values provided by the user. These methods use different overloads of the `Editor` method. + + + using Maps.Models; + using Orchard.ContentManagement; + using Orchard.ContentManagement.Drivers; + + namespace Maps.Drivers + { + public class MapPartDriver : ContentPartDriver + { + protected override DriverResult Display( + MapPart part, string displayType, dynamic shapeHelper) + { + return ContentShape("Parts_Map", + () => shapeHelper.Parts_Map( + Longitude: part.Longitude, + Latitude: part.Latitude)); + } + + //GET + protected override DriverResult Editor( + MapPart part, dynamic shapeHelper) + { + return ContentShape("Parts_Map_Edit", + () => shapeHelper.EditorTemplate( + TemplateName: "Parts/Map", + Model: part)); + } + + //POST + protected override DriverResult Editor( + MapPart part, IUpdateModel updater, dynamic shapeHelper) + { + updater.TryUpdateModel(part, Prefix, null, null); + return Editor(part, shapeHelper); + } + } + } + + +The `Editor` method marked "GET" uses the `ContentShape` method to create a shape for an editor template. In this case, the type name is `Parts_Map_Edit` and the `shapeHelper` object creates an `EditorTemplate` shape. This is a special shape that has a `TemplateName` property and a `Model` property. The `TemplateName` property takes a partial path to the template. In this case, `"Parts/Map"` causes Orchard to look for a template in your module at the following path: + +_Views/EditorTemplates/Parts/Map.cshtml_ + +The `Model` property takes the name of the part's model file, but without the file-name extension. + + + +# Naming Shapes and Templates +As noted, the name given to a shape type binds the shape to the template that will be used to render the shape. For example, suppose you create a part named `Map` that displays a map for the specified longitude and latitude. The name of the shape type might be `Parts_Map`. By convention, all part shapes begin with `Parts_` followed by the name of the part (in this case `Map`). Given this name (`Parts_Map`), Orchard looks for a template in your module at the following path: + +_views/parts/Map.cshtml_ + +The following table summarizes the conventions that are used to name shape types and templates. + +Applied To | Shape Naming Convention | Shape Type Example | Template Example +---------------------- | ----------------------------------------------------------------- | ---------------------------------------------------- | ------------------------------------------ +Content shapes | Content\_\_\[ContentType\] | Content\_\_BlogPost | Content-BlogPost +Content shapes | Content\_\_\[Id\] | Content\_\_42 | Content-42 +Content shapes | Content\_\_\[DisplayType\] | Content\_\_Summary | Content.Summary +Content shapes | Content\_\[DisplayType\]\_\_\[ContentType\] | Content\_Summary\_\_BlogPost | Content-BlogPost.Summary +Content shapes | Content\_\[DisplayType\]\_\_\[Id\] | Content\_Summary\_\_42 | Content-42.Summary +Content.Edit shapes | Content\_Edit\_\_\[DisplayType\] | Content\_Edit\_\_Page | Content-Page.Edit +Content Part templates | \[ShapeType\]\_\_\[Id\] | Parts\_Common\_Metadata\_\_42 | Parts/Common.Metadata-42 +Content Part templates | \[ShapeType\]\_\_\[ContentType\] | Parts\_Common\_Metadata\_\_BlogPost | Parts/Common.Metadata-BlogPost +Field templates | \[ShapeType\]\_\_\[FieldName\] | Fields\_Common\_Text\_\_Teaser | Fields/Common.Text-Teaser +Field templates | \[ShapeType\]\_\_\[PartName\] | Fields\_Common\_Text\_\_TeaserPart | Fileds/Common.Text-TeaserPart +Field templates | \[ShapeType\]\_\_\[ContentType\]\_\_\[PartName\] | Fields\_Common\_Text\_\_Blog\_\_TeaserPart | Fields/Common.Text-Blog-TeaserPart +Field templates | \[ShapeType\]\_\_\[PartName\]\_\_\[FieldName\] | Fields\_Common\_Text\_\_TeaserPart\_\_Teaser | Fields/Common.Text-TeaserPart-Teaser +Field templates | \[ShapeType\]\_\_\[ContentType\]\_\_\[FieldName\] | Fields\_Common\_Text\_\_Blog\_\_Teaser | Fields/Common.Text-Blog-Teaser +Field templates | \[ShapeType\]\_\_\[ContentType\]\_\_\[PartName\]\_\_\[FieldName\] | Fields\_Common\_Text\_\_Blog\_\_TeaserPart\_\_Teaser | Fields/Common.Text-Blog-TeaserPart-Teaser +LocalMenu | LocalMenu\_\_\[MenuName\] | LocalMenu\_\_main | LocalMenu-main +LocalMenuItem | LocalMenuItem\_\_\[MenuName\] | LocalMenuItem\_\_main | LocalMenuItem-main +Menu | Menu\_\_\[MenuName\] | Menu\_\_main | Menu-main +MenuItem | MenuItem\_\_\[MenuName\] | MenuItem\_\_main | MenuItem-main +Resource | Resource\_\_\[FileName\] | Resource\_\_flower\.gif | Resource-flower.gif +Style | Style\_\_\[FileName\] | Style\_\_site\.css | Style-site.css +Widget | Widget\_\_\[ContentType\] | Widget\_\_HtmlWidget | Widget-HtmlWidget +Widget | Widget\_\_\[ZoneName\] | Widget\_\_AsideSecond | Widget-AsideSecond +Zone | Zone\_\_\[ZoneName\] | Zone\_\_AsideSecond | Zone-AsideSecond + +You should put your templates in the project according to the following rules: + +* Content item shape templates are in the _views/items_ folder. +* `Parts_` shape templates are in the _views/parts_ folder. +* `Fields_` shape templates are in the _views/fields_ folder. +* The `EditorTemplate` shape templates are in the _views/EditorTemplates/_`template` name folder. +For example, an `EditorTemplate` with a template name of _Parts/Routable.RoutePart_ has its template at _views/EditorTemplates/Parts/Routable.RoutePart.cshtml_. +* All other shape templates are in the _views_ folder. + +> **Note**` `The template extension can be any extension supported by an active view engine, such as _.cshtml_, _.vbhtml_, or _.ascx_. + +## From Template File Name to Shape Name + +More generally, the rules to map from a template file name to the corresponding shape name are the following: + +* Dot (.) and backslash (\) change to underscore (_). Note that this does not mean that an _example.cshtml_ file in a _myviews_ subdirectory of _Views_ is equivalent to a _myviews_example.chtml_ file in _Views_. The shape templates must still be in the expected directory (see above). +* Hyphen (-) changes to a double underscore (\_\_). + +For example, _Views/Hello.World.cshtml_ will be used to render a shape named `Hello_World`, and _Views/Hello.World-85.cshtml_ will be used to render a shape named `Hello_World__85`. + +## Alternate Shape Rendering + +As noted, an HTML widget in the `AsideSecond` zone (for example) could be rendered by a _widget.cshtml_ template, by a _widget-htmlwidget.cshtml_ template, or by a _widget-asidesecond.cshtml_ if they exist in the current theme. When various possibilities exist to render the same content, these are referred to as _alternates_ of the shape, and they enable rich template overriding scenarios. + +Alternates form a group that corresponds to the same shape if they differ only by a double-underscore suffix. For example, `Hello_World`, `Hello_World__85`, and `Hello_World__DarkBlue` are an alternate group for a `Hello_World` shape. `Hello_World_Summary`, conversely, does not belong to that group and would correspond to a `Hello_World_Shape` shape, not to a `Hello_World` shape. (Notice the difference between "\_\_" and "\_".) + +## Which Alternate Will Be Rendered? + +Even if it has alternates, a shape is always created with the base name, such as `Hello_World`. Alternates give additional template name options to the theme developer beyond the default (such as _hello.world.cshtml_). The system will choose the most specialized template available among the alternates, so _hello.world-orange.cshtml_ will be preferred to _hello.world.cshtml_ if it exists. + +## Built-In Content Item Alternates + +The table above shows possible template names for content items. It should now be clear that the shape name is built from `Content` and the display type (for example `Content_Summary`). + +The system also automatically adds the content type and the content ID as alternates (for example `Content_Summary__Page` and `Content_Summary__42`). + +For more information about how to use alternates, see [Alternates](Alternates). + +# Rendering Shapes Using Templates +A shape template is a fragment of markup that is used to render the shape. The default view engine in Orchard is the Razor view engine. Therefore, shape templates use Razor syntax by default. For an introduction to Razor syntax, see [Template File Syntax Guide](Template-file-syntax-guide). + +The following example shows a template for displaying a `Map` part as an image. + + + Location + + +This example shows an `img` element in which the `src` attribute contains a URL and a set of parameters passed as query-string values. In this query string, `@Model` represents the shape that was passed into the template. Therefore, `@Model.Latitude` is the `Latitude` property of the shape, and `@Model.Longitude` is the `Longitude` property of the shape. + +The following example shows the template for the editor. This template enables the user to enter values for the latitude and longitude. + + + @model Maps.Models.MapPart + +
+ Map Fields + +
+ @Html.LabelFor(model => model.Longitude) +
+
+ @Html.TextBoxFor(model => model.Latitude) + @Html.ValidationMessageFor(model => model.Latitude) +
+ +
+ @Html.LabelFor(model => model.Longitude) +
+
+ @Html.TextBoxFor(model => model.Longitude) + @Html.ValidationMessageFor(model => model.Longitude) +
+ +
+ + +The `@Html.LabelFor` expressions create labels using the name of the shape properties. The `@Html.TextBoxFor` expressions create text boxes where users enter values for the shape properties. The `@Html.ValidationMessageFor` expressions create messages that are displayed if users enter an invalid value. + +For more information about shape templates and Razor syntax, see +[Template Files and their Locations](Template-files-and-their-locations). + +## Wrappers +Wrappers let you customize the rendering of a shape by adding markup around the shape. For example, _Document.cshtml_ is a wrapper for the `Layout` shape, because it specifies the markup code that surrounds the `Layout` shape. For more information about the relationship between `Document` and `Layout`, see [Template File Syntax Guide](Template-file-syntax-guide). + +Typically, you add a wrapper file to the _Views_ folder of your theme. For example, to add a wrapper for `Widget`, you add a _Widget.Wrapper.cshtml_ file to the _Views_ folder of your theme. If you enable the **Shape Tracing** feature, you'll see the available wrapper names for a shape. You can also specify a wrapper in the _placement.info_ file. For more information about how to specify a wrapper, see [Understanding the placement.info File](Understanding-placement-info). + +# Creating a Shape Method +Another way to create and render a shape is to create a method that both defines and renders the shape. The method must be marked with the `Shape` attribute (the `Orchard.DisplayManagement.ShapeAttribute` class). The method returns an `IHtmlString` object instead of using a template; the returned object contains the markup that renders the shape. + +The following example shows the `DateTimeRelative` shape. This shape takes a `DateTime` value in the past and returns a string that relates the value to the current time. + + + public class DateTimeShapes : IDependency { + private readonly IClock _clock; + + public DateTimeShapes(IClock clock) { + _clock = clock; + T = NullLocalizer.Instance; + } + + public Localizer T { get; set; } + + [Shape] + public IHtmlString DateTimeRelative(HtmlHelper Html, DateTime dateTimeUtc) { + var time = _clock.UtcNow - dateTimeUtc; + + if (time.TotalDays > 7) + return Html.DateTime(dateTimeUtc, T("'on' MMM d yyyy 'at' h:mm tt")); + if (time.TotalHours > 24) + return T.Plural("1 day ago", "{0} days ago", time.Days); + if (time.TotalMinutes > 60) + return T.Plural("1 hour ago", "{0} hours ago", time.Hours); + if (time.TotalSeconds > 60) + return T.Plural("1 minute ago", "{0} minutes ago", time.Minutes); + if (time.TotalSeconds > 10) + return T.Plural("1 second ago", "{0} seconds ago", time.Seconds); + + return T("a moment ago"); + } + } + diff --git a/Documentation/Adding-Pages-to-Your-Site.markdown b/Documentation/Adding-Pages-to-Your-Site.markdown new file mode 100644 index 00000000..37ddc3c8 --- /dev/null +++ b/Documentation/Adding-Pages-to-Your-Site.markdown @@ -0,0 +1,58 @@ + +After you create a Web site in Orchard, you will need to add to pages for your content. This topic shows how to create a new web page, add content using Orchard's rich-text editor, and publish the page to your web site. + +# Creating a New Page + +In the Admin Panel under **Content**, click **Create Page**. The **Create Page** settings are displayed, as shown in the following image. + +![](../Upload/screenshots_675/Create_Page.png) + +Using the **Create Page** settings, you can do the following: + +* Give your new page a title. +* Add a permalink. +* Set the new page as the home page for the web site. +* Add content using the rich-text editor. +* Add content tags. +* Indicate whether to show the page on the main menu. +* Allow comments from users to be posted to the page. +* Assign an owner for the page. +* Save and publish the page to the site. + +## Permalinks +A permalink is a URL that points to this page indefinitely and is less susceptible to "link rot" (links that become unavailable). A suggested permalink based on the page title is automatically provided when you enter the text box. You can accept the one provided or change it as needed. + +![](../Upload/screenshots/Permalink.png) + +## Content Tags +A content tag assigns a content category to this page. For example, a page about famous fiction authors might have the following tags: authors, fiction, and books. After the page is published, a list of tags assigned to the page is displayed below the body of the content. By clicking on a tag, the user can find all of the pages on your web site that have the same tag assigned. + +## Show on Main Menu +If you want a link to this page to appear on the main menu, select the **Show on main menu** check box. When this option is selected, the **Menu text** box will be displayed and you can enter the text to display on the main menu. + +![](../Upload/screenshots/ShowOnMainMenu.png) + +## User Comments +To enable users to post comments on the page, select the **Allow new comments** check box. A form will be added to the bottom of the page for user comments. The following image shows the form that is added to the published page. + +![](../Upload/screenshots/AddComment.png) + +# Using the Rich-text Editor + +The Orchard text editor enables you to add content to your web page while taking advantage of its powerful rich-text features. The following image shows the editor's tool bar with each button labeled. The label shown here is consistent with the tooltip that appears when you hover over the button. + +![](../Upload/screenshots/EditorControls.png) + +Some of the less commonly available editing features include the following: + +* Add Media lets you upload new media files, such as images, sound files, and video files. +* Insert/Edit Image lets add an image to the page or resize a selected image. +* Insert/Edit Link button lets to insert a hyperlink in the page. +* Edit HTML Source displays the underlying HTML text and lets you edit it directly. +* Toggle Fullscreen Mode expands the editor to cover your entire screen or returns it to its normal size. + +# Saving and Publishing a Page + +The controls along the bottom of the page enable you to save a draft of your new page, publish the page to your web site immediately, or schedule the page to be published at a specified date and time. + +![](../Upload/screenshots/save_publish_buttons.png) diff --git a/Documentation/Adding-a-Blog-to-Your-Site.markdown b/Documentation/Adding-a-Blog-to-Your-Site.markdown new file mode 100644 index 00000000..96e3b2df --- /dev/null +++ b/Documentation/Adding-a-Blog-to-Your-Site.markdown @@ -0,0 +1,51 @@ + +Orchard provides a powerful blogging engine that makes it easy to add a blog to your web site. This topic describes how to create a blog for your site and then add a new blog post. + +# Creating a New Blog + +In the Admin Panel under **Blogs**, click **Create New Blog**. The **Create New Blog** settings are displayed, as shown in the following image. + +![](../Upload/screenshots_675/blog_create_675.png) + +Using the **Create New Blog** settings, you can do the following: + +* Give your new blog a title. +* Add a permalink to the blog. +* Set the blog as the home page for the web site. +* Add a description that will appear at the top of the blog when published. +* Add content tags for the blog as a whole. +* Indicate whether to show the blog on the main menu. +* Assign an owner for the blog. + +For more information about permalinks, content tags, or the **Show on main menu** checkbox, see [Adding Pages to Your Site](Adding-Pages-to-Your-Site). + +After selecting the settings for your blog, click **Add** to add the new blog to your site. + +# Creating a New Blog Post + +As soon as the blog is added to your site, you can add blog posts. As the following image shows, click **New Post** to add a blog post. + +![](../Upload/screenshots_675/blog_new_post_675.png) + +The **Create New Blog Post** settings are displayed, as shown in the following image. + +![](../Upload/screenshots_675/blog_new_post_2_675.png) + +Using the **Create New Blog Post** settings, you can do the following: + +* Give your new blog post a title. +* Add a permalink for the blog post. +* Set the blog post as the home page for the web site. +* Add content using the rich-text editor. +* Add content tags. +* Allow comments from users to be posted to the blog post. +* Assign an owner for the blog post. +* Save and publish the blog post to the site. + +For more information about using the text editor or saving and publishing the blog post, see [Adding Pages to Your Site](Adding-Pages-to-Your-Site). + +After you have created a new blog and published it to your site, your blog will look similar to the following image. + +![](../Upload/screenshots_675/playground_blog_675.png) + + diff --git a/Documentation/Adding-admin-menu-items.markdown b/Documentation/Adding-admin-menu-items.markdown new file mode 100644 index 00000000..e69de29b diff --git a/Documentation/Adding-and-managing-media-content.markdown b/Documentation/Adding-and-managing-media-content.markdown new file mode 100644 index 00000000..b3cb11e4 --- /dev/null +++ b/Documentation/Adding-and-managing-media-content.markdown @@ -0,0 +1,52 @@ + +When you upload images using the rich-text editor in Orchard (or using an XML-RPC client, such as [Windows Live Writer](http://explore.live.com/windows-live-writer)), the images are saved in a _Media_ folder under the root of your Orchard installation. The _Media_ folder must be writable (by the user process that's running the website) in order for image uploads to succeed. If you installed Orchard using the [Web Platform Installer](http://www.microsoft.com/web/downloads/platform.aspx), the _Media_ folder write permissions are configured automatically. + +To add and delete media folders, click **Media** in the dashboard. + +![](../Upload/screenshots_675/manage_media_675.png) + +Browse to a media image file and view the details. The properties of a media file are: + +* **Screenshot**. A thumbnail preview of the image content. +* **Size** and **Added on**. Properties of the media file. +* **Embed**. The URL of the media file, which you can copy to the HTML view of the rich-text editor in order to embed the media image into content. +* **Name**. The name of the media file. + +![](../Upload/screenshots/edit_media_1.png) + +To manage the subfolders for your media folder, click **Media** again on the dashboard. Then click a folder to display the **Manage Folder** screen. + +![](../Upload/screenshots_675/manage_media_folders_675.png) + +This screen gives you the options to add or delete media files and to create subfolders. + +Click **Add a folder** to create a new subfolder. + +Name the new subfolder (for example, name the subfolder "Pictures") and save it. + +![](../Upload/screenshots_675/manage_folders_add_subfolder_675.png) + +Browse to the new subfolder and click **Add media**. + +![](../Upload/screenshots_675/add_media_1_675.png) + +Orchard lets you upload single media files as well as uploading a _.zip_ file that contains multiple image files. If you have a large set of images to upload, it can be more efficient to first add them all to a _.zip_ file and then just upload the _.zip_ file instead of uploading the images one by one. + +To see how this works, create a _.zip_ file on your computer that contains several image files, and then click **Upload**. The **Extract zip** checkbox is selected by default, which will cause the uploaded images in the _.zip_ to be extracted and added to the folder. + +![](../Upload/screenshots_675/upload_zip_media_675.png) + +The uploaded and extracted images are displayed in their parent folder. + +![](../Upload/screenshots_675/upload_zip_media_2_675.png) + +To see or edit the details of an individual uploaded image, click it. + +![](../Upload/screenshots_675/upload_zip_media_3_675.png) + + + + +### Change History +* Updates for Orchard 1.1 + * 3-16-11: Updated all screen shots and menu choices text. diff --git a/Documentation/Adding-code-to-themes.markdown b/Documentation/Adding-code-to-themes.markdown new file mode 100644 index 00000000..e69de29b diff --git a/Documentation/Adding-custom-admin-pages.markdown b/Documentation/Adding-custom-admin-pages.markdown new file mode 100644 index 00000000..e69de29b diff --git a/Documentation/Adding-custom-settings.markdown b/Documentation/Adding-custom-settings.markdown new file mode 100644 index 00000000..8952c414 --- /dev/null +++ b/Documentation/Adding-custom-settings.markdown @@ -0,0 +1,251 @@ +Sometimes you may need to persist some global settings (eg. license code, service login, default width etc.) to be reused across your module. Orchard makes it really simple and I'll show you how to do it. + +Basically, there are two scopes you can define your settings in: + +1. **Site scope** - for global site settings. +2. **Content type scope** - for settings common to all items of a given type (eg. a Page, a Blog, a BlogPost and so on). + +## Defining site scope settings + +You define those settings in a separate content part. Imagine such scenario (_real one - I used it in_ [Content Sharing](http://orchardsharing.codeplex.com/) _module_): + +**"I want to hold my AddThis service login to be reused in share bars across the site"** + +First, you have to create a content part (you can read about content parts [here](http://www.szmyd.com.pl/blog/jumpstart-into-orchard-module-development)): + + + public class ShareBarSettingsPart : ContentPart { + public string AddThisAccount { + get { return Record.AddThisAccount; } + set { Record.AddThisAccount = value; } + } + } + + +and a corresponding record for storage + + + public class ShareBarSettingsPartRecord : ContentPartRecord { + public virtual string AddThisAccount { get; set; } + } + + +You can also decorate the content part AddThisAccount property with `[Required]` attribute to make it a required field when editing site settings. + +After creating the content part and record classes, you need to create an appropriate DB mappings, called in Orchard - **Data Migration**. You shouldn't do it by hand - there is a command-line command - `codegen datamigration ` which will create the appropriate file for you. You can see how to use it [here](http://www.orchardproject.net/docs/Writing-a-content-part.ashx). + +The next step is to create a corresponding driver, which will be responsible for displaying the edit form and saving the posted data. If you have already written some content parts, than this part of code should look familiar: + + + [UsedImplicitly] + public class ShareBarSettingsPartDriver : ContentPartDriver { + public ShareBarSettingsPartDriver( + INotifier notifier, + IOrchardServices services) { + _notifier = notifier; + T = NullLocalizer.Instance; + } + + public Localizer T { get; set; } + private const string TemplateName = "Parts/Share.Settings"; + private readonly INotifier _notifier; + + protected override DriverResult Editor(ShareBarSettingsPart part, dynamic shapeHelper) { + return ContentShape("Parts_Share_Settings", + () => shapeHelper.EditorTemplate( + TemplateName: TemplateName, + Model: part, + Prefix: Prefix)); + } + + protected override DriverResult Editor(ShareBarSettingsPart part, IUpdateModel updater, dynamic shapeHelper) { + if (updater.TryUpdateModel(part, Prefix, null, null)) { + _notifier.Information(T("Content sharing settings updated successfully")); + } + else { + _notifier.Error(T("Error during content sharing settings update!")); + } + return Editor(part, shapeHelper); + } + } + + +I omitted some code for checking permissions to edit the settings for better readability, but you are free to take a look at the full source code hosted on Codeplex. + +So we have our content part, record and a driver and we need just two more things: a handler in which we define the behavior of our part, and the view (shape) where we create the HTML markup for our form. The handler looks like: + + + [UsedImplicitly] + public class ShareBarSettingsPartHandler : ContentHandler { + public ShareBarSettingsPartHandler(IRepository repository) { + Filters.Add(new ActivatingFilter("Site")); + Filters.Add(StorageFilter.For(repository)); + } + } + + +And in almost all cases it will be exactly like that. There are two things we've done here: + +1. Adding an activating filter, which will tell Orchard to which of the existing content types our **ShareBarSettingsPart** should be attached to. Site is also a content type, so we attach the part to it. **Basically, this is the point that differentiates the ordinary content parts from site settings.** +2. Adding the storage filter to register our settings repository, which will be storing records in the database. + +So we've got one thing left - the .cshtml shape file with HTML markup - and we're done. First, you have to create a .cshtml file under `/Views/EditorTemplates/Parts/`. This file, as the [naming convention](http://www.orchardproject.net/docs/Accessing-and-rendering-shapes.ashx) forces us, should be named `Share.Settings.cshtml`. This name corresponds to the `Parts_Share_Settings` shape which we used inside the driver above. + +![](http://www.szmyd.com.pl/Media/BlogPs/Windows-Live-Writer/804b787519c9_1126C/image_thumb.png) + +We've got only a single field (AddThisAccount) in our settings, so the markup inside the `Share.Settings.cshtml` file will look like this: + + + @model Szmyd.Orchard.Modules.Sharing.Models.ShareBarSettingsPart +
+ @T("Content sharing settigs") +
+ @Html.LabelFor(m => m.AddThisAccount, @T("AddThis service account")) + @Html.EditorFor(m => m.AddThisAccount) + @Html.ValidationMessageFor(m => m.AddThisAccount, "*") +
+
+ + +In order to make this visible we've got to tell Orchard where in the `Site -> Settings` pane our form should be displayed. To achieve this, create a `Placement.info` file in your module root with: + + + + + + + +which will tell Orchard to display our form field at the beginning. We're now done with creating our settings, but how to use them? + +## Using site scope settings + +This part is basically a one-liner: + + + var shareSettings = _services.WorkContext.CurrentSite.As(); + + +Where _services is the `IOrchardServices` object (eg. injected in the constructor). Simple, isn't it? The full (simplified for readability) example from the ShareBarDriver from [Content Sharing](http://orchardsharing.codeplex.com/) module: + + + [UsedImplicitly] + public class ShareBarPartDriver : ContentPartDriver { + private readonly IOrchardServices _services; + + public ShareBarPartDriver(IOrchardServices services) { + _services = services; + } + + protected override DriverResult Display(ShareBarPart part, string displayType, dynamic shapeHelper) { + var shareSettings = _services.WorkContext.CurrentSite.As(); + + // Prevent share bar from showing if account is not set + if (shareSettings == null || string.IsNullOrWhiteSpace(shareSettings.AddThisAccount)) { + return null; + } + + return ContentShape("Parts_Share_ShareBar", + () => shapeHelper.Parts_Share_ShareBar(Account: shareSettings.AddThisAccount)); + } + } + + +This is a second part of a series about settings. In [the first one](http://www.szmyd.com.pl/blog/how-to-add-settings-to-your-content-parts-and-items) I showed you how to add site-scoped settings. If you haven't read it yet, I strongly encourage you to do so. This time we're going to take a more fine-grained approach - create a settings/defaults wired with specific content type (like Page, User, Blog etc.). + +## Defining settings for content type + +This looks much different comparing to the previous one, but also requires less coding. There are just two classes and one shape involved and that's all. As previously, we'll use the simplified examples taken from the [Orchard Sharing](http://orchardsharing.codeplex.com/) project. + +The goal which we want to achieve today can be described as: "I want all of my Blog Posts to have ShareBar with the same look." Imagine that you're writing posts via LiveWriter (like me) - do you want to log in and edit every post after publishing just to change the share bar? I don't. I want to have it defined upfront. + +The first thing you have to do is to create a class holding your settings: + + + public class ShareBarTypePartSettings { + public ShareBarMode Mode { get; set; } + public IEnumerable AvailableModes { get; set; } + } + + +This class has one property - `Mode`, which holds the default mode for all ShareBarParts attached to some content items of a given type. `ShareBarMode` is just an enum type defining the display modes. For the sake of brevity, I won't paste the code here. This could be any type you want. The second property is just used for the display purposes (holds items for display in drop-down list), as this class is also used as a ViewModel. It is not being persisted. + +The second class can be thought of as a kind of a driver for the settings. It's not the Orchard ContentDriver we wrote previously, but also it's responsible for rendering the edit form and saving the posted data: + + + public class ShareBarSettingsHooks : ContentDefinitionEditorEventsBase { + public override IEnumerable TypePartEditor( + ContentTypePartDefinition definition) { + + if (definition.PartDefinition.Name != "ShareBarPart") yield break; + var model = definition.Settings.GetModel(); + + model.AvailableModes = Enum.GetValues(typeof(ShareBarMode)) + .Cast() + .Select(i => + new { + Text = Enum.GetName(typeof(ShareBarMode), i), + Value = i + }); + + yield return DefinitionTemplate(model); + } + + public override IEnumerable TypePartEditorUpdate( + ContentTypePartDefinitionBuilder builder, + IUpdateModel updateModel) { + + if (builder.Name != "ShareBarPart") yield break; + + var model = new ShareBarTypePartSettings(); + updateModel.TryUpdateModel(model, "ShareBarTypePartSettings", null, null); + builder.WithSetting("ShareBarTypePartSettings.Mode", + ((int)model.Mode).ToString()); + yield return DefinitionTemplate(model); + } + } + + +This class overrides the `ContentDefinitionEditorEventsBase` which defines two overridable methods - `TypePartEditor` and `TypePartEditorUpdate`. The first one gets called when the edit form is being rendered and the second one - when the edit form data gets posted. Unlike the generic content part drivers, this class is not bound to the specific content type (as the content types are just a text names for a collection of parts), so each of the methods we just defined will be called for every content type and for every part. This is why the `yield break` statement at the beginning of each is needed - to filter only the ones containing the part we need - `ShareBarPart`. + +By convention, as shown in the TypePartEditorUpdate method, settings should be named as `.` when passing to `builder.WithSetting(...)`, where `prefix` is the string passed to the updateModel.TryUpdateModel. `Prefix` can be anything, but has to be unique. Remember though, when you use string other than your settings class name, you cannot use `Settings.GetModel()` (as shown in the TypePartEditor method above). In this case you have to use `Settings.GetModel(prefix)` instead. + +1. It should be considered best practice to use your settings class name as a `prefix` (as in the code above). +2. Settings are persisted within the content type definition in the db in the string form. You have to be sure that the properties you define are convertible to and from the string representation. + +BTW - notice the usage of `Enum.GetValues(typeof(someEnum)), Enum.GetNames(typeof(someEnum))` and `Enum.GetName(typeof(someEnum), i)`. This methods get very useful when you want to iterate over the names/values of an enum. + +If you're done with the code above, there's only one thing left - creating a .cshtml view (shape) to render our form: + +![](http://www.szmyd.com.pl/Media/BlogPs/Windows-Live-Writer/Using-custom-settings-in-Orchard-Part-2-_AE9C/image_thumb.png) + +Shapes defining edit forms for content type settings has to be placed under `/Views/DefinitionTemplates/` with the name `.cshtml`. So in our case it'll look like on the picture above. Inside, it's just like any other Razor view file: + + + @model Szmyd.Orchard.Modules.Sharing.Settings.ShareBarTypePartSettings +
+
+ @Html.LabelFor(m => m.Mode, T("Share bar display style")) + @Html.DropDownListFor(m => m.Mode, + new System.Web.Mvc.SelectList(Model.AvailableModes, "Value", "Text", (int)Model.Mode)) +
+
+ + +This part of code renders the dropdown list so user can choose one of the predefined Modes. `Model.AvailableModes` contains the available ones - we populated the property with appropriate data in `TypePartEditor` method above. + +Hooray, we're done! + +Now you possibly wonder, where will this edit form be shown? Orchard will render settings form when you'll try to edit the content type containing your part. The steps are like this: `Content Types -> Edit the type you want -> Add your part -> Voila!` There is a nice arrow image next to your part. If you click it - the form shows. + +![](http://www.szmyd.com.pl/Media/BlogPs/Windows-Live-Writer/Using-custom-settings-in-Orchard-Part-2-_AE9C/image_thumb_4.png) + + +## Using settings for content type + +As for site-scoped settings, this section is also a one-liner. The part below is some content part (in this case a ShareBarPart from the [Orchard Sharing](http://orchardsharing.codeplex.com/) project). + + + var typeSettings = part.Settings.GetModel(); + + +You can retrieve and use the settings wherever you have access to your part (particularly in the driver Display/Editor methods, but also shapes, handlers and so on). I used it in the ShareBarPart driver Display method to change the look of a share bar part. diff --git a/Documentation/Alternates.markdown b/Documentation/Alternates.markdown new file mode 100644 index 00000000..ba859e08 --- /dev/null +++ b/Documentation/Alternates.markdown @@ -0,0 +1,172 @@ +> New for the Orchard 1.1 release. + +Alternates are optional variations of a shape that you can implement in a theme in order to customize the rendering of the shape for specific cases. By using alternates, you can override which template is used to render content, based on the type (or other characteristic) of that content. For example, you can use alternates to apply one layout file for the home page but another layout file for subpages. Or you can use alternates to render tags one way when the tags are in a page but a different way when the tags are in a blog post. Alternates are particularly useful when you have different types of content and you want to customize the appearance of these different types of content. + +The Orchard framework uses a naming convention to determine whether an alternate template is used for rendering content. The naming convention enables you to add template files that are used automatically, without requiring you to modify any code. + + +## Naming Convention for Alternates +Alternate shapes are named using the name of the base shape followed by a double underscore \(\_\_\) and an ending that is specific to the alternate shape. For example, a `Parts_Tags_ShowTags` shape can have alternates with names such as `Parts_Tags_ShowTags__BlogPost` and `Parts_Tags_ShowTags__Page`. The part of the alternate name after the double underscore reflects when the shape is used, such as the current content type. (For more information about how shapes are named, see [Accessing and Rendering Shapes](Accessing-and-rendering-shapes).) + +## Mapping a Template File to an Alternate +To create a template file that maps to the corresponding shape name, you must name the template according to the following naming convention: + +* Convert an underscore (_) in the shape name to either a dot (.) or backslash (\) in the template name. A backslash indicates that the template resides in a subfolder. +* Convert a double underscore \(\_\_\) in the shape name to a hyphen (-). +* For any Display type value in the shape name, place the type name after a dot (.) at the end of the template name, such as Content-BlogPost.Summary. + +All templates for alternates must reside in the _Views_ folder. The _Views_ folder can be located either in the theme or in the module. The following table shows which subfolders of _Views_ to use for different types of templates. + +Shape type | Template Folder +-------------- | ---------------- +Content item | _Views\Items_ +Parts | _Views\Parts_ +Fields | _Views\Fields_ +EditorTemplate | _Views\EditorTemplates\\[template type folder\]_ (For example, an **EditorTemplate** for a part is located at _Views\EditorTemplates\Parts_.) +All other | _Views_ + +For example, to create an alternate template for the **Tags** part, you can add a template to the _MyTheme\Views\Parts_ folder. However, because the underscore can be converted to either a dot (.) or backslash (\), you can also create a template in the _Views_ folder and add _Parts._ to the beginning of the name. A template at either _Views\Parts\Tags.ShowTags-BlogPost.cshtml_ or _Views\Parts.Tags.ShowTags-BlogPost.cshtml_ will map to a shape named `Parts_Tags_ShowTags__BlogPost`. + +If the Orchard framework cannot locate an alternate template that has the expected name, the default template will be used for those shapes. For example, if you do not create an alternate for showing tags, the default template for tags (located at _Views\Parts\Tags.ShowTags.cshtml_) is used. + +The Orchard framework automatically creates many alternates that you can use in your application. However, you can create templates for these alternate shapes. The patterns for creating alternates are shown below, with examples of matching templates in parenthesis. + +For **Content** shapes: + +* _Content\_\_\[DisplayType\]_. (Example template: `Content.Summary`) +* _Content\_\_\[ContentType\]_. (Example template: `Content-BlogPost`) +* _Content\_\_\[Id\]_. (Example template: `Content-42`) +* _Content_\[DisplayType\]\_\_\[ContentType\]_. (Example template: `Content-BlogPost.Summary`) +* _Content_\[DisplayType\]\_\_\[Id\]_. (Example template: `Content-42.Summary`) + +For **Zone** shapes: + +* _Zone\_\_\[ZoneName\]_. (Example template: `Zone-SideBar`) + +For menu and menu item shapes: + +* _Menu\_\_\[MenuName\]_. (Example template: `Menu-main`) +* _MenuItem\_\_\[MenuName\]_. (Example template: `MenuItem-main`) + +For local menu and local menu item shapes: + +* _LocalMenu\_\_\[MenuName\]_. (Example template: `LocalMenu-main`) +* _LocalMenuItem\_\_\[MenuName\]_. (Example template: `LocalMenuItem-main`) + +For styles and resources: + +* _Style\_\_\[FileName\]_ +* _Resource\_\_\[FileName\]_ + +For widget shapes: + +* _Widget\_\_\[ZoneName\]_. (Example template: `Widget-SideBar`) +* _Widget\_\_\[ContentType\]_. (Example template: `Widget-BlogArchive`) + +For fields: + +* _\[ShapeType\_\_FieldName\]_. (Example template: `Fields\Common.Text-Teaser`) +* _\[ShapeType\_\_PartName\]_. (Example template: `Fields\Common.Text-TeaserPart`) +* _\[ShapeType\]\_\_\[ContentType\]\_\_\[PartName\]_. (Example template: `Fields\Common.Text-Blog-TeaserPart`) +* _\[ShapeType\]\_\_\[PartName\]\_\_\[FieldName\]_. (Example template: `Fields\Common.Text-TeaserPart-Teaser`) +* _\[ShapeType\]\_\_\[ContentType\]\_\_\[FieldName\]_. (Example template: `Fields\Common.Text-Blog-Teaser`) +* _\[ShapeType\]\_\_\[ContentType\]\_\_\[PartName\]\_\_\[FieldName\]_. (Example template: `Fields\Common.Text-Blog-TeaserPart-Teaser`) + +For content parts: + +* _\[ShapeType\]\_\_\[Id\]_. (Example template: `Parts\Common.Metadata-42`) +* _\[ShapeType\]\_\_\[ContentType\]_. (Example template: `Parts\Common.Metadata-BlogPost`) + +You can use the **Shape Tracing** module to generate alternate templates through the **Shape Tracing** user interface. For more information, see [Customizing Orchard using Designer Helper Tools](Customizing-Orchard-using-Designer-Helper-Tools). + +## URL Alternates +The **URL Alternates** module enables you to create templates for specific URLs. You must enable the **URL Alternates** module to use this feature. When it is enabled, alternate shapes are created based on the URL. These URL alternates are combined with the alternate patterns defined above. For example, the URL _/my-blog/post-1_ has the following alternates are available for a `MenuItem` object: + +`MenuItem-main` +`MenuItem-main-url-my-blog` +`MenuItem-main-url-my-blog-post-1` + +For the homepage, the following alternate is available: + +`MenuItem-main-url-homepage` + +Using this module, you can add URL-specific alternates to the **Layout** shape, such as the following: + +`Layout-url-homepage` + +Example. if you wanted a specific layout for your About page of your site. + +Creating a new layout file in your Themes/ThemeName/Views named `Layout-url-About.cshtml` would be picked up and used when viewing the /About page in your site. + +*Note if the changes are only small, perhaps using alternate url naming to the zone would be more appropriate. + +You can enable URL Alternates by downloading the Designer Tools module from the Orchard Team in the Orchard Modules Gallery [Orchard Designer Tools](http://orchardproject.net/gallery/List/Modules/Orchard.Module.Orchard.DesignerTools) + + +## Explicitly Designating an Alternate Template +In addition to using the automatically generated alternates, you can manually specify an alternate. In a _placement.info_ file, you can specify which alternates are available for a content type. For example, to specify a different template (identified as `Parts_Tags_ShowTags_BlogPost`) for rendering the tags for blog posts, you can revise the _placement.info_ file for the **Orchard.Tags** module to include an element that matches `BlogPost` types. The following example shows the revised file. + + + + + + + + + + + + + + + + +The ordering of the `Match` elements is significant. Only the first matched element is used to render the item. In the example, placing the element for `BlogPost` below `Detail` and `Summary` means that `Parts_Tags_ShowTags_BlogPost` will not be used, even for `BlogPost` items, because the earlier elements match the item. For more information about the _placement.info_ file, see [Understanding placement.info](Understanding-placement-info). + +## Adding Alternates Through Code + +In addition to methods described above for adding alternates, you can add alternates through code. To designate an alternate through code, you create a class that implements the `IShapeTableProvider` interface. Then, you add a handler for `OnDisplaying` for each type of shape that needs an alternate. You specify the shape name as the parameter for the `Describe` method on the `ShapeTableBuilder` class. Within the handler, you add any logic that you need to specify when the alternate is used. The following example first shows how to specify an alternate for shape named `Content`, but only when the user is on the home page. It also shows how to specify an alternate for a shape named `Parts_Tags_ShowTags` when the `DisplayType` is `Summary`. + + + using Orchard; + using Orchard.ContentManagement; + using Orchard.DisplayManagement.Descriptors; + + namespace MyTheme.ShapeProviders + { + public class ExampleShapeProvider : IShapeTableProvider + { + private readonly IWorkContextAccessor _workContextAccessor; + + public ExampleShapeProvider(IWorkContextAccessor workContextAccessor) + { + _workContextAccessor = workContextAccessor; + } + + public void Discover(ShapeTableBuilder builder) + { + builder.Describe("Content") + .OnDisplaying(displaying => + { + if (displaying.ShapeMetadata.DisplayType == "Detail") + { + ContentItem contentItem = displaying.Shape.ContentItem; + if (_workContextAccessor.GetContext().CurrentSite.HomePage.EndsWith(';' + contentItem.Id.ToString())) + { + displaying.ShapeMetadata.Alternates.Add("Content__HomePage"); + } + } + }); + + builder.Describe("Parts_Tags_ShowTags") + .OnDisplaying(displaying => + { + if (displaying.ShapeMetadata.DisplayType == "Summary") + { + displaying.ShapeMetadata.Alternates.Add("Tags_ShowTags_Summary"); + } + }); + } + } + } + diff --git a/Documentation/Anatomy-of-a-theme.markdown b/Documentation/Anatomy-of-a-theme.markdown new file mode 100644 index 00000000..12556d9d --- /dev/null +++ b/Documentation/Anatomy-of-a-theme.markdown @@ -0,0 +1,179 @@ + +Themes enable Orchard users to customize the rendering of the site and tailor it to their needs and design goals. Themes can perform targeted overrides of style sheets, images, layouts, or of any content template provided by any Orchard module. + + +# Where Themes Live + +A theme is set of appropriately named files inside of a folder. That folder must be under the _Themes_ folder under your Orchard website's root folder. + +# TheThemeMachine + +The theme named **TheThemeMachine** is the theme that comes built into Orchard. You can examine this theme in order to learn about Orchard themes. Like any theme, it can be found under the _Themes_ folder. + +![The contents of The Theme Machine](../Attachments/Anatomy-of-a-theme/TheThemeMachine.PNG) + +The **TheThemeMachine** theme has been designed to be a clean-looking, modern theme and to be a good starting point for customization and for the development of new themes. This article uses this theme as an illustration. + +# Anatomy of a Theme +This section describes required and optional elements of a theme. + +## Manifest +To be valid, a theme must have a manifest that describes it to the system. The manifest is a text file named _Theme.txt_ that is found in the root folder of the theme it describes. Here is the manifest for the **TheThemeMachine** theme: + + + Name: The Theme Machine + Author: jowall, mibach, loudej, heskew + Description: Orchard Theme Machine is a flexible multi-zone theme that provides a solid foundation to build your site. It features 20 collapsible widget zones and is flexible enough to cover a wide range of layouts. + Version: 0.1 + Tags: Awesome + Website: http://orchardproject.net + Zones: Header, Navigation, Featured, BeforeMain, AsideFirst, Messages, BeforeContent, Content, AfterContent, AsideSecond, AfterMain, TripelFirst, TripelSecond, TripelThird, FooterQuadFirst, FooterQuadSecond, FooterQuadThird, FooterQuadFourth, Footer + + +The beginning of the file gives the theme a friendly name, description, author, description, and tags. The `Zones` field provides a list of all the zone names that are going to be available for widgets throughout the theme's layouts and templates. Zones are containers that can be added to any template or layout. Various UI elements can be injected into zones, but the most common ones are widgets. Not all zones need to be exposed in the manifest, only those that are intended to host widgets. + +![All the zones in The Theme Machine](../Attachments/Anatomy-of-a-theme/TheThemeMachineZoneScreenshot.PNG) + +This illustration shows 19 zones, which is typically more than you need for a site. The zones include a header and footer, which are zones situated on the top and bottom of the page. There is a navigation zone, which is typically where navigation menus would be inserted. The `Featured` zone is where you might put a site banner. `BeforeMain` and `AfterMain` surround the main zones on the top and bottom. `AsideFirst` and `AsideSecond` are sidebars that are rendered on the left and right of the main content. In the center of the page there is a `Messages` zone where notifications go, followed by `BeforeContent`, the content itself, the `Content` zone and the `AfterContent` zone. On the bottom of the page, there are `TripelFirst`, `TripelSecond`, and `TripelThird` that you can use if you want three columns on the bottom, and the `FooterQuad*` zones that you can use if you want four columns. + +All zones in **TheThemeMachine** theme are collapsible, which means that they will only be rendered if there is content in them. + +## Icon or Thumbnail + +A _Theme.png_ file should be included with all Orchard themes. This image should be at least 400x400 pixels and is meant to represent the theme in the gallery or in the theme administration page. It usually is a thumbnail image of a page of a site rendered using that theme. + +## Widget Zones Preview Image + +Optionally, a preview image for the widget zones can be added to the theme. The image should be placed at the root of the theme and be called ThemeZonePreview.png. This image should be 400 pixels wide and should show the different zones and their names. An example can be found in TheThemeMachine. + +![The zone preview image appears in the widget administration screen.](../Attachments/Anatomy-of-a-theme/WidgetZonePreview.PNG) + +## Static Resources + +A theme typically contains a number of static resources, such as CSS style sheets, JavaScript files, or images. Those files must be in the following folders: + +* CSS style sheets should be in the _\Styles_ folder of the theme. +* JavaScript files should be in the _\Scripts_ folder of the theme. Any scripts you put in this folder should be custom scripts that are only related to your theme, not scripts that are intended to be reused. Such reusable scripts should be included in a separate module. See the jQuery module for an example. +* Images should be in _\Content\Images_ folders. If your theme contains few images, it's fine to keep them all at the same level. However, if you have many images, it is recommended that you organize them in subfolders. + +> **Note** To enable files to be served, each of the folders that contains static files such as style sheets, images, or JavaScript code should contain a _web.config_ file that contains the following content: + + + + + + + + + + + + + + + + + + + + +## Document + +The _Document.cshtml_ file is usually not found in themes because there is seldom any reason to overwrite it. Most themes can just fall back to the version of the file that can be found in the **SafeMode** theme, under _\Views_. The _Document.cshtml_ file is responsible for the HTML that goes around the `body` element. This means it defines the `doctype` element (Orchard assumes the HTML5 document type), the `html` element, the `head` element (where it defines the head zone where the `meta` tags), some `script` elements, and the links for style sheets to be inserted. (This is different from the `Header` zone, which is the top zone in the body.) The _Document.cshtml_ file also contains the `title` element inside the `head` element. Finally, the file defines the `body` element where the `Body` and `Tail` zones are rendered. + +## Layouts + +Layouts are the outermost shape that is rendered within the `body` elemnent. For example, this is typically where you define the main widget zones. You can read about the details of the markup inside of a layout in the [Markup](#markup) section later in this document. + +A theme can contain any number of layout files, even though currently only one is supported and included in the **TheThemeMachine** theme, namely _Layout.cshtml_. For example, a theme can add specialized layouts, such as _Layout-Blog.cshtml_ or _Layout-HomePage.cshtml_, that would be used instead of the default for a blog or for the homepage, provided there is an extension providing those layout shape alternates. Notice that layouts are named _Layout-\{layout name\}.cshtml_. Each layout can have a different set of zones, organized differently in markup. + +For an example of how your own modules and themes can provide alternative layouts based on custom criteria, see [Switching the Layout in Orchard CMS](http://weblogs.asp.net/bleroy/archive/2010/12/14/switching-the-layout-in-orchard-cms.aspx). + +## Shape Templates + +In Orchard, before a web page is rendered into HTML, it is built as a tree of [shapes](Accessing-and-rendering-shapes). Shapes are flexible objects that represent the objects that will contribute to the rendering of the page. Examples include zones, menus, menu items, and widgets. + +Each shape can be rendered by a template, which can be overridden by a theme. Templates have the same name as the shape they are made to render. For example, if _Menu.cshtml_ exists, it is used to render a `Menu` shape. + +The **TheThemeMachine** theme has two shape templates, `BadgeOfHonor` and `Branding`, which are built from _Layout.cshtml_ and injected into the `Header` and `Footer` zones using the following code: + + + // Site name and link to the home page + WorkContext.Layout.Header.Add(New.Branding(), "5"); + // Powered by Orchard + WorkContext.Layout.Footer.Add(New.BadgeOfHonor(), "5"); + + +> **Note** Templates are one of two ways to render shapes. In addition to templates, you can define the rendering using code, by defining a method that has a `Shape` attribute. Look for the _CoreShapes.cs_ file for examples. This is usually done in modules, but themes can do it as well. + +## Item Templates + +Themes can override how content items are rendered by including a template in their _\Views\Items_ folder. The name of the template should be _Content-\{content type name\}.cshtml_ or _Content-\{content type name\}\.\{display type\}.cshtml_. For example, a template that overrides how blog posts are rendered should be _\Views\Items\Content-BlogPost.cshtml_, and a template that overrides the summary rendering of a blog post should be _\Views\Items\Content-BlogPost.Summary.cshtml_. + +## Part Templates + +Themes can override the rendering of content parts. The convention is similar to the convention for content item templates. The template for a part must be in _\Views\Parts_ and must be named for the shape for the part. For example, the rendering for comments can be overridden by creating the file _\Views\Parts\Comments.cshtml_. + +## Field Templates + +Field rendering can be overridden as well, although not yet at the field instance level. In other words, you can override what a text field looks like but not what a specific text field looks like. To override a field template, create a _\{field type name\}.cshtml_ or _\{field type name\}\.\{display type\}.cshtml_ file in _\Views\Fields_. For example, the rendering of text fields can be overridden by a _\Views\Fields\Common.Text.cshtml_ template. + +## Alternates + +Alternates are a set of related shapes with corresponding templates or layout files that enable you to control how different types of content are rendered within a theme. For example, you can use alternates to apply one layout file for the home page but another layout file for subpages, or you can use alternates to render elements one way when the elements are in a page but a different way when they are in a blog post. + +For more information, see [Alternates](Alternates). + +## Widget Overrides + +The rendering for widgets can also be overridden by creating a template in _\Views_ named _widget-\{widget type\}_. For example, you can override the rendering of the HTML widget and add a red frame around the content by putting the following _widget-htmlwidget.cshtml_ file into the _\Views_ folder of your theme: + + +
+ @Display(Model.Content) +
+ + +![Overriding widget rendering](../Attachments/Anatomy-of-a-theme/OverridingWidgetRendering.PNG) + +Note that this is just a simple example, and normally adding a frame would be better done using CSS. + +## Placement Files + +A theme can modify where shapes are rendered by including a _placement.info_ file at the root of the theme folder. The _placement.info_ file is an XML file. Here is an example: + + + + + + + + + + + + + + + + +# Markup +The markup in each file is constrained by the view engine that you choose. The default in Orchard is Razor (_.cshtml_ files), for which a quick guide can be found in [Template File Syntax Guide](Template-file-syntax-guide). + +Within a template, the `Model` object represents the current shape being rendered. That means that if you are working with the message shape, which has a `Message` property, you can display that by writing `@Model.Message` from within the template markup. + +An important addition that Orchard provides is the `Display` method, which renders a shape. For example, if you look at the _layout.cshtml_ file, you can see how the zones are rendered, using calls such as `@Display(Model.Content)`. + +Finally, you can also see in various templates calls such as `@Html.RegisterScript("mystyle.css")` or `@Html.RegisterScript("myscript.js")`. These registration calls are necessary because the collections of scripts and stylesheets are a shared resource. The same `link` or `script` element should not be rendered twice even if multiple modules or multiple instances of the same widget require the same file. + +# Themes with Code + +Most themes will consist only of a stylesheet, a few templates (usually layouts), and a few images. They will contain no code except for the simple code in the template files. For more advanced themes, you might want to provide settings, create custom shapes, or override shapes in code. + +To address these scenarios, it is possible to build a theme much like a module and include a _.csproj_ file that describes how to compile the code it contains. For informaiton about module development, see [Walkthrough: Writing An Orchard Module](Walkthrough-Writing-An-Orchard-Module) and [Creating a Module with a Simple Text Editor](Creating-a-module-with-a-simple-text-editor). diff --git a/Documentation/Archived-specs.markdown b/Documentation/Archived-specs.markdown new file mode 100644 index 00000000..06bd471a --- /dev/null +++ b/Documentation/Archived-specs.markdown @@ -0,0 +1,21 @@ + +* [Blogs](blogs) +* [Comments](comments) +* [Content types](content-types) +* [Definitions](definitions) +* [HTML doctype](fundamentals-doctype) +* [Linkbacks: Pingbacks, Refbacks and Trackbacks](linkback) +* [Media management](media-management) +* [Navigation](navigation) +* [Page editing](pages-editing) +* [Page management and publishing](pages) +* [Page publishing workflow](pages-publishing) +* [RSS and Atom feeds](rss-atom) +* [Slugs](slugs) +* [Page templates and syntax](templates) +* [Tags](tags) +* [Themes](themes) +* [Theme includes](themes-includes) +* [Users, roles and permissions](users) +* [Widgets](widgets) +* [XML-RPC and Live Writer](xml-rpc) diff --git a/Documentation/Automation-test-guidance.markdown b/Documentation/Automation-test-guidance.markdown new file mode 100644 index 00000000..7e239e1e --- /dev/null +++ b/Documentation/Automation-test-guidance.markdown @@ -0,0 +1,108 @@ +We apply selenium for UI automation test; please download selenium IDE and selenium RC from its official website. Please read the selenium document in the web site to learn its usage. + +# Export test case to VSTT +Please export test cases as C# code in Selenium IDE, after you finished recording a test case. Although the generated C# code targets NUnit only, however, it is not difficult for you to do tiny modification to use the code in VSTT. Below are all modification you should make: + +1. Changing \[TestFixture\] attribute to \[TestClass\] attribute\. +2. Changing \[Setup\] attribute to \[TestInitialize\] attribute +3. Changing \[TearDown\] attribute to \[TestCleanup\]\. +4. Changing \[Test\] attribute to \[TestMethod\]\. + +# Encapsulate common test actions to functions & classes +Though Selenium does a great job for us to generate C# test code, however, many common actions exist in our test cases. For e.g. most of site administration functions require user logon, before making any actions. Actions like logon, create blog/post are good candidates to be rewritten as a common function. + +If you see common steps/verifications in more 2 test cases, you'd better to think moving the steps to a helper class (classes derived from class HelperBase). + +# Create a simple test by using the test framework +Let's say you are going to create a test which verifies a link named �Admin� is presented, for Administrators. Below is the tests based on the test framework: + + + [TestMethod] + public void CanNotAccessAdminPanelTestHelper() + { + TestLibrary.UserHelper.LogOn(�Administrator�, �0123456�); + Assert.IsFalse(selenium.IsElementPresent("link=Admin")); + } + + +In above code, the UI actions required for logon actions are encapsulated to TestLibrary.UserHelper.LogOn method, which accepts logon user name as its first parameter, the password as its second parameter. This is the source code of TestLibrary.UserHelper.LogOn, you can see how the logic is applied: + + + public void LogOn(string username, string password) + { + if (username == null) + throw new CaseErrorException(new ArgumentNullException("username")); + if (password == null) + throw new CaseErrorException(new ArgumentNullException("password")); + + selenium.Open("/"); + selenium.Click("link=Log On"); + selenium.WaitForPageToLoad(TestLibrary.Consts.TimeToWaitForPageToLoad); + selenium.Type("username", username); + selenium.Type("password", password); + selenium.Click("//input[@value='Log On']"); + selenium.WaitForPageToLoad(TestLibrary.Consts.TimeToWaitForPageToLoad); + } + + +Because logon as default administrator is frequently used in test code, we created a handy method called TestLibrary.UserHelper.LogOnAsAdmin for this. Above code can be rewritten as below: + + + [TestMethod] + public void CanNotAccessAdminPanelTestHelper() + { + TestLibrary.UserHelper.LogOnAsAdmin(); + Assert.IsFalse(selenium.IsElementPresent("link=Admin")); + } + + +# Description of Important Classes & Methods + +## Class CaseErrorException +If you need throw an exception from your test code, indicates test code error. Please throw an instance of CaseErrorException, instead of throwing original exception directly. For e.g, in below test code: + + + public Blog CreateBlog(string title, string menuText, string permalink, + string description, bool addMainMenu, string owner) + { + // empty string is intendly left for testing purpose + if (title == null) + throw new CaseErrorException(new ArgumentNullException("title")); + if (permalink != null) + throw new CaseErrorException("Set menu Permalink is not implemented yet!"); + if (owner != null) + throw new CaseErrorException("Set owner is not implemented yet!"); + + � + } + + +If a null reference is passed to parameter �title�, this is a bug in test code. In order to distinguish test bugs from product bugs, we'd better throw an instance of CaseErrorException, with the original exception as its inner exception. This is useful in controller test, because the test code calls controllers directly, we need a way to distinguish test bugs from product bugs, while investigate test failures. + +## Class TestLibrary.Consts +Please put all constants to this class, for e.g. the default administrator name/password in the test database. + +## Method TestLibrary.SetupTest +This static method launches different browsers according to predefined excel spreadsheet file. Because it is common for us to debug new test and test failures in local machine, the method is able to detect this. + +# Data driven test approach + +## Methodology of data driven tests +Please check the following article to understand how data driven tests is done in Visual Studio Team Test/Suite edition: + + +## Running tests against different browsers +In order to run all tests on different browsers, and reuse the same test logics. The test code saves browsers settings in the excel file. Test team developed a script, which adds browser settings, such as �*opera�, �*iexplore� and e.t.c to the excel files. So in test case automation phase, just put test data in the excel files is fine. The script is run before any tests, which adds browser settings to all excel files and copy the files to %TestOutputDir%. + +There is another way to launch different browser, selenium remote control sever has a switch called -forcedBrowserMode, this switch overrides settings (hard code brower string) in ocde. This is also quite convenient while debugging test failures. + +## Naming Convention +In order to keep test cases and test data are easy to read, please follow below guideline: + +1. One test class should have 1 excel file which saves test data. For e.g. If you need save test data for class CommentsTest, please name the excel file as CommentsTest.xls. Please note that only Excel 2003 file format is supported by Visual Studio Team Test Edition. +2. Each test method has its own worksheet to save test data, and the worksheet's name is same as test method name. +3. Please refer to test class Orchard.Test\Automation\Components\Comments\CommentsTest.cs for a sample of this guideline. + +// TODO: add steps to create BVT.ordertest and other test suites + + diff --git a/Documentation/Basic-Orchard-Concepts.markdown b/Documentation/Basic-Orchard-Concepts.markdown new file mode 100644 index 00000000..8645bc13 --- /dev/null +++ b/Documentation/Basic-Orchard-Concepts.markdown @@ -0,0 +1,232 @@ + +Orchard is a Web CMS, which essentially aims at helping you build web sites from existing pieces. Those pieces come in a few different sizes and shapes that need to be well understood if you're going to be productive with them. This article will go through those pieces and explain their names and behavior. + + +# General CMS definitions + +## Content + +The 'C' in CMS means "content" so it would be fair to say that content is anything that the CMS manages. More precisely, content is everything in the site that has any information in it. For example, a blog post, a comment, a product and even the navigation menu or your company's logo are identifiable, individual pieces of content. If you were thinking at this moment that content is pretty much everything on the site you'd be right. If you were thinking that is pretty vague, you'd be right as well, but fortunately we will get a lot more specific and distinguish between different kinds of content in following sections. + +## Admin panel, Dashboard or back-end + +The admin panel (sometimes also called dashboard or back-end) is where you manage your site and its content. It is restricted to users who have the "Access admin panel" permission. This is the 'M' in CMS. + +![](../Attachments/Basic-Orchard-Concepts/Adminpanel.PNG) + +## CMS + +And the 'S' in CMS is for "System", which is not as vague and meaningless as it seems. It's important that CMS manage content in a systematic way: it means that all content is managed homogeneously, which enables mutuality of resources. + +For example, you can manage blog posts, pages and products using common tools, and all of those can get comments, ratings or tagging from common modules. This gives you a more consistent experience and facilitates the creation of new types of content. + +## Front-end + +The front-end is the part of the site that is accessible to regular and anonymous users. In other words, it's the public-facing part of your site: everything but the admin UI. + +![](../Attachments/Basic-Orchard-Concepts/FrontEnd.PNG) + +## Setup + +Setup is the process you must follow in order to get your web site to working condition (and no more than that, you still have work to do after it's done, such as creating content). + +![](../Attachments/Basic-Orchard-Concepts/Setup.PNG) + +# Orchard concepts + +## Content Item + +A content item is a single piece of content, often associated with a single URL (address) on the site. Examples of content items are pages, blog posts or products. + +## Content type + +Content items are instances of content types. Said differently, content types are classes of content items. We said in the previous section that examples of content items are pages, blog posts, and products. Those three examples also describe three content types: page, blog post and product. In other words what we call a blog post is just an item of type blog post. + +## Content Part + +In Orchard, content types are built from smaller parts, that are conveniently called content parts. Content parts are atoms of content that are enough to build a specific coherent behavior and that can be reused across content types. + +![A blog post is made from parts.](../Attachments/Basic-Orchard-Concepts/ContentParts.PNG) + +For example, comments, tags or ratings are content parts because they define a specific behavior and can be reused by any content type. There is nothing in comments that is specific to a given content type such as blog posts. Comments can be equally useful on blog posts as they would be on pages or products. + +There can be only one of each part on any given content type. + +## Content Field + +Content fields are pieces of information that can be added to a content type. Content fields have a name and a type and are specific to a content type. There can be several of each field type on any given content type. + +For example, a Product content type can have a text field representing its Sku, a numeric field representing its price, and another numeric field representing its weight. Each of these fields probably only makes sense on a product. + +> Note: it would be possible to create a product part with three properties that would be roughly equivalent to this set of fields. This would have the advantage of making it possible to transform any content type into a product. Each approach is a valid choice and Orchard allows for both. + +## Module + +The various possible custom possible extensions that can be built for Orchard are typically built as modules. A module is a set of extensions for Orchard that are grouped under a single sub-folder of the Modules directory that can be found under the Orchard web site. + +Optional modules for Orchard can be found in the Orchard Gallery (see the menu entry on top of this page). + +![The Module management screen](../Attachments/Basic-Orchard-Concepts/Modules.PNG) + +## Feature + +A module can contain one or more features, which is a logical grouping of functionality that can be enabled or disabled individually. For example, a custom authentication module could have separate features for OpenID, FaceBook, LiveID, Twitter or Google authentication that can each be turned on or off. + +Features can depend on each other, whether they are in the same module or not. + +![The feature management screen](../Attachments/Basic-Orchard-Concepts/Features.PNG) + +## Manifest + +A manifest is a small text file that describes a module or a theme to the system. + +Here is an example of a manifest: + + + Name: Comments + AntiForgery: enabled + Author: The Orchard Team + Website: http://orchardproject.net + Version: 0.9.0 + OrchardVersion: 0.9.0 + Description: The comments system implemented by this module can be applied to arbitrary Orchard content types, such as blogs and pages. It includes comment validation and spam protection through the Akismet service. + Features: + Orchard.Comments: + Name: Comments + Description: Standard content item comments. + Dependencies: Settings + Category: Social + + +# UI composition + +Orchard manages content that is composed from parts. It needs a mechanism that orchestrates the display while taking into account the composite nature of the content. This is why we talk about UI composition, as elementary bits and pieces of content need to be composed into a harmonious and consistent whole. Several concepts contribute to this UI composition. + +## Theme + +When designing a web site, it is important to be able to modify the visual look of every single aspect of the site. Orchard provides a clean separation between the content management and the visual rendering of the content. + +A theme is a packaged look and feel for an Orchard site. It can consist of any combination of style sheets, images, layouts, templates and even custom code. It is even possible to create a theme that inherits from another, which is very useful if you are trying to make only small modifications on an existing theme. + +![The same site can be displayed differently by switching themes.](../Attachments/Basic-Orchard-Concepts/ThemeComparison.png) + +## Layout + +A layout is a file in a theme that defines the general organization of the pages of the site that use it. A layout typically defines a set of zones where contents or widgets can be inserted. + +![The layout for the theme machine, with its various collapsible zones](http://orchardproject.net/docs/GetFile.aspx?Page=Anatomy-of-a-theme&File=TheThemeMachineZoneScreenshot.PNG) + +## Template + +Each content part, each field and each widget will need to be graphically represented in the front-end, transforming the data that it represents into a form that can be read by the users of the site. A template is the recipe that formats that data and transforms it into HTML for the browser to display. You can think of a template as plain HTML with well-defined "holes" where data gets inserted. + +Here is an example of a template that displays the title from the Route part: + + +

@Model.Title

+ + +## Shape + +Before displaying something using a template, that something gets transformed into a shape, which is a very malleable object that contains all the information required in order to display it. Before getting rendered by templates, everything gets mapped into a tree of shapes that is a sort of abstract representation of the contents of the final page. The advantage of such trees of shapes is that any module can modify existing shapes or create new ones. + +The layout, zones, widgets and content parts all get represented as shapes as part of the rendering process. + +One could imagine for example a Gravatar module that would add avatar icon shapes to the comment shapes that were created by the comment module. In the same way, the layers from the widget module are adding widget shapes to the zone shapes of the layout shape. + +## Placement + +When rendering the collections of parts and fields -or any other shapes- that compose a page or content item, Orchard needs to know in what order to do so. Placement.info files are XML files that describe rules that can be used to determine what shapes go into what zones and in what order. This enables not only the rendering of each shape to be customized, but also the order in which they get rendered. + +Here is an example of a placement file: + + + + + + + + +## Zone + +Zones are specific parts of a layout that can be customized by inserting widgets. In some themes, zones are collapsible, which means that they disappear if they contain no active widget. + +## Widget + +A widget is a small fragment of UI that can be added to some or all pages of the site. Examples of widgets are tag clouds, maps, archives, a search form, or recent blog posts. + +![A few widgets](../Attachments/Basic-Orchard-Concepts/Widget.PNG) + +## Layer + +A layer is a group of widgets (with their specific configuration, which includes their positioning -zone name and ordering-) that is activated by a specific rule. + +For example, the TheHomePage layer is activated by a rule that specifically selects the home page. The Default layer is always active no matter what page is displayed. The Authenticated layer is only active when users have identified themselves. + +When more than one layer is active on any given page, all the widgets from all those layers get displayed at the same time. Orchard orders them based on their position string. + +# Security + +## Users and roles + +In Orchard, users can be attributed roles, which can be seen as stereotypes of users. Permissions can then be attributed to roles in order to define who can do what on the site (more on this in the next section). Any user can have one or several roles. + +Site owners can create their own roles but Orchard comes with built-in roles that should cover most sites' requirements: + +* Administrator: have full control over the site's settings and contents. +* Editor: does not create content but edit and publish content created by authors. +* Moderator: validates user-created contents such as comments. +* Author: writes and publishes his own content. +* Contributor: writes content but does not necessarily have the rights to publish it. +* Anonymous: an unknown user, someone who hasn't logged in. +* Authenticated: any user who has logged in. + +Neither Anonymous nor Authenticated can be assigned to a user manually. Rather, they are determined dynamically at runtime. + +## Privileges and Permissions + +All users don't have the same rights and privileges in Orchard: the site owner can choose who can create content, who can write or validate comments, etc. Rights and privileges are represented as permissions. In Orchard, permissions are granted to roles but are not explicitly denied. In other words if a user belongs to any role that has a given permission, he has that permission. To revoke a permission, you need to either remove a user with the role the permission has been granted to or you need to remove that permission for the whole role. + +Some permissions are "effectively granted". This means that they have not been explicitly granted, but that they have been implied by another permission. For example, if you grant the site owner permission, you are implicitly granting all the other permissions. + +![](../Attachments/Basic-Orchard-Concepts/Permissions.PNG) + +Permissions, as well as their default settings for the built-in roles, are defined by modules. This means that if you build your own module, you can define specific permissions to accompany it. + +## Site owner + +The site owner, sometimes also called "super user" is a special user that is defined at setup time and that has all the rights on the site. It can be changed from the settings admin screen if you have the permission to do so. + +There is a permission called "Site Owners Permission" that grants the same right and that is granted by default to only members of the Administrator role. We advise never to grant that permission to any other role. + +# Development + +In this section we will describe concepts that are only required for module developers. + +## ASP.NET MVC + +ASP.NET MVC is the Web framework that Orchard is built on. + +## Handler + +A handler is similar to an MVC filter in that it contains code that will execute for specific events of the request life-cycle. They are typically used to set-up data repositories or to do additional operations when something gets loaded. + +## Driver + +Drivers are similar to MVC controllers, but they act at the level of a content part instead of at the level of the full request. They typically prepare shapes for rendering and handle post-backs from admin editors. + +## Record + +A record is a class that models the database representation of a content part. They are POCOs where each property must be virtual. + +## Model + +What plays the part of the model for a content part is the part class itself. Some parts also define view models, in the form of strongly-typed classes or of more flexible dynamic shapes. + +## Migration + +A migration is a description of the operations to execute when first installing a feature or when upgrading it from a version to the next. This enables smooth upgrades of individual features without data loss. Orchard includes a data migration framework. + +## Injection +Inversion of Control, or injection, is widely used in Orchard. When any piece of code requires a dependency, it will typically demand the injection of one or several instances of a specific interface. The framework will take care of selecting, instantiating and injecting the right implementations at runtime. + diff --git a/Documentation/Blogging-with-LiveWriter.markdown b/Documentation/Blogging-with-LiveWriter.markdown new file mode 100644 index 00000000..28f7af16 --- /dev/null +++ b/Documentation/Blogging-with-LiveWriter.markdown @@ -0,0 +1,62 @@ + +While Orchard provides a simple way to write blog posts using the built-in features of the admin panel, many people prefer to author posts using a client application, such as [Windows Live Writer](http://explore.live.com/windows-live-writer). These clients use an XML-RPC interface to publish posts remotely, and offer additional capabilities like saving offline drafts (for example, to write your blog posts on an airplane and sync-up your site later). + +To enable Remote Blog Publishing, click **Features** in the Orchard admin panel. + +To use Windows Live Writer with Orchard, you need to enable the **Remote Blog Publishing** feature. To enable **Remote Blog Publishing** click the **Enable** link on the feature box. Note that if you haven't already created a blog on your site, you'll want to do so. + +![](../Upload/screenshots_675/feature_enable_675.png) + +Now, launch Live Writer from your **Start** menu in Windows. + +![](../Upload/screenshots/live_writer.png) + +Choose **Add blog account...** from the **Blogs** menu. + +![](../Upload/screenshots/livewriter2.png) + +Choose **Other blog service** from the available options and click **Next**. + +![](../Upload/screenshots_675/livewriter3.png) + +Type the URL to your Orchard blog, along with the admin user name and password that you defined when you set-up Orchard for the first time. + +> Note: it is possible to publish using other XML-RPC aware client applications such as Microsoft Word, but you might have to provide the URL of the xmlrpc endpoint rather than the blog URL. For example, http://myimaginaryorchardsite.com/xmlrpc. + +![](../Upload/screenshots_675/livewriter4.png) + +Live Writer will connect to your blog in order to read the XML-RPC capabilities that Orchard supports and download the current Theme (for previewing posts before publishing). If you are prompted to create a temporary post during this step, select "Yes" in the dialog. + +![](../Upload/screenshots_675/livewriter5.png) + +After Live Writer is configured, click **Finish**. + +![](../Upload/screenshots_675/livewriter6.png) + +Write a title and some content for your blog post in the Live Writer editor area. + +![](../Upload/screenshots_675/livewriter7.png) + +You can also insert pictures to your post using the **Insert Picture** button on the toolbar. + +![](../Upload/screenshots_675/livewriter8.png) + +![](../Upload/screenshots_675/livewriter9.png) + +To edit the URL for your post, select **View / Properties** in the Live Writer menu. + +![](../Upload/screenshots_675/livewriter10.png) + +The **Slug** input appears at the bottom of the editor, where you can type the portion of the URL that refers to this post. + +![](../Upload/screenshots_675/livewriter11.png) + +To preview your post in the context of the currently applied Theme in Orchard, select the **Preview** tab in Live Writer. When you are satisfied with the way your post looks, click the **Publish** button. + +![](../Upload/screenshots_675/livewriter12.png) + +Live Writer publishes your post, and will automatically load the URL for the post in your browser for viewing. + +![](../Upload/screenshots/livewriter13.png) + + diff --git a/Documentation/Blogs.markdown b/Documentation/Blogs.markdown new file mode 100644 index 00000000..fb966d4d --- /dev/null +++ b/Documentation/Blogs.markdown @@ -0,0 +1,82 @@ + + +# Initial feature set + +## Post Creation & Administration +This feature makes it possible to create new blog posts as well as find and edit existing ones (see scenarios below). This should be a consistent user experience with [CMS page](pages). + +## XML-RPC / Live Writer Integration +The existing [XML-RPC features](xml-rpc) will be extended to work for blog posts. + +## Media Integration +The existing [media management](media-management) features will be integrated into the blog post editing experience (including Live Writer). + +## Drafts +Blog post drafts will be implemented in a way that is consistent with [CMS page](pages) drafts. + +## Scheduled Publication +Scheduled publication of blog posts will be implemented in a way that is consistent with [CMS page](pages) scheduled publication. + +## Multi-blog / Multi-author +This feature could potentially be postponed, but if implemented it enables multiple authors to maintain multiple blogs. A given author can create more than one blog, and a given blog can be contributed to by more than one author. + +The simple [permission model](users) may need to be modified to enable authorship delegation, or this can be implemented as an ad-hoc feature. + +## Archives +The list of posts can be displayed by month. A list of past months with the number of posts for each month can be displayed. + +## Linkback: trackback, pingback and refback +[Linkback](http://en.wikipedia.org/wiki/Linkback) is a generic term that describes one of the three current methods to manage posts linking to each other across blogs. + +The blog package should send trackbacks when a post gets created, and should receive refbacks, trackbacks and pingbacks. It should put all three through spam filters and should provide admin UI to manage the linkbacks and configure their moderation (moderation required or not, etc.). + +## Related aspects +A few features that are necessary for any blog engine will be implemented as aspects that can be applied to other content types in addition to blog posts. + +### List of Posts +Lists of content items need to be implemented for the blog front-end to work. This will be implemented as part of this iteration. + +### RSS/Atom +All lists in the application should be exposed as alternate views that conform to RSS and Atom. + +### Comments +Comments will be implemented with the bare minimum features (name, URL, e-mail, text, date). We will implement spam protection to an external service such as Akismet, and make it swappable in a future iteration. We will also support authenticated comments (captring user name for comments when a user is logged in). + +The implementation is described in [comments](comments). + +### Tags +Tagging is described in [Tags](Tags). + +### Search +Search will not be implemented in the initial blog iteration but will be added later as a cross-content-type aspect. + +### Themes +Themes will be implemented for the whole application in a later iteration. + +### Plug-ins +Plug-ins will be implemented in a future iteration and will be retrofitted into the existing blog code. + +### Background tasks +Background tasks will be implemented in this iteration and will be retrofitted where relevant into the existing pages code. + +### Widgets +Widgets will be implemented in a future iteration and will be retrofitted where relevant into the existing blog code. + +## Future features + +### BlogML import and export +This will provide a migration path to and from Oxite and other blogging engines. + +# Permissions +Here, owner means the post owner if acting on a post, the blog owner if creating a post, and the site owner when creating a blog. + +Permission | Anon. | Authentic. | Owner | Admin. | Author | Editor +------------------------------------------------ | ----- | ---------- | ----- | ------ | ------ | ------ +View Posts | Yes | Yes | Yes | Yes | Yes | Yes +Create & Manage Blogs | No | No | Yes | Yes | No | No +Create & Manage Posts (implies all others) | No | No | Yes | Yes | Yes | No +Create Drafts | No | No | Yes | Yes | Yes | No +Modify/Delete posts | No | No | Yes | Yes | Yes | Yes +Publish/Unpublish/Schedule posts | No | No | Yes | Yes | Yes | Yes + +Additional permissions may apply to aspects such as comments or tags. diff --git a/Documentation/Browsing-the-gallery-web-site.markdown b/Documentation/Browsing-the-gallery-web-site.markdown new file mode 100644 index 00000000..c7f9095e --- /dev/null +++ b/Documentation/Browsing-the-gallery-web-site.markdown @@ -0,0 +1,51 @@ + +The [Orchard Gallery web site](http://orchardproject.net/gallery) allows you to browse and search for available modules and themes to extend and customize the behavior of any Orchard site. It also provides a convenient way for developers and designers to [upload and share modules and themes with others](Contributing-a-module-or-theme-to-the-gallery). + +> You can also browse modules and themes from the gallery using the Orchard admin panel. Refer to [Installing modules and themes from the gallery](Installing-modules-and-themes-from-the-gallery) for more information. + +To view the gallery website, navigate to [http://orchardproject.net/gallery](http://orchardproject.net/gallery) in your browser. + +![](../Upload/screenshots_675/gallery_home.png) + +On the **Modules** tab of the website, you can browse and search for available modules. + +![](../Upload/screenshots_675/gallery_modules.png) + +Modules are categorized, so you can quickly find what you are looking for by clicking any category link or selecting from the category dropdown next to the search input box. + +![](../Upload/screenshots_675/gallery_category_email.png) + +The **Themes** tab displays a list of themes, similar to the modules section. Unlike modules, themes are not categorized. However, both modules and themes support tags that can be specified by the author/submitter, and you can click any tag link on the site to find other items that share that tag. + +![](../Upload/screenshots_675/gallery_themes.png) + +You can search for available themes or modules by typing keywords in the search input box. For modules, you can also search within a specific category or across all categories. + +![](../Upload/screenshots_675/gallery_search_blue.png) + +Each module or theme in the gallery has a details page that displays more information about the package, such as screenshots, the package version, number of downloads, license information, or a project site where you can learn more. There is a Report Abuse link on every details page that you can use to contact the gallery administrator to report inappropriate content or malware. Please use this for abuse reports only. If you want to report a bug or issue to the package author, please use the Project Site link instead. + +![](../Upload/screenshots_675/gallery_details_contoso.png) + +> Note that a few key gallery features are remaining to implement, and those will be available on the website as soon as they are ready. See "About the Orchard Gallery Project" below for more information + +## Multiple Versions of the Same Package + +Currently, each version of a package (module or theme) is listed as a unique entry in the web site, which can make it somewhat difficult to know whether you are downloading the most recent version. + +![](../Upload/screenshots_675/gallery_packageversions.png) + +We have plans to address this in a future update to the gallery website (see "About the Orchard Gallery Project" below). For now, we recommend that you search for the name of the package (without the version number) in order to list all versions of a given package before selecting one to download. + +## About the Orchard Gallery Project + +The gallery website (and related feed) implementation are being developed as an open source project under the same New BSD license and contribution terms as Orchard itself, and the source code is available to you on [OrchardGallery.CodePlex.com](http://orchardgallery.codeplex.com) and [GalleryServer.CodePlex.com](http://galleryserver.codeplex.com)). The open source gallery project is meant to provide a reference implementation for exposing a gallery feed and website, and can be used to set up your own gallery site. For example, the [NuGet.org](http://nuget.org) website uses this gallery implementation too. + +The gallery project is a work-in-progress, and there are a number of improvements we will be making to the gallery over time. In the near future, we are planning to implement these features: + +* Reviews and ratings +* Collapse all versions of a package under a single details page +* Display aggregate rating and download stats across all versions of a package +* Better management and submission interface for package submitters + +If you want to log a bug (or submit a patch) for the gallery website, or if you have a great feature suggestion we should consider, please post it to [OrchardGallery.CodePlex.com](http://orchardgallery.codeplex.com). diff --git a/Documentation/Bug-bash-1-18-2010.markdown b/Documentation/Bug-bash-1-18-2010.markdown new file mode 100644 index 00000000..e201f027 --- /dev/null +++ b/Documentation/Bug-bash-1-18-2010.markdown @@ -0,0 +1,96 @@ + + +* Archive data is not displayed in all themes (e.g. classic theme, green theme) +* Need a �Preview� button for editing pages and posts +* (loudej) Need to bring back the �Delete this draft� operation on the page/post editing page (perhaps as a small link to deemphasize it, ala WordPress) +* Theme Preview button to be implemented +* (heskew) Implement Javascript Datetime Picker for post/page scheduling UI +* (suhacan-FIXED) Need ability to delete a user in Manage Users +* (suhacan-FIXED) Bug: /Tags/{tagName} just redirects to /Tags (even when there are content items that tag is attached to) +* (suhacan-FIXED)Bug: Tags aren't added to a content item when the content item is first created (edit works fine) Repro: Add a blog post with a tag of "test" and save (and notice there is no tag of "test" on that blog post). +* (heskew-FIXED) Pre-fill comment form with authenticated user name and email <- authenticated user needs a different form (body only, other fields as hidden - include user name) since there's no reason for them to change the user info +* (heskew-FIXED) Tags and comments should work for CMS pages (aspect UI should appear on the Edit page admin screen, like for posts) + + +**Pri-2 Issues:** + +* Implement MORE tag support (excerpts) for posts (used on front-end list of posts for a blog) +* Validation on comment form (name, email required) +* Bug: create comment missing name or email -> create view not found. +* Bug: After creating a folder in media, you should get back to the folder where it was created, not to the media root. +* Bug: Uploading a zip full of media did not work but in a weird way (Ask Bertrand for the zip file) +* Bug: Media image captions do not seem to be persisted. Apply a caption to an image, save, navigate away and back to the image editing page: caption is gone. +* Front-end: Get rid of this on blogs list front end (see image screenshot in email) +* Front-end: Clean up on Blog and post details in front-end -- put Edit button and stats above and move blog/post text up (see image screenshot in email) + + +**Needs design (admin UI consistency issues):** _Jonathan and Michael are working on an admin UI proposal to share this week..._ + + +* Bulk operations on Manage Blog page (e.g. delete post) (put same drop downs that we have for pages on top of blog list) +* Bulk operations on Manage Blogs page, like CMS pages� (put same drop downs that we have for pages on top of blog post list) +* Ability to filter posts by published/draft/schedule on Manage Blogs , like CMS pages +* How to Unpublish a post on the Manage Blog page? Like CMS pages� +* Blog Details Page needs UI cleanup (placement, icons need text), also need ability to View blog from here: +* Media list is inconsistent: all other contents have separate edit links. For media, you click on the image name. +* All screens that have bulk actions have a header item in the drop down. Media has delete only (which also redirects to the root) +* Bug: Multiple error messages for the same thing (repro: media management, create a folder with an empty name: 2 errors message: 1 top message, 1 field validation) + + +**Pri-3 Issues:** + + +* Finalize this text: Possible text about setting up and managing a blog goes here. +* New Post: helper text for �Tags� (comma-separated) +* Finalize this text: "X" Allow new comments, Enable to show the comment form. Disabling still allows the existing comments to be shown but does not allow the conversation to continue. +* �Your Site� in Admin header should render Site Name setting instead (should be separate from �preview site� link?) +* Rename �Manage Folders� to �Manage Media� + + +**Do Later:** + + +* What UI do we want for change ownership? Do we want to display owner textbox on every content item? +* If only one blog, �Manage Blog� goes to blog details page. Else goes to list of blogs (as it is today). May also need a way to get to a specific blog from the admin panel menu. +Stylesheet applied to TinyMCE content should be style of applied theme. +* Revisit whether we should validate duplicate slugs at publish-time (log a bug for this) +* Uploading an image file should attempt to extract title or subject from embedded meta-data and make those the values for the image name and caption. +* The embed field could have script on focus that selects the whole value (makes it a lot easier to copy). +* The embed field could have a copy button. + + +**Untriaged:** +* None +* XMLRPC/LiveWriter support seems to be broken. I found Louis' previous instructions, which said to type �http://localhost:/xmlrpc. However, I tried that and it didn't work. Any ideas? + + +**No repro:** + + +* Tags mysteriously disappeared from my post after I deleted a tag from the tag admin. Can't reproduce it anymore though. (no clear repro for now...) + + +**DONE:** +* (erikpo-FIXED)When in an archive page, the archive navigation with the collapsible years should be there too. Here's what I was doing: I clicked on the January 2010 archive link from my blog, then I clicked the �2010� link. That didn't give me a way to get back to January. Two ways this can be fixed is by showing �subarchives� links under where you are (2010 would have a link for January) or you have the full archive menu there at all times (that's probably simpler). +* (rpaquay-FIXED) Attempting to access an incorrectly cased page results in a null ref exception: create a page with the slug "About" (uppercase A) then try to access "/about" (lowercase a). +* (erikpo-FIXED) Finish blog archive and remove fake archive data +* (rpaquay-FIXED) Bug: Exception: When creating a new post (no theme applied) - System.InvalidOperationException: The view 'NotFound' or its master was not found. +* (rpaquay-FIXED) Bug: Draft posts affect the number of posts listed for a blog (on front-end and back-end) +* (suhacan-FIXED) Bug: When saving a draft post, should redirect to/Edit admin URL for that post +* (suhacan-FIXED) Bug: When publishing a post from the �edit post� page, should redirect to the list of posts +* (suhacan-FIXED) Bug: Post Publishing Now button on Blog Details page throws 404 error +* (heskew-FIXED) Blog slug generation: "!!!Brad's Blog!!!" -Brad-s-Blog- (remove beginning/trailing slashes) +* (heskew-FIXED) Blog slug generation: "todo: (heskew) need path to here" +* (heskew-FIXED; still need to be selective on when to show the manage bits) When I'm on a post's front-end page, logged in as an admin/author/owner with the default blue theme, I don't have a direct link to edit the post. +* (rpaquay-FIXED) Page front-end has weird URLs: http://localhost:30320/Pages/Page/Item?slug=About (it used to work) (heskew: ISlugConstraint functionality hasn't been hooked up since cms pages migration) +* (rpaquay-FIXED) Why do published posts still say �Draft� on the blog front-end page? (bug <- related to create as published problems?) + + + +* (rpaquay-FIXED) Implement "true" versioning for blog posts (we currently only keep the latest version of posts in the DB) +* (heskew-FIXED) We need to use IDs instead of slugs for admin URLs where slugs aren't guaranteed to be unique +* (rpaquay-FIXED) Implement �?? comments� on: Manage Blog (for blog), Blog Details Page (for posts in a list) - both admin and front-end (for now we are going to append aspect UI in some deterministic order at some placeholder in a template, similar to what we do for aspects on a content item editor today). Will tackle the bigger problem of UI composition and placement within a template later (not sure if before Mix?). "xx Comments" in admin for blog post summary should be a link to comments page filtered on the blog post. FIX COMMENTS ON BLOG POST TO BE CONSISTENT! (Punt on blog for now) + + + +* (rpaquay-FIXED) FIX COMMENTS on blogs (same as posts, but aggregated for blogs) diff --git a/Documentation/Building-a-hello-world-module.markdown b/Documentation/Building-a-hello-world-module.markdown new file mode 100644 index 00000000..5731034c --- /dev/null +++ b/Documentation/Building-a-hello-world-module.markdown @@ -0,0 +1,166 @@ + +This article is describes how to build a very small module for Orchard that will just display a "hello world" page. + +Another simple example of a module can be found here: [Quick Start - Get module blueprint](http://orchardjumpstart.codeplex.com/) + + +# Introduction + +Orchard is built on top of ASP.NET MVC, which means that if you already know that framework you should feel right at home. If not, do not worry as we'll explain everything we're doing. + +MVC is a pattern where concerns are neatly separated: there is a model (M) for the data, a controller (C) that orchestrates the UI and determines how it operates on the model, and a view (V) whose only responsibility is to display what the controller hands it. + +In the case of our Hello World module, we won't have any data so the model will be of no concern to us. We will just have a controller and a view. All the rest will be some necessary plumbing to declare what we're doing to Orchard. We will come back to these concepts and recapitulate once we've built our module. + +Modules in Orchard are sets of extensions that can be packaged in order to be re-used on other Orchard sites. Modules are implemented as MVC Areas. Areas in MVC are sub-sites that contain a set of features that act in relative isolation from the other parts of the site. An Orchard module is simply an area with a manifest file. It may use Orchard APIs (but it doesn't necessarily have to). + +# Generating the Module Structure + +Before you can generate the file structure for your module, you need to download, install, and enable the **Code Generation** feature for Orchard. For more information, see [Command-line Code Generation](Command-line-scaffolding). + +Once you have code generation enabled, open the Orchard command-line, and create the `HelloWorld` module with the following command: + + + codegen module HelloWorld + + +# Modifying the Manifest + +You should now have a new HelloWorld folder under the Modules folder of your Orchard web site. In this folder, you'll find a module.txt file. Open it and customize it as follows: + + + name: HelloWorld + antiforgery: enabled + author: The Orchard Team + website: http://orchardproject.net + version: 0.5.0 + orchardversion: 0.5.0 + description: The Hello World module is greeting the world and not doing much more. + features: + HelloWorld: + Description: A very simple module. + Category: Sample + + +This text file is describing your module to the system. The information contained in this file will be used for example in the features administration screen. + +> Note: be careful to use spaces and not tabs to indent this file + +# Adding the Route + +Your module will have to handle the /HelloWorld relative URL under your Orchard web site. In order to declare what to do when that URL gets hit, create the following Routes.cs file in the HelloWorld folder: + + + using System.Collections.Generic; + using System.Web.Mvc; + using System.Web.Routing; + using Orchard.Mvc.Routes; + + namespace HelloWorld { + public class Routes : IRouteProvider { + public void GetRoutes(ICollection routes) { + foreach (var routeDescriptor in GetRoutes()) + routes.Add(routeDescriptor); + } + + public IEnumerable GetRoutes() { + return new[] { + new RouteDescriptor { + Priority = 5, + Route = new Route( + "HelloWorld", + new RouteValueDictionary { + {"area", "HelloWorld"}, + {"controller", "Home"}, + {"action", "Index"} + }, + new RouteValueDictionary(), + new RouteValueDictionary { + {"area", "HelloWorld"} + }, + new MvcRouteHandler()) + } + }; + } + } + } + + +A route is a description of the mapping between URLs and controller actions. This code maps the HelloWorld URL to the area HelloWorld with the Home controller and the Index action. + +# Creating the Controller + +The new module also has a Controllers folder ready to be filled. Create the following HomeController.cs file in that folder: + + + using System.Web.Mvc; + using Orchard.Themes; + + namespace HelloWorld.Controllers { + [Themed] + public class HomeController : Controller { + public ActionResult Index() { + return View("HelloWorld"); + } + } + } + + +This is the controller that will handle the requests for the HelloWorld URL. The default action, index, is requesting that the HelloWorld view gets rendered. + +Notice the Themed attribute on the controller class that will request that the view gets skinned with the currently active theme. + +# Creating the View + +In the Views folder, create a folder named Home. In the Views\Home folder, create the following HelloWorld.cshtml file: + + +

@T("Hello World!")

+ + +This file is specifying the core contents of our view. All the chrome around it will get added by the current theme's default layout. + +Notice that we used the T helper function that makes this view ready to be localized. This is not mandatory but it's a nice touch. + +# Adding the new files to the project + +We're almost done. The only task remaining is to declare to the system the set of files in the module for dynamic compilation. + +Open the HelloWorld.csproj file in a text editor and add the following lines after one of the </ItemGroup> tags: + + + + + + + + +Also add the following to the ItemGroup section that already has other Content tags: + + + + + +# Activate the Module + +Finally, you need to activate your new module. In the command line, type: + + + feature enable HelloWorld + + +You could also have done this from the "Features" screen in the site's admin UI. + +# Use the Module + +You may now add /HelloWorld to the URL of your Orchard site in your favorite web browser and obtain a nice Hello World message: + +![The UI for our completed module](../Attachments/Building-a-hello-world-module/HelloWorld.png) + +# Conclusion + +In this tutorial, we have built a very simple module that handles a route (/HelloWorld) through the home controller's index action and serves a simple view that gets skinned by the current theme. We have done so with only free tools and in a way that differs very little from what you would do in a regular ASP.NET MVC area. We did get a few things for free by making this an Orchard module, such as activation/deactivation of the module, or theming of the view with no effort on our part. + +Hopefully this will get you started with Orchard and prepare you to build more elaborate modules. + +The code for this topic can be downloaded from here: [HelloWorld.zip](../Attachments/Building-a-hello-world-module/HelloWorld.zip) diff --git a/Documentation/Building-and-deploying-Orchard-from-a-source-code-drop.markdown b/Documentation/Building-and-deploying-Orchard-from-a-source-code-drop.markdown new file mode 100644 index 00000000..8ece41c5 --- /dev/null +++ b/Documentation/Building-and-deploying-Orchard-from-a-source-code-drop.markdown @@ -0,0 +1,17 @@ + +This document is providing the steps in order to do so. + +If you just need to compile locally, and you want to use IIS on your dev machine instead of the built-in development web server, all you need to do is to go into the properties of the Orchard.Web project in Visual Studio, go to the Web tab and check "use local IIS Web Server" instead of the default development server. + +If instead what you need is a clean version of the application ready to run, follow the following steps: + +1. Make sure that you have either the .NET SDK or Visual Studio installed (in the latter case, make sure you are using a Visual Studio command prompt). +2. [Enlist in the source](http://orchardproject.net/docs/Setting-up-a-source-enlistment.ashx) +3. Open a command prompt at the location of your enlistment and run **build "compile;package"**. This will build the application into a "build" subdirectory. +4. Deploy the contents of the \build\Stage directory into a clean IIS web site's root directory. +5. If you are running on a 64 bit system, go into the advanced setting of the application pool for the application and make sure 32 bit applications are enabled (create a new app pool if you have to). +6. Create an App_data folder under the IIS application's root and make sure the user that IIS is running under has write access to that directory. If you're not sure what that user is, go to IIS Authentication for the application. If anonymous access is enabled, the user is the local IIS_USRS. Make sure the directory is empty. +7. Create a Media folder under the IIS application's root and give write access. +8. Browse to the application. You should see the setup screen at this point. + +Note: if you are using IIS6, you need to configure the star mapping: . diff --git a/Documentation/Code-conventions.markdown b/Documentation/Code-conventions.markdown new file mode 100644 index 00000000..0c9c1365 --- /dev/null +++ b/Documentation/Code-conventions.markdown @@ -0,0 +1,30 @@ + + +## Definitions +* [Camel case](http://en.wikipedia.org/wiki/CamelCase) is a casing convention where the first letter is lower-case, words are not separated by any character but have their first letter capitalized. Example: thisIsCamelCased. +* [Pascal case](http://c2.com/cgi/wiki?PascalCase) is a casing convention where the first letter of each word is capitalized, and no separating character is included between words. Example: ThisIsPascalCased. + +## C# Coding Conventions + +We are using the C# coding conventions described in this document: [C# Coding Guidelines](http://blogs.msdn.com/brada/articles/361363.aspx) with the following exceptions: + +* Opening braces are on the same line as the statement that begins the block, with a space before the brace (this is consistent with what we do in JavaScript), a.k.a. K&R convention. +* Private fields are prefixed with an underscore and camel-cased. +* Using directives appear before the namespace, not inside it. + +## JavaScript Coding Conventions + +* Namespaces are Pascal-cased. +* Class names are Pascal-cased. +* Plugin names are Camel-cased. +* Properties, fields, local variables are Camel-cased. +* Parameters are Camel-cased. +* Function names are Camel-cased unless they really are class constructors or namespaces (in other words, global/local functions and methods are Camel-cased). +* Private/internal/protected members are underscore-prefixed and Camel-cased. +* Constants are just static fields (apply same rules as for fields). +* JavaScript coding conventions follow C# conventions except for Pascal vs. Camel. +* " and ' are interchangeable (strictly equivalent). XHTML attributes should be in double quotes and if code needs to be in there, it has to use single quotes. ex: (note: this kind of DOM-0 event creating is itself discouraged and is only shown here as an example). In pure JS code, use double quotes for string delimiters. When the string is one character and the intent is a character, use single quote for consistency with managed code. +* There is no need for String.Empty, just use "". +* Localizable strings need to be isolated into resource dictionaries until we figure out our client localization story. ex. alert(Foo.badArgument); ... Foo = {badArgument: "Teh argument was bad."}; +* Don't worry about string concatenation unless you have specific evidence that regular concatenation is significantly harming performance in your specific scenario. +* Use the [K&R](http://en.wikipedia.org/wiki/Indent_style) style for opening braces (put the opening brace on the opening line). This is because in JavaScript, the semicolon is optional, which can cause difficult to spot bugs (see [http://msmvps.com/blogs/luisabreu/archive/2009/08/26/the-semicolon-bug.aspx](http://msmvps.com/blogs/luisabreu/archive/2009/08/26/the-semicolon-bug.aspx) for an example). diff --git a/Documentation/Command-line-scaffolding.markdown b/Documentation/Command-line-scaffolding.markdown new file mode 100644 index 00000000..c95915cf --- /dev/null +++ b/Documentation/Command-line-scaffolding.markdown @@ -0,0 +1,40 @@ + +Code generation is an Orchard module that automates the task of creating additional files and extensions. This feature is useful for developers that want to create controllers, data migration classes, modules, and themes. However, the code generation feature is not installed by default when you install Orchard. + +You can install the code generation feature using the Orchard Gallery. Open the admin panel, click **Modules** under the **Gallery** heading. + +![](../Upload/screenshots_675/gallery_modules_675.PNG) + +Find the **Code Generation** module, and click **Install**. + +![](../Upload/screenshots_675/gallery_code_generation_675.png) + +To enable code generation, click **Features** under **Configuration**, find the **Code Generation** feature, and click **Enable**. + +![](../Upload/screenshots/enable_codegen.png) + +To enable the feature from the Orchard command-line, open the orchard command-line, and enter the following command. For more information about the Orchard command-line, see [Using the command-line interface](Using-the-command-line-interface). + + + orchard> feature enable Orchard.CodeGeneration + Enabling features Orchard.CodeGeneration + Orchard.CodeGeneration was enabled + + +Once the code generation feature is enabled, new commmands are available for creating a module, theme, data migration, or controller. Currently, the code generation commands add files to the appropriate location. + + + codegen controller + Create a new Orchard controller in a module + + codegen datamigration + Create a new Data Migration class + + codegen module [/IncludeInSolution:true|false] + Create a new Orchard module + + codegen theme [/CreateProject:true|false][/IncludeInSolution:true|false][/BasedOn:] + Create a new Orchard theme + + +For a walkthrough of using the code generation feature to create a new module and data migration, see [Writing a content part](Writing-a-content-part). diff --git a/Documentation/Comments.markdown b/Documentation/Comments.markdown new file mode 100644 index 00000000..1df9b2f2 --- /dev/null +++ b/Documentation/Comments.markdown @@ -0,0 +1,109 @@ + + +# Scenarios + +## A user can comment content entries + +1. User browses the site and wants to comment a blog post + +2. User scrolls down to the bottom of the post and starts entering the mandatory information: name, e-mail and comment. He also enters the URL of his own blog and checks "remember me" so that he doesn't have to enter that information when he returns. He clicks the "add comment" button. + +Validation rules check that the e-mail, name and text was entered before validating the comment. + +When "remember me" is checked, a cookie with a long expiration is set on the client to store the information to remember. + +3. The comment is published after validation by the spam filter. + +## A user can receive notifications when answers to his comments are published + +1. When adding a comment, a user can check "receive e-mail notifications for new comments on this post". + +2. A new comment gets added to the same post. + +3. The user receives an e-mail to notify him of the new comment. +The e-mail contains the text of the new comment and a link (using a # anchor) to the new comment. + +**Status: Not implemented yet** + +## A user can subscribe to the comments feed for any item + +1. The user can use the feed icon for the comment stream to add it to his favorite feed reader (modus operandi varies with readers and browsers). + +2. New comments get published. + +3. User sees the new comments in feed reader. + +**Status: Not implemented yet** + +## The site administrator gets notified when new comments are added + +1. A user adds a comment. + +2. The administrator receives an e-mail with a link to the admin UI for comments. + +3. The administrator can then click on a comment and moderate it or click the link to the content item in order to answer the new comment. + +**Status: Not implemented yet** + +## The site administrator can manage comments + +1. The administrator of the site clicks "Manage comments" from the admin UI's global menu or from a "manage comments for this item" link at the bottom of the admin UI for a specific content item or from an alert e-mail he received from the site. + +2. He checks the checkbox in front of a bunch of comments he recognizes as spam, chooses the "Delete" bulk action and clicks "Apply". + +3. He clicks on a specific unpublished comment, reads it and then clicks "publish". + +4. The new comment can be read by anyone. + +## The site administrator can configure comment publication rules + +1. The administrator goes to the permission administration screen. + +2. He changes the "Add a comment without validation" right to apply only to authenticated users. + +3. Comments by non-authenticated users are not published by default anymore, but only when an administrator publishes them. + +## A content owner can close comments on his items + +1. A content author feels the comment thread on one of his blog posts is spinning out of control into a troll fest. + +2. He clicks "Close comments on this item". + +3. No new comments can be added. + +## Comments are threaded + +1. A user sees a specific comment he wants to answer. + +2. He clicks the "reply" button next to that specific comment. + +3. He types an answer that is stored as an answer to the original comment. + +4. The resulting new comment gets added at the end of the comment thread and has a link to the original comment. + +## Authenticated users and author comments appear different + +1. An author answers a comment on one of his content items. + +2. His comment appears in the comment thread with a different style. + +**Note:** authenticated users' comments could also appear differently (from non-authenticated and also from author comments) as they can have a different weight in people's minds on some sites. + +# Spam protection + +Spam protection is strictly necessary on a comment feature but is difficult to implement. Fortunately, many solutions already exist and can be integrated into existing applications. + +The comment infrastructure should be ready to be extended with various spam protection technologies such as CAPTCHA or Akismet. We will integrate Akismet by default and make it easy for users to obtain their own Akismet key. + +Administrators can mark comments as spam rather than delete them, which could result in the comment being fed into the spam protection provider's feedback service. + +# Permissions +In this context, the owner is the owner of the content item being commented (the container of the comments). + + +Permission | Anon. | Authentic. | Owner | Admin. | Author | Editor +------------------------------------------------ | ----- | ---------- | ----- | ------ | ------ | ------ +Add Comments | Yes | Yes | Yes | Yes | Yes | Yes +Manage Comments (implies all others) | No | No | Yes | Yes | No | Yes +Close Comments | No | No | Yes | Yes | Yes | Yes +Moderate comments | No | No | Yes | Yes | No | Yes diff --git a/Documentation/Common-Issues.markdown b/Documentation/Common-Issues.markdown new file mode 100644 index 00000000..6ddfdaf4 --- /dev/null +++ b/Documentation/Common-Issues.markdown @@ -0,0 +1,19 @@ + +If you receive this error: + + + Server Error in '/' Application. + + Configuration Error + + Description: An error occurred during the processing of a configuration + file required to service this request. Please review the specific error + details below and modify your configuration file appropriately. + + Parser Error Message: It is an error to use a section registered as + allowDefinition='MachineToApplication' beyond application level. + This error can be caused by a virtual directory not being configured as + an application in IIS. + + +It may be because the folder where the Orchard web application is installed is not configured to be an application. This can be fixed by going into the IIS configuration and making the folder an IIS application. diff --git a/Documentation/Community-resources.markdown b/Documentation/Community-resources.markdown new file mode 100644 index 00000000..e69de29b diff --git a/Documentation/Configuring-email.markdown b/Documentation/Configuring-email.markdown new file mode 100644 index 00000000..e69de29b diff --git a/Documentation/Configuring-shared-hosting.markdown b/Documentation/Configuring-shared-hosting.markdown new file mode 100644 index 00000000..e69de29b diff --git a/Documentation/Content-types.markdown b/Documentation/Content-types.markdown new file mode 100644 index 00000000..6132102d --- /dev/null +++ b/Documentation/Content-types.markdown @@ -0,0 +1,227 @@ + +At the core of the idea of CMS is the ability to extend the system to new content types instead of restricting it to pre-defined ones such as blog posts. + +Orchard has a rich composition model that enables new content types to be created from existing parts and extended at runtime. It also enables a development model that is code-centric rather than database-centric: for all practical purposes, database persistence will just happen without the developer having to do anything beyond defining the shape of his objects in code. + + +# Basic Concepts + +## Content Item +A content item is a piece of content that you'd want to manipulate as a single entity. For example, a blog post is composed of many parts: there is a title, a body, an author, comments, tags, etc. But it is clear that the entity that you want to manipulate is the blog post as a whole. Other examples of content items are images, videos, wiki pages, products, forum threads, etc. + +A content item has an integer id that is unique across the site. + +The definition of a content item is voluntarily relatively vague, because we don't want to restrict what is considered a content item, so that developers can apply the same concepts to a wide array of objects. + +## Content Type +A content type can be seen as a category of contents; it represents what a content item is. For example, it's easy to understand that a content item is a blog post, or a photo, or a wiki page. The core of the notion here are in the words "is a": if you can say that a given content item is a "something", that "something" probably is the content type of the content item. + +In developer speech, this concept is analogous to the concept of class, although the Orchard type system is established at run-time rather than statically determined from definitions in source code. + +A content type in Orchard is just a name (in other words, it's identified by a simple string). + +## Content Part +Content items in Orchard are composed from existing nuggets of data and logic called content parts. A content part packages the set of fields and methods that are necessary to implement a particular reusable aspect of a content item. + +All the parts that form a given content item share the same integer id. + +For example, the "HasComments" part has two properties, a list of comments and a flag that determines whether the comment thread is closed. That part can be added to a content type to make it commentable. In this system, the comment aspect doesn't need to know what it's commenting, and the commented item doesn't need to know that it has comments. + +This of course provides high reusability as the composed units are narrow and loosely-coupled aspects. Still, the size of the aspects is large enough that they can package a whole feature (as opposed to field-level composition that does not enable rich feature sets to be encapsulated as one single entity, and to type-level definition of behavior that doesn't provide easy reuse of cross-concerns that apply to more than one content type). + +## Record +A record is a concept that only needs to be known to content-type developers and that doesn't need to surface to the end user of the application. + +A record is the simple code representation of a content part, as an almost Plain CLR Object. "Almost" because it derives from ContentPartRecord, which gives them an Id and a reference to the content item the part is participating in. + +## Content Handler +A content handler is the object that manages content items and parts. It is a set of services that will chime in whenever the application needs to create parts or items, among other tasks. Content providers are built around the idea of a filter, where the application calls into all filters when it needs something, and each filter can decide whether to participate or not, depending on the parameters communicated by the application. + +For example, a content handler could look at the content type and decide based on it to add a specific part to the current content item. + +Most handlers are implemented as a simple assemblage of pre-defined filters, as we'll see in the actual example below. + +# Building a new content type +In this example, we'll build a simple content type that just consists of a single name field at first, to which we'll add parts and settings. + +The first part of this is done by creating a simple record class: + + + namespace Orchard.Sandbox.Records { + public class SandboxPageRecord : ContentPartRecord{ + public virtual string Name { get; set; } + } + } + + +Very straightforward stuff here. + +First, we work in a "Records" or "Models" namespace. This is actually an important convention as this namespace pattern will enable automatic database persistence of our objects. + +Then, we create a simple record class that derives from ContentPartRecord. The base class here gives us an Id and a reference to the content item this part will help represent. Notice here that this is implemented as a part, but it's the one part that will be used only for our content type that does not have a vocation to be re-used. For all practical purposes, this is the part that will be the most representative of the whole content type. + +Finally, we define the name property as a read/write string. + +## Choosing the parts +On its own, the part we just defined isn't doing much. To fix this, we'll add the following parts: + +* CommonAspect gives an owner, created and last modified dates as well as an optional container (useful for hierarchies of content items such as a book containing chapters that contain pages that contain paragraphs that have comments for example). +* Routable gives the item a title and a slug, making it possible to navigate to the item as a page in the front-end. +* Body adds a body field and a format for that body. + +## Building the content handler +This is done from a new content handler that we're defining as follows: + + + namespace Orchard.Sandbox.Models { + public class SandboxContentHandler : ContentHandler { + } + } + + +Again, the namespace is not neutral here as it enables the application to discover the content handlers dynamically at runtime. + +Adding the parts is done from the constructor of the handler class: + + + public SandboxContentHandler( + IRepository pageRepository, + IRepository settingsRepository) { + + // define the "sandboxpage" content type + Filters.Add(new ActivatingFilter("sandboxpage")); + Filters.Add(new ActivatingFilter("sandboxpage")); + Filters.Add(new ActivatingFilter("sandboxpage")); + Filters.Add(new ActivatingFilter("sandboxpage")); + Filters.Add(new StorageFilter(pageRepository) { AutomaticallyCreateMissingRecord = true }); + + // add settings to site, and simple record-template gui + Filters.Add(new ActivatingFilter>("site")); + Filters.Add(new StorageFilter(settingsRepository) { AutomaticallyCreateMissingRecord = true }); + Filters.Add(new TemplateFilterForRecord("SandboxSettings")); + + } + + +This code is the first time the actual content type makes an apparition as the "sandboxpage" string (we are repeating a string constant here for clarity but you'd of course move that to a constant in real code). Each ActivatingFilter that is added here adds a part any time a content item of type "sandboxpage" is created by the application. + +One thing to notice is that we're not using the SandboxPageRecord directly here, but the SandboxPage, which is the actual part. This class is defined as follows: + + + namespace Orchard.Sandbox.Models { + public class SandboxPage : ContentPart, IContentDisplayInfo { + string IContentDisplayInfo.DisplayText { + get { return Record.Name; } + } + } + } + + +The part is defined as a ContentPart of SandboxPageRecord, which gives calling code access to the data for the part through the Record base property. It also implements IContentDisplayInfo, which enables the application to have a uniform way of displaying a short text representing a content item. It is implemented here to surface the value of the Name property. + +We also create a storage filter for our own part from this handler to tell the system to use a repository of sandbox page records for storage. We don't have to worry about the storage of the other aspects in our content type as it will be handled by the handler for each of those parts (which probably has a storage filter of their own). + +## Settings +Our content type has a few settings that can be configured from the site settings page. The settings themselves are defined by a part for which the record is defined like follows: + + + namespace Orchard.Sandbox.Models { + public class SandboxSettingsRecord : ContentPartRecord { + public virtual bool AllowAnonymousEdits { get; set; } + } + } + + +Because this settings part is going to be very simple (it's pure data from a single part), we can build a part from the record generically: ContentPart. + +The code in our handler above (there is no need for a separate handler for the settings) adds an activating filter for that settings part, filtered on the "site" content type. Site is a special content type that represents the global settings of the site. With that simple filter, we've dynamically added our own settings to the global site settings. + +Then, we have the storage filter for the settings that is similar to the one for the part itself. + +Finally, we have a template filter, which is pointing the system to the editor to use for our settings record. The template should be located in packages/orchard.sandbox/Views/Models/EditorTemplate and called "SandboxSettingsRecord.ascx". The code for it can be: + + + <%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %> +

Sandbox

+
    +
  1. + <%= Html.LabelFor(x=>x.AllowAnonymousEdits) %> + <%= Html.EditorFor(x=>x.AllowAnonymousEdits) %> + <%= Html.ValidationMessage("AllowAnonymousEdits", "*")%> +
  2. +
+ + + +## Admin Menu +Modules also have a way to plug into the admin system. This can be accomplished by using the INavigationProvider interface in the Orchard.UI.Navigation namespace. + + + public class AdminMenu : INavigationProvider { + public string MenuName { get { return "admin"; } } + + public void GetNavigation(NavigationBuilder builder) { + builder.Add("Sandbox", "1", + menu => menu + .Add("Manage Pages", "1.0", item => item.Action("List", "Admin", new { area = "Orchard.Sandbox" }).Permission(StandardPermissions.AccessAdminPanel))); + } + } + + +Note that we're using Orchard.Security.StandardPermissions.AccessAdminPanel here. You can just as easily define your own permissions using the IPermissionProvider interface. + +## Adding the Module.txt +For Orchard to pick up your module in the system, there needs to be a Module.txt file with your package name in it like this: + + name: Sandbox + + +# Using our new content type +To use content types from a controller's code, you need to inject an instance of the content manager and of any repository that you want to use: + + + namespace Orchard.Sandbox.Controllers + { + public class PageController : Controller { + private readonly IContentManager _contentManager; + + public PageController(IContentManager contentManager) { + _contentManager = contentManager; + } + } + } + + +## Creating items of the new type +You can create a new sandbox page by calling the Create method of the content manager: + + + var page = _contentManager.Create("sandboxpage", item => { + item.Record.Name = "My page"; + }); + + +## Querying the catalog +To get a specific content item of which you know the id, you can call: + + + var page = _contentManager.Get(id); + + +It is also possible to create more general queries against the content manager, that can return lists that contain items of various types: + + + var items = _contentManager.Query("blogpost", "sandboxpage") + .Where(b => b.Body.Contains("foo")) + .OrderBy(r => r.Title) + .Slice(10, 5); + + +The code above will get the items 10 to 15 in the list of blog posts and sandbox pages that have "foo" in their bodies, when ordered by title. + +## Accessing the parts of the item +To access the different parts of a content item, you can call the Get method on any of the parts: + + + var body = mypage.Get().Body + diff --git a/Documentation/Continuous-integration.markdown b/Documentation/Continuous-integration.markdown new file mode 100644 index 00000000..4c685384 --- /dev/null +++ b/Documentation/Continuous-integration.markdown @@ -0,0 +1,6 @@ + +There are currently two builds configured: "Continuous Builder" that runs on every check-in and "Full Build" that runs nightly. They are currently identical but eventually the nightly will also run functional tests. + +## Code Coverage + +Code coverage data is being generated with each run of both builders. The code coverage data can be viewed by clicking the "Code Coverage" tab of the project or by going into the artifacts tab and downloading the source and coverage zips that can then be used from the [NcoverExplorer](http://www.kiwidude.com/blog/2007/09/ncoverexplorer-v140.html) to explore code coverage to the level of the line of code. diff --git a/Documentation/Contributing-a-module-or-theme-to-the-gallery.markdown b/Documentation/Contributing-a-module-or-theme-to-the-gallery.markdown new file mode 100644 index 00000000..506ce171 --- /dev/null +++ b/Documentation/Contributing-a-module-or-theme-to-the-gallery.markdown @@ -0,0 +1,130 @@ + +Have you created an Orchard module or theme that you want to share with other Orchard users? The [Orchard Gallery](http://orchardproject.net/gallery) makes this easy, and you can always update and manage your contributions to the gallery as you have new versions to share, or when you want to make changes to existing contributions. + + +To get started, click on the **Contribute** tab of the gallery site. + +![](../Upload/screenshots_675/gallery_contribute.png) + + +## Creating a User Account + +To [submit a module or theme to the gallery](#submittingapackage), you must first create a user account on the gallery. Click the **Sign In** link in the header area of the site to get to the **Log On** page. In the sidebar for the site, click the link to **Register Now**. + +![](../Upload/screenshots_675/gallery_logon.png) + +On the account registration page, specify your account details. + +![](../Upload/screenshots_675/gallery_register.png) + +Upon submitting this form, you will receive a notification that email has been sent to you. + +![](../Upload/screenshots_675/gallery_emailsent.png) + +Click the verification link in the email in order to activate your account. + +![](../Upload/screenshots_675/gallery_email.png) + +This will return you to the web site, where you can now sign in. + +![](../Upload/screenshots_675/gallery_emailsuccess.png) + + +## Submitting a Package to the Gallery + +A package is just a zipped up file (in [.nupkg](http://nuget.org) format) containing your module or theme, and it is easy to create a package using the orchard command-line utility. For instructions on how to create a package, refer to these topics: + +* [Packaging and sharing a module](Packaging-and-sharing-a-module) +* [Packaging and sharing a theme](Packaging-and-sharing-themes) + +Once you have packaged your module or theme, visit the **Contribute** page on the gallery site and click the **Add a New Module or Theme** link. + +![](../Upload/screenshots_675/gallery_contribute_addpackage.png) + +Uploading a package is done in three simple steps: + +1. Upload a package file (or specify a remote URL to the package file) +2. Enter the details about your package (description, tags, license, etc) +3. Specify an optional logo and/or screenshots. + +### Specifying a Package File +In the first step, you will be asked to specify a package file, either by uploading from your local computer or by a specifying a URL. + +![](../Upload/screenshots_675/gallery_contribute_uploadpackage.png) + +To upload a package file, browse for a .nupkg file on your local computer that you created using the Orchard command-line utility. You can also specify a URL to a package file if you have published it elsewhere. For example, if you have released your package on a [CodePlex.com](http://codeplex.com) site, you could specify the URL to your release. + +* Example URL: [http://orchardmaps.codeplex.com/Project/Download/FileDownload.aspx?DownloadId=187223](http://orchardmaps.codeplex.com/Project/Download/FileDownload.aspx?DownloadId=187223) + +In this walkthrough, we will assume you are browsing for the package on your local computer. Click the **Browse** button to find the .nupkg file. + +![](../Upload/screenshots_675/gallery_contribute_uploadpackage2.png) + +### Specifying the Package Details + +Once you upload your package, click **Next** and you will be presented with a form for specifying the details of your package. One of the advantages of using the .nupkg format is that the gallery can automatically extract many details about your package from the file itself. These details are determined by the Module.txt or Theme.txt file in your module or theme. + +Many of the fields on this form are optional, but allow you to specify tags, license information, a project web site, and other information that will help visitors of the gallery to find and learn more about your package. + +![](../Upload/screenshots_675/gallery_contribute_packagedetails_full.png) + +There are a couple key fields worth calling out: + +* **Package ID** is the unique name for your package. It is obtained from the package when you upload it, and if you are the first person to submit a package with this ID, you will given exclusive ownership for that ID. While you can upload additional versions of packages sharing this ID, no other submitter will be able to use this ID for their package uploads unless you grant explicit owner rights to that user (see [Assigning additional owners for a package](#assignpackageowners)). It is also possible to [register a package ID in advance](#registerpackageid) of uploading your module, to be sure you can claim the name that you want. + +* **Package Version** is a version number for the package, and must be unique among all other packages in the gallery that same the same package ID. Every time you submit a package to the gallery, you will need to increment the version number for your package. This allows users of your package to know when a new version is available. + +* **Package Type** is what determines whether your package will appear on the Modules or Themes tab of the gallery site. Be sure to pick the right type for your package! + +### Specifying a Logo and Screenshots + +In the final step of the submission process, you can specify a custom logo image and zero or more screenshot images, which users will be able to see on the details page for your package. Both of these are optional, so feel free to skip this step, if you prefer not to customize the default images. + +![](../Upload/screenshots_675/gallery_contribute_screenshots.png) + +When you finish the submission, you will be notified that your package will appear on the gallery shortly. Normally, your package will appear on the site in 60 seconds or less. + +![](../Upload/screenshots_675/gallery_contribute_submissioncomplete.png) + + +## Managing your Contributions to the Gallery +Once your package appears on the web site, you will notice that you can perform additional tasks for this package when you are logged in: + +![](../Upload/screenshots_675/gallery_testpackage.png) + +* **Edit** allows you to return to the package details form and update information about your package. +* **Manage Owners** allows you to assign additional owners for your package. See [Assigning additional owners for a package](#assignpackageowners). +* **Delete** allows you to delete a submission from the gallery. Note: When you delete a submission, you will lose the download count history for that package version. + +To see all of the packages that you previously uploaded to the gallery, visit the **Contribute** tab and click the **Manage My Contributions** link. + +![](../Upload/screenshots_675/gallery_contribute_managecontributions.png) + + +## Assigning Additional Owners to a Package + +By default, you will be the only owner for packages that you contribute, and only you can edit, delete, or manage owners for the package. However, by assigning additional owners, you can grant permissions to other users of the gallery to perform these operations on your package too. + +> Be careful that you trust users you grant ownership rights, as they will be able to perform all of the same operations on the package that you can perform, including deleting your package from the gallery. Also, anyone with ownership rights to your package can upload additional versions of this package to the gallery. + +![](../Upload/screenshots_675/gallery_manageowners.png) + + +## Registering a Package ID in Advance + +You may want to register a package ID ahead of time, because you want to claim the name of an idea, before you've implemented your module or theme. You can do this from the **Contribute** tab of the site. + +![](../Upload/screenshots_675/gallery_contribute_registerpackageid.png) + +> It is a known issue that you cannot see the packages that you have previously claimed. This will be fixed in a future update to the gallery site. + +## Managing Your Account + +The **My Account** link allows you to manage your gallery account. + +![](../Upload/screenshots_675/gallery_myaccount.png) + +You can view your account key and reset your password from here. You account key is used when using the [NuGet.org](NuGet.org) command-line utility to upload a package to the gallery feed. + +![](../Upload/screenshots_675/gallery_myaccount2.png) + diff --git a/Documentation/Contributing-documentation.markdown b/Documentation/Contributing-documentation.markdown new file mode 100644 index 00000000..356fb6e0 --- /dev/null +++ b/Documentation/Contributing-documentation.markdown @@ -0,0 +1,6 @@ + +At the beginning of your topic, add a statement that clearly identifies the version of Orchard the topic was written for, such as the following. + +> This topic targets, and was tested with, the Orchard 0.8 release. + +Make sure you test all code and markup with the targeted version of Orchard. diff --git a/Documentation/Contributing-patches.markdown b/Documentation/Contributing-patches.markdown new file mode 100644 index 00000000..bb39b4b3 --- /dev/null +++ b/Documentation/Contributing-patches.markdown @@ -0,0 +1,66 @@ + +Creating **a fork should be preferred** because it makes merging a lot easier. + +## Working on a Patch + +When working on a patch, your local enlistment should in most cases be synchronized to the latest check-in in the **contributions** branch (contributions tip). Working on the dev branch would only expose you to nasty things (like the application breaking all the time). + +Another thing to consider is the status of the issue you are fixing. Bugs that are marked as "Proposed" have been reported, but not yet triaged by the team. It just means that we didn't have time to look at them and see if they are valid, or duplicates of existing issues, or have since already been fixed. Thus, for best results, please send patches for issues that are marked as "Active". + +Please only fix one issue per patch: if one fix is rejected and the other accepted, it would be more difficult for us to integrate the accepted fix and we might have to reject the whole patch and ask you to resubmit. One fix per patch also makes the source tree's history cleaner and more readable. + +## Submitting a Patch as a Fork + +If you go to the source code tab of the project, you'll see links on the top of the page to manage and create forks. Each fork is a copy of the full source code repository that you own entirely. + +You can create a new fork by clicking "Create fork". You can then enter a name for your fork, typically the name of the feature you want to work on or a bug number if you're patching a bug. The description is optional. + +Once you've hit save, you'll see a view of the forks that you own. Each of them has its own clone URL. What you want to do next is clone that remote CodePlex repository to your local machine in order to be able to start working. + +Once you've made your changes and are ready to submit them back to us, right-click the clone directory and choose "Hg commit". Click "commit". This commits the change to the local repository clone. The patch has not yet been submitted to CodePlex. + +![](../Upload/submitting-patches/HgCommit_675.PNG) + +Next, you'll want to push your changes to your private fork on CodePlex through the Hg Repository Explorer. + +Before preparing to submit a contribution, be sure to: +1. Mark new files as added +2. Mark missing files as deleted +3. Use Hg update to ensure the local copy is current +4. Verify sources build and unit tests pass +5. Do any merge and re-base operations necessary to get your local change tree to what you actually want to submit (see [Mercurial documentation](http://mercurial.selenic.com/wiki/Mercurial) if in doubt about what this means). In particular, before you submit, your enlistment should be **merged into contributions tip**. + +Once this is done, your changes are on CodePlex, but not yet in the project's official repository. To get it there, you'll need to ask us to pull the changes in. In order to do that, send us a pull request from the fork management screen under the source control tab on CodePlex: + +![](../Upload/submitting-patches/PullRequest.jpg) + +You will receive an e-mail update from us when your patch submission has been evaluated and applied. + +More information about fork management on CodePlex can be found in this post: . + +## Submitting a Patch as an Attachment to an Issue + +An alternative to using a fork is to package your changes into a file and then to attach that file to the issue or feature proposal corresponding to your patch. + +In order to prepare your patch, you'll need to get a local enlistment of the source code of the application and work off of that. + +Before preparing to submit a contribution, be sure to: +1. Mark new files as added +2. Mark missing files as deleted +3. Use Hg update to ensure the local copy is current +4. Verify sources build and unit tests pass +5. Do any merge and re-base operations necessary to get your local change tree to what you actually want to submit (see [Mercurial documentation](http://mercurial.selenic.com/wiki/Mercurial) if in doubt about what this means). + +Once this is done, go into the Repository Explorer for your local enlistment, right-click your latest revision and choose "Export Patch...": + +![](../Upload/submitting-patches/ExportPatch.png) + +You should now have a ".patch" file that you can attach to the issue it fixes in the [CodePlex Issue Tracker](http://orchard.codeplex.com/WorkItem/AdvancedList.aspx) by clicking "Choose File" under "Attach File" and then uploading. + +If you have the permissions to do so, you can change the status of the issue to "Fixed". + +Once the patch has been attached to the issue, please send us e-mail at ofeedbk@microsoft.com so that we can evaluate and integrate it. + +## What to Do Once Your Patch Has Been Processed + +Once the patch master has looked at your contribution and has either accepted and integrated it, or he has rejected it, there is no point in the fork still existing, so we recommend that you go ahead and delete it in order to keep the list of forks as clean as possible. diff --git a/Documentation/Contribution.markdown b/Documentation/Contribution.markdown new file mode 100644 index 00000000..e69de29b diff --git a/Documentation/Creating-1-n-and-n-n-relations.markdown b/Documentation/Creating-1-n-and-n-n-relations.markdown new file mode 100644 index 00000000..365a05b1 --- /dev/null +++ b/Documentation/Creating-1-n-and-n-n-relations.markdown @@ -0,0 +1,1169 @@ + +It is very common for contents to consist in part of lists or choices in lists. For example, an address can have a state or region property where the value is one in a predefined list of choices. That is a 1-n relationship. A n-n relationship could be for example a list of commercial rewards that a customer can benefit from. Orchard does of course provide support for those scenarios. This topic is going to walk you through the creation of such contents. + + +# Building a _1-N_ Relationship + +The model that we're going to build here consists of an Address part that can be attached for example to a Customer content type. The address part has a street address, a zip code, a city name and a state. The state is what we are going to model as a 1-n relationship to a table of states. + +> Note: this is clearly over-normalized, as a state in an address would usually be sufficiently well represented by a simple two-letter state code. The UI can then take care of representing the choice of that code as a constrained choice in a list of states. We are not claiming what we are building here is the correct way to represent a state in an address, but that the process exposed here is representative of what you'd follow to build a real-world 1-n association in Orchard. + +## Modeling the Address Part + +Here is the code for the `Address` part: + + + using Orchard.ContentManagement; + + namespace RelationSample.Models { + public class AddressPart : ContentPart { + public string Address { + get { return Record.Address; } + set { Record.Address = value; } + } + public string City { + get { return Record.City; } + set { Record.City = value; } + } + public StateRecord State { + get { return Record.StateRecord; } + set { Record.StateRecord = value; } + } + public string Zip { + get { return Record.Zip; } + set { Record.Zip = value; } + } + } + } + + +All properties are proxies to the record properties: + + + using Orchard.ContentManagement.Records; + + namespace RelationSample.Models { + public class AddressPartRecord : ContentPartRecord { + public virtual string Address { get; set; } + public virtual string City { get; set; } + public virtual StateRecord StateRecord { get; set; } + public virtual string Zip { get; set; } + } + } + + +The state record class itself has a two-letter code and a name: + + + namespace RelationSample.Models { + public class StateRecord { + public virtual int Id { get; set; } + public virtual string Code { get; set; } + public virtual string Name { get; set; } + } + } + + +Here is a representation of what we just showed in code: +![Modeling the address part](../Attachments/Creating-1-n-and-n-n-relations/AddressDiagram.PNG) + +## Creating the Database Tables and Part + +The database structure for the model we just built can be created from a migration: + + + public int Create() { + SchemaBuilder.CreateTable("AddressPartRecord", + table => table + .ContentPartRecord() + .Column("Address") + .Column("City") + .Column("StateRecord_Id") + .Column("Zip") + ); + + SchemaBuilder.CreateTable("StateRecord", + table => table + .Column("Id", column => column.PrimaryKey().Identity()) + .Column("Code", column => column.WithLength(2)) + .Column("Name") + ); + + ContentDefinitionManager.AlterPartDefinition("AddressPart", + builder => builder.Attachable()); + + return 1; + } + + +This migration creates an AddressPartRecord table that is a content part record (this gets us the default fields that a content part needs). It adds columns for address, city and zip that are going to be auto-mapped to our record's properties. + +The interesting column here is StateRecord_Id. As you can see, its type is the same as the type of the Id column of the StateRecord class, because the system will be able to recognize this as a foreign key and to map that integer value to a StateRecord property by just following the relation. It is important here that the name of the column that will represent the relation is the name of the column on the "1" end of the relation, followed by an underscore and the name of the column of the "n" end of the relation. + +There is nothing remarkable on the StateRecord table: it's just mapping Id to be the primary key and constraining the Code column to be 2 characters long. + +The last statement before the return in the migration is declaring the AddressPart and making it attachable. That will enable us to attach it to any content type. + +## Populating the State Table + +> Note: this section is included for completeness of the sample code but is far from essential to understanding how to implement relationships in Orchard. Please consider it as sample data generation. + +Because the list of states is going to be relatively stable, I did not make them content items (although that would be entirely possible with just a little more work). Instead, I'm populating the table with a list of states right in the migration code. The migration class has a reference to the state repository: + + + private readonly IRepository _stateRepository; + [...] + public RelationSampleDataMigration(IRepository stateRepository) { + _stateRepository = stateRepository; + } + + +It also has the list of states to add to the database: + + + private readonly IEnumerable _states = + new List { + new StateRecord {Code = "AL", Name = "Alabama"}, + new StateRecord {Code = "AK", Name = "Alaska"}, + [...] + new StateRecord {Code = "WS", Name = "Western Australia"}, + }; + + +The population of the table is done by the following code: + + + public int UpdateFrom1() { + if (_stateRepository == null) + throw new InvalidOperationException("Couldn't find state repository."); + foreach (var state in _states) { + _stateRepository.Create(state); + } + return 2; + } + + +## The Address Part Handler + +The handler for the address part is rather uninteresting and just wires up the repository: + + + using Orchard.Data; + using Orchard.ContentManagement.Handlers; + using RelationSample.Models; + + namespace RelationSample.Handlers { + public class AddressPartHandler : ContentHandler { + public AddressPartHandler(IRepository repository) { + Filters.Add(StorageFilter.For(repository)); + } + } + } + + +## The Address Part Driver + +The driver is more interesting as it prepares the shapes for rendering and handles posted back admin forms. + + + using JetBrains.Annotations; + using Orchard.ContentManagement; + using Orchard.ContentManagement.Drivers; + using RelationSample.Models; + using RelationSample.Services; + using RelationSample.ViewModels; + + namespace RelationSample.Drivers { + [UsedImplicitly] + public class AddressPartDriver : ContentPartDriver { + private readonly IAddressService _addressService; + + private const string TemplateName = "Parts/Address"; + + public AddressPartDriver(IAddressService addressService) { + _addressService = addressService; + } + + protected override string Prefix { + get { return "Address"; } + } + + protected override DriverResult Display( + AddressPart part, + string displayType, + dynamic shapeHelper) { + + return ContentShape("Parts_Address", + () => shapeHelper.Parts_Address( + ContentPart: part, + Address: part.Address, + City: part.City, + Zip: part.Zip, + StateCode: part.State.Code, + StateName: part.State.Name)); + } + + protected override DriverResult Editor( + AddressPart part, + dynamic shapeHelper) { + + return ContentShape("Parts_Address_Edit", + () => shapeHelper.EditorTemplate( + TemplateName: TemplateName, + Model: BuildEditorViewModel(part), + Prefix: Prefix)); + } + + protected override DriverResult Editor( + AddressPart part, + IUpdateModel updater, + dynamic shapeHelper) { + + var model = new EditAddressViewModel(); + updater.TryUpdateModel(model, Prefix, null, null); + + if (part.ContentItem.Id != 0) { + _addressService.UpdateAddressForContentItem( + part.ContentItem, model); + } + + return Editor(part, shapeHelper); + } + + private EditAddressViewModel BuildEditorViewModel(AddressPart part) { + var avm = new EditAddressViewModel { + Address = part.Address, + City = part.City, + Zip = part.Zip, + States = _addressService.GetStates() + }; + if (part.State != null) { + avm.StateCode = part.State.Code; + avm.StateName = part.State.Name; + } + return avm; + } + } + } + + +When displaying on the front-end, we prepare a Parts_Address shape that has a reference to the original part (although that is not necessary), all the part properties flattened out and the state is available as both a code and a name. + +When in the admin UI, we build shapes with a statically-typed view model because these are still easier to use when using form fields and MVC model binding. That view model, like the shape used on the front-end, has a flattened view of the data that we need to display, but it also has a full list of all the available states, that the view will use to render the state drop-down list: + + + using System.Collections.Generic; + using RelationSample.Models; + + namespace RelationSample.ViewModels { + public class EditAddressViewModel { + public string Address { get; set; } + public string City { get; set; } + public string StateCode { get; set; } + public string StateName { get; set; } + public string Zip { get; set; } + public IEnumerable States { get; set; } + } + } + + +The last thing to notice in the driver is that the Editor override that handles postbacks is just using `updater.TryUpdateModel()`, which is enough to incorporate the submitted form values onto the view model. This is followed by a call into the address service class which will update the actual content part data with the updated model. + +## The Address Service Class + +The address service class takes a dependency on the state repository in order to be able to query for the full list of states. Its other method, `UpdateAddressForContentItem`, copies an EditAddressViewModel onto the address content part of a content item. It does so by looking up a state record from the state repository using the state code from the model. + + + using System.Collections.Generic; + using System.Linq; + using Orchard; + using Orchard.ContentManagement; + using Orchard.Data; + using RelationSample.Models; + using RelationSample.ViewModels; + + namespace RelationSample.Services { + public interface IAddressService : IDependency { + void UpdateAddressForContentItem( + ContentItem item, EditAddressViewModel model); + IEnumerable GetStates(); + } + + public class AddressService : IAddressService { + private readonly IRepository _stateRepository; + + public AddressService(IRepository stateRepository) { + _stateRepository = stateRepository; + } + + public void UpdateAddressForContentItem( + ContentItem item, + EditAddressViewModel model) { + + var addressPart = item.As(); + addressPart.Address = model.Address; + addressPart.City = model.City; + addressPart.Zip = model.Zip; + addressPart.State = _stateRepository.Get( + s => s.Code == model.StateCode); + } + + public IEnumerable GetStates() { + return _stateRepository.Table.ToList(); + } + } + } + + +## Building the Views + +### The Front-End View + +The front-end view for the part is straightforward as it's just displaying the properties of the shape: + + +

+

@Model.Address
+ @Model.City, + @Model.StateCode + @Model.Zip +

+ + +We are using the vcard microformat in this template so the address can get picked-up by consumers that understand this format. + +### The Editor View + +The editor view is also relatively straightforward, with just the editor for the state being of a little more interest: + + + @model RelationSample.ViewModels.EditAddressViewModel +
+ Address + +
+ @Html.LabelFor(model => model.Address, T("Street Address")) +
+
+ @Html.TextAreaFor(model => model.Address) + @Html.ValidationMessageFor(model => model.Address) +
+ +
+ @Html.LabelFor(model => model.City, T("City")) +
+
+ @Html.TextBoxFor(model => model.City) + @Html.ValidationMessageFor(model => model.City) +
+ +
+ @Html.LabelFor(model => model.StateCode, T("State")) +
+
+ @Html.DropDownListFor(model => model.StateCode, + Model.States.Select(s => new SelectListItem { + Selected = s.Code == Model.StateCode, + Text = s.Code + " " + s.Name, + Value = s.Code + }), + "Choose a state...") + @Html.ValidationMessageFor(model => model.StateCode) +
+ +
+ @Html.LabelFor(model => model.Zip, T("Zip")) +
+
+ @Html.TextBoxFor(model => model.Zip) + @Html.ValidationMessageFor(model => model.Zip) +
+
+ + +The DropDownListFor method takes an expression for the property to represent, and a list of SelectListItems that we build on the fly from the complete list of states and what we know of the current state for that address (notice the expression for Selected). + +## The Placement File + +Finally, we need a placement file to determine the default position of our part within a larger content type: + + + + + + + + +## Using the Address Part + +We can now go into the "Features" admin page and enable the RelationSample feature under the Sample category. Once this is done we can go to "Content Types" and create a new "Customer" content type. Add the Common and Address parts, as well as a text field named "Name". + +![](../Attachments/Creating-1-n-and-n-n-relations/CustomerTypeAddress.PNG) + +We now have a new "Customer" menu entry under "New", enabling us to create a new customer: + +![](../Attachments/Creating-1-n-and-n-n-relations/CreateCustomer.PNG) + +The customer can be displayed on the front-end as well. + +![](../Attachments/Creating-1-n-and-n-n-relations/CustomerFrontEnd.PNG) + +# Building an _N-N_ Relationship + +Building a n-n relationship in Orchard relies on the same principles as what we did for the 1-n relationship. The main difference is that instead of having one foreign key on the part record, we have an intermediary object for the relationship that has two foreign keys to the records. This is of course close to the way this is done in relational databases. + +In this section, we are going to build a part that can record an arbitrary number of associations with reward programs for our customers. + +## Modeling the Rewards Part + +The rewards part and its association with reward programs are modeled as follows: + +![](../Attachments/Creating-1-n-and-n-n-relations/RewardDiagram.PNG) + +### The Rewards Part Record + +The part record has just one property, the collection of rewards: + + + using System.Collections.Generic; + using Orchard.ContentManagement.Records; + + namespace RelationSample.Models { + public class RewardsPartRecord : ContentPartRecord { + public RewardsPartRecord() { + Rewards = new List(); + } + public virtual IList Rewards { get; set; } + } + } + + +### The Rewards Part + +The rewards part itself proxies the Rewards property to the record: + + + using System.Collections.Generic; + using System.Linq; + using Orchard.ContentManagement; + + namespace RelationSample.Models { + public class RewardsPart : ContentPart { + public IEnumerable Rewards { + get { + return Record.Rewards.Select(r => r.RewardProgramRecord); + } + } + } + } + + +### The Reward Program Record + +Reward programs have a name and a discount rate: + + + namespace RelationSample.Models { + public class RewardProgramRecord { + public virtual int Id { get; set; } + public virtual string Name { get; set; } + public virtual double Discount { get; set; } + } + } + + +### The Association Record + +Finally, the association record has a reference to a reward part record and a reference to a reward program: + + + namespace RelationSample.Models { + public class ContentRewardProgramsRecord { + public virtual int Id { get; set; } + public virtual RewardsPartRecord RewardsPartRecord { get; set; } + public virtual RewardProgramRecord RewardProgramRecord { get; set; } + } + } + + +## Creating the Database Tables and Record + +Here is the migration: + + + public int UpdateFrom2() { + SchemaBuilder.CreateTable("RewardsPartRecord", + table => table + .ContentPartRecord() + ); + + SchemaBuilder.CreateTable("RewardProgramRecord", + table => table + .Column("Id", column => column.PrimaryKey().Identity()) + .Column("Name") + .Column("Discount") + ); + + SchemaBuilder.CreateTable("ContentRewardProgramsRecord", + table => table + .Column("Id", column => column.PrimaryKey().Identity()) + .Column("RewardsPartRecord_Id") + .Column("RewardProgramRecord_Id") + ); + + ContentDefinitionManager.AlterPartDefinition( + "RewardsPart", + builder => builder.Attachable()); + + return 3; + } + + +This code creates the three tables we need to persist the three records that we just modeled. It also declares the RewardsPart and makes it attachable. + +As with addresses and states, you can see the convention for relations in action here: the columns for the association record table are of type integer (the type of the id of each of the associated tables) and bears the name of the linked table, an underscore and the name of the key column of the associated table. + +## Populating the Reward Program Table + +Like we did with states, we pre-populate the reward program table from the migration class. In a real world scenario, the rewards could be content items and you could have a specific management screen for them. There would be nothing specific about that coming from the fact that these items happen to be at one end of a n-n relation. + + + private readonly IRepository _rewardProgramRepository; + [...] + private readonly IEnumerable _rewardPrograms = + new List { + new RewardProgramRecord {Name = "Senior", Discount = 0.05}, + new RewardProgramRecord {Name = "Family", Discount = 0.10}, + new RewardProgramRecord {Name = "Member", Discount = 0.15}, + }; + [...] + public int UpdateFrom3() { + if (_rewardProgramRepository == null) + throw new InvalidOperationException( + "Couldn't find reward program repository."); + foreach (var rewardProgram in _rewardPrograms) { + _rewardProgramRepository.Create(rewardProgram); + } + return 4; + } + + +## The Reward Handler + +There is nothing remarkable with the driver for this part, which is just wiring the repository: + + + using Orchard.Data; + using Orchard.ContentManagement.Handlers; + using RelationSample.Models; + + namespace RelationSample.Handlers { + public class RewardsPartHandler : ContentHandler { + public RewardsPartHandler(IRepository repository) { + Filters.Add(StorageFilter.For(repository)); + } + } + } + + +## The Reward Driver + +The driver is also surprisingly unsurprising given the requirement to persist the n-n relationship: + + + using System.Linq; + using JetBrains.Annotations; + using Orchard.ContentManagement; + using Orchard.ContentManagement.Drivers; + using RelationSample.Models; + using RelationSample.Services; + using RelationSample.ViewModels; + + namespace RelationSample.Drivers { + [UsedImplicitly] + public class RewardsPartDriver : ContentPartDriver { + private readonly IRewardService _rewardService; + + private const string TemplateName = "Parts/Rewards"; + + public RewardsPartDriver(IRewardService rewardService) { + _rewardService = rewardService; + } + + protected override string Prefix { + get { return "Rewards"; } + } + + protected override DriverResult Display( + RewardsPart part, + string displayType, + dynamic shapeHelper) { + + return ContentShape("Parts_Rewards", + () => shapeHelper.Parts_Rewards( + ContentPart: part, + Rewards: part.Rewards)); + } + + protected override DriverResult Editor( + RewardsPart part, + dynamic shapeHelper) { + + return ContentShape("Parts_Rewards_Edit", + () => shapeHelper.EditorTemplate( + TemplateName: TemplateName, + Model: BuildEditorViewModel(part), + Prefix: Prefix)); + } + + protected override DriverResult Editor( + RewardsPart part, + IUpdateModel updater, + dynamic shapeHelper) { + + var model = new EditRewardsViewModel(); + updater.TryUpdateModel(model, Prefix, null, null); + + if (part.ContentItem.Id != 0) { + _rewardService.UpdateRewardsForContentItem( + part.ContentItem, model.Rewards); + } + + return Editor(part, shapeHelper); + } + + private EditRewardsViewModel BuildEditorViewModel(RewardsPart part) { + var itemRewards = part.Rewards.ToLookup(r => r.Id); + return new EditRewardsViewModel { + Rewards = _rewardService.GetRewards().Select( + r => new RewardProgramEntry { + RewardProgram = r, + IsChecked = itemRewards.Contains(r.Id) + }).ToList() + }; + } + } + } + + +Like with the address part, we are fetching all the reward programs and putting them on the editor view model for the template to display as checkboxes. In BuildEditorViewModel, you can see that we build the current rewards as a lookup and then use that to determine the checked state of each reward program. + +Here is the editor view model: + + + using System.Collections.Generic; + using RelationSample.Models; + + namespace RelationSample.ViewModels { + public class EditRewardsViewModel { + public IList Rewards { get; set; } + } + + public class RewardProgramEntry { + public RewardProgramRecord RewardProgram { get; set; } + public bool IsChecked { get; set; } + } + } + + +> Note: we are making the assumption here that there are only a few reward programs. If you are modeling a relationship with a large number of records on both sides of the relationship, the basic principles and models exposed here still stand but you'll have to adapt and optimize the code. In particular, using checkboxes to select the associated records is the best UI solution for small numbers of records but it won't scale well to more than a few dozens of records. Instead, you'd probably need to use a search UI of sorts and an Add/Remove pattern. + +## The Rewards Service + +The rewards service is responsible for driving the relatively complex task of updating the database for the new values for the relation: + + + using System.Collections.Generic; + using System.Linq; + using Orchard; + using Orchard.ContentManagement; + using Orchard.Data; + using RelationSample.Models; + using RelationSample.ViewModels; + + namespace RelationSample.Services { + public interface IRewardService : IDependency { + void UpdateRewardsForContentItem( + ContentItem item, + IEnumerable rewards); + IEnumerable GetRewards(); + } + + public class RewardService : IRewardService { + private readonly IRepository + _rewardProgramRepository; + private readonly IRepository + _contentRewardRepository; + + public RewardService( + IRepository rewardProgramRepository, + IRepository contentRewardRepository) { + + _rewardProgramRepository = rewardProgramRepository; + _contentRewardRepository = contentRewardRepository; + } + + public void UpdateRewardsForContentItem( + ContentItem item, + IEnumerable rewards) { + + var record = item.As().Record; + var oldRewards = _contentRewardRepository.Fetch( + r => r.RewardsPartRecord == record); + var lookupNew = rewards + .Where(e => e.IsChecked) + .Select(e => e.RewardProgram) + .ToDictionary(r => r, r => false); + // Delete the rewards that are no longer there + // and mark the ones that should stay + foreach(var contentRewardProgramsRecord in oldRewards) { + if (lookupNew.ContainsKey( + contentRewardProgramsRecord.RewardProgramRecord)) { + + lookupNew[contentRewardProgramsRecord.RewardProgramRecord] + = true; + } + else { + _contentRewardRepository.Delete(contentRewardProgramsRecord); + } + } + // Add the new rewards + foreach(var reward in lookupNew.Where(kvp => !kvp.Value) + .Select(kvp => kvp.Key)) { + _contentRewardRepository.Create(new ContentRewardProgramsRecord { + RewardsPartRecord = record, + RewardProgramRecord = reward + }); + } + } + + public IEnumerable GetRewards() { + return _rewardProgramRepository.Table.ToList(); + } + } + } + + +> Note: again, this is designed for small numbers of reward programs. If you have larger models and have adopted an Add/Remove pattern talked about in the previous note, the code for the service actually becomes simpler as it executes lower-level operations that affect one program at a time rather than try to synchronize the whole collection at once. + +## Building the Views + +### The Front-End View + +The front-end view is just displaying the list of rewards as an unordered list: + + +

@T("Rewards"):

+
    + @foreach (var reward in Model.Rewards) { +
  • @string.Format("{0} ({1:P1})", reward.Name, -reward.Discount)
  • + } +
+ + +### The Editor View + +The editor view is a little more remarkable: + + + @model RelationSample.ViewModels.EditRewardsViewModel +
@T("Rewards") +
    + @{ + var rewardIndex = 0; + } + @foreach (var reward in Model.Rewards) { +
  • + + @{rewardIndex++;} +
  • + } +
+
+ + +Notice how the check-boxes use Html.FieldNameFor. This will ensure that they will have a name that the model binder will be able to understand and correctly bind when it is posted back. + +Also noticeable is the hidden input, which is a standard workaround for the peculiar way in which HTML check-boxes don't post anything when not checked. The model binder knows how to use the information for both the hidden input and the check-box to determine the Boolean values to set. + +Of course, any variation from that naming scheme would make the binding fail. + +## The Placement File + +For the parts to appear at all in the UI, we need to update our placement.info file: + + + + + + + + + + +## Using the Rewards Part + +If you haven't used the application's admin UI since you wrote the migration, it should now warn you that a feature needs to be upgraded. That is our sample feature, as the system noticed the latest executed migration does not match the highest available. Go to the features screen, locate the RelationSample and click "Update". + +In order to use the new part on our customer content items, we need to add it to the type. Go to the "Content Types" screen and click "Edit" next to "Customer". Click "Add" next to "Parts", check the Rewards part and save. + +![The customer type with the address and rewards parts.](../Attachments/Creating-1-n-and-n-n-relations/CustomerType.PNG) + +If you go back to an existing customer's edit screen or create a new one, you'll see a screen such as this: + +![](../Attachments/Creating-1-n-and-n-n-relations/EditCustomerRewards.PNG) + +On the front-end, the customer now looks like this: + +![](../Attachments/Creating-1-n-and-n-n-relations/CustomerWithRewards.PNG) + +# Building a Relation Between Content Items + +Our third example will establish a relation between content items, which is a step up from our previous examples which were establishing relations between records. Doing the same thing with items is not fundamentally very different, but there are a couple of caveats that justify a specific example. + +The example that we will build is a Sponsor part that records that a specific customer was sponsored by another. + +## Modeling the Sponsor Part + +The Sponsor part will consist of a single Sponsor property. This time, we will use a lazy field so that its content only gets fetched when it is needed. + + + using Orchard.ContentManagement; + using Orchard.Core.Common.Utilities; + + namespace RelationSample.Models { + public class SponsorPart : ContentPart { + private readonly LazyField _sponsor = new LazyField(); + + public LazyField SponsorField { get { return _sponsor; } } + + public IContent Sponsor { + get { return _sponsor.Value; } + set { _sponsor.Value = value; } + } + } + } + + +We will see how the lazy field gets set and populated when we look at the code for the handler. + +The corresponding record is extremely simple: + + + using Orchard.ContentManagement; + using Orchard.ContentManagement.Records; + + namespace RelationSample.Models { + public class SponsorPartRecord : ContentPartRecord { + public virtual ContentItemRecord Sponsor { get; set; } + } + } + + +## Building the Database Table and Part + +The migration for this part is as follows: + + + public int UpdateFrom4() { + + SchemaBuilder.CreateTable("SponsorPartRecord", + table => table + .ContentPartRecord() + .Column("Sponsor_Id") + ); + + ContentDefinitionManager.AlterPartDefinition( + "SponsorPart", builder => builder.Attachable()); + + return 5; + } + + +We are in known territory here: the table uses the convention that we have already applied twice in the previous examples, where the name of the column establishing the relation is the concatenation of the column names in both records. + +We also make the new SponsorPart attachable, as usual. + +## The Sponsor Handler + +The handler is going to be a little more elaborate than usual, because of the use of lazy fields: + + + using Orchard.ContentManagement; + using Orchard.Data; + using Orchard.ContentManagement.Handlers; + using RelationSample.Models; + + namespace RelationSample.Handlers { + public class SponsorPartHandler : ContentHandler { + private readonly IContentManager _contentManager; + + public SponsorPartHandler( + IRepository repository, + IContentManager contentManager) { + + Filters.Add(StorageFilter.For(repository)); + _contentManager = contentManager; + + OnInitializing(PropertySetHandlers); + OnLoaded(LazyLoadHandlers); + } + + void LazyLoadHandlers(LoadContentContext context, SponsorPart part) { + // add handlers that will load content just-in-time + part.SponsorField.Loader(() => + part.Record.Sponsor == null ? + null : _contentManager.Get(part.Record.Sponsor.Id)); + } + + static void PropertySetHandlers( + InitializingContentContext context, SponsorPart part) { + // add handlers that will update records when part properties are set + part.SponsorField.Setter(sponsor => { + part.Record.Sponsor = sponsor == null + ? null + : sponsor.ContentItem.Record; + return sponsor; + }); + + // Force call to setter if we had already set a value + if (part.SponsorField.Value != null) + part.SponsorField.Value = part.SponsorField.Value; + } + } + } + + +The storage filter is as usual setting up the repository of sponsor part records, but we also have OnInitializing and OnLoaded event handlers that will respectively set-up the setter for the lazy field and the loader of the value that will be executed the first time the field is accessed. + +At loading time, we look at the record, and if there is a sponsor we get the full content item from the content manager using the record's id. + +The lazy field setter just sets the underlying record's Sponsor property. + +## The Driver + +The driver is relying on the following view model: + + + using System.Collections.Generic; + using Orchard.ContentManagement; + using RelationSample.Models; + + namespace RelationSample.ViewModels { + public class EditSponsorViewModel { + public int CustomerId { get; set; } + public int SponsorId { get; set; } + public IEnumerable Customers { get; set; } + } + + public class CustomerViewModel { + public int Id { get; set;} + public string Name { get; set;} + } + } + + +Here is the code for the driver itself, which should by now seem very familiar: + + + using System.Linq; + using JetBrains.Annotations; + using Orchard.ContentManagement; + using Orchard.ContentManagement.Drivers; + using RelationSample.Models; + using RelationSample.Services; + using RelationSample.ViewModels; + + namespace RelationSample.Drivers { + [UsedImplicitly] + public class SponsorPartDriver : ContentPartDriver { + private readonly ICustomerService _customerService; + + private const string TemplateName = "Parts/Sponsor"; + + public SponsorPartDriver(ICustomerService customerService) { + _customerService = customerService; + } + + protected override string Prefix { + get { return "Sponsor"; } + } + + protected override DriverResult Display( + SponsorPart part, string displayType, dynamic shapeHelper) { + + return ContentShape("Parts_Sponsor", + () => shapeHelper.Parts_Sponsor( + ContentPart: part, + Sponsor: part.Sponsor, + SponsorName: _customerService.GetCustomerName(part.Sponsor) + )); + } + + protected override DriverResult Editor( + SponsorPart part, dynamic shapeHelper) { + + return ContentShape("Parts_Sponsor_Edit", + () => shapeHelper.EditorTemplate( + TemplateName: TemplateName, + Model: BuildEditorViewModel(part), + Prefix: Prefix)); + } + + protected override DriverResult Editor( + SponsorPart part, IUpdateModel updater, dynamic shapeHelper) { + + var model = new EditSponsorViewModel(); + updater.TryUpdateModel(model, Prefix, null, null); + + if (part.ContentItem.Id != 0) { + _customerService.UpdateSponsorForContentItem( + part.ContentItem, model); + } + + return Editor(part, shapeHelper); + } + + private EditSponsorViewModel BuildEditorViewModel(SponsorPart part) { + var itemSponsor = new EditSponsorViewModel { + CustomerId = part.ContentItem.Id, + Customers = _customerService.GetCustomers() + }; + if (part.Sponsor != null) { + itemSponsor.SponsorId = part.Sponsor.Id; + } + return itemSponsor; + } + } + } + + +## The Service Class + +The driver is also using the following helper service: + + + using System; + using System.Collections.Generic; + using System.Linq; + using Orchard; + using Orchard.ContentManagement; + using Orchard.Data; + using RelationSample.Models; + using RelationSample.ViewModels; + + namespace RelationSample.Services { + public interface ICustomerService : IDependency { + void UpdateSponsorForContentItem( + ContentItem item, EditSponsorViewModel model); + string GetCustomerName(IContent customer); + IEnumerable GetCustomers(); + } + + public class CustomerService : ICustomerService { + private readonly IContentManager _contentManager; + + public CustomerService(IContentManager contentManager) { + _contentManager = contentManager; + } + + public void UpdateSponsorForContentItem( + ContentItem item, EditSponsorViewModel model) { + + var sponsorPart = item.As(); + sponsorPart.Sponsor = _contentManager.Get(model.SponsorId); + } + + public string GetCustomerName(IContent customer) { + return customer.ContentItem.Parts + .SelectMany(p => p.Fields) + .Where(f => f.Name == "Name") + .First() + .Storage.Get(null); + } + + public IEnumerable GetCustomers() { + return _contentManager + .Query("Customer") + .List() + .Select(ci => new CustomerViewModel { + Id = ci.Id, + Name = GetCustomerName(ci) + }); + } + } + } + + +The only notable thing here is the way we are assuming the content type has a "Name" field that we'll use to build the list of customers that will be used to build the UI to select the sponsor. The GetCustomerName is implementing this assumption. Of course, you could also have a Customer part that has a Name property, or you could use Routable and its Title. + +## Building the Views + +The editor and front-end views should by now look fairly familiar: + + + @model RelationSample.ViewModels.EditSponsorViewModel +
+ Sponsor +
+ @Html.DropDownListFor(model => model.SponsorId, + Model.Customers + .Where(c => c.Id != Model.CustomerId) + .Select(c => new SelectListItem { + Selected = c.Id == Model.SponsorId, + Text = c.Name, + Value = c.Id.ToString() + }), + "Choose a customer...") + @Html.ValidationMessageFor(model => model.SponsorId) +
+
+ + +> **Note:** Again, we are assuming a small number of customers. In a real scenario where there are too many customers to be handled in a drop-down-list, it would be possible to adapt the code in this sample by changing among other things the kind of UI that is used to select the sponsor customer. + +The front-end view is as follows: + + + @if (Model.Sponsor != null) { + Customer sponsored by @Model.SponsorName. + } + + +Of course, the placement file also needs to be updated: + + + + + + + + + + + + +## Using the Sponsor Part + +We can now go back to the Customer type definition and add our new part. Now when we create a new customer, we can choose his sponsor: + +![](../Attachments/Creating-1-n-and-n-n-relations/EditCustomerWithSponsor.PNG) + +On the front-end, the sponsor now also appears: + +![](../Attachments/Creating-1-n-and-n-n-relations/CustomerWithSponsor.PNG) + +# Conclusion + +This topic should show the way for the creation of complex content parts involving arbitrary data relations. There is actually not much to it, as the system already knows how to persist and bind such complex objects. Rather, it's a matter of building the model according to the conventions in place. + +You may download the code for this topic from this link: [Orchard.Module.RelationSample.0.5.0.nupkg](http://orchardproject.net/docs/GetFile.aspx?File=Orchard.Module.RelationSample.0.5.0.nupkg&AsStreamAttachment=1&Provider=ScrewTurn.Wiki.FilesStorageProvider&IsPageAttachment=1&Page=Creating-1-n-and-n-n-relations&NoHit=1) diff --git a/Documentation/Creating-a-custom-field-type.markdown b/Documentation/Creating-a-custom-field-type.markdown new file mode 100644 index 00000000..c26a1034 --- /dev/null +++ b/Documentation/Creating-a-custom-field-type.markdown @@ -0,0 +1,501 @@ + +Fields can be used in Orchard to [build new content types](Creating-custom-content-types). Orchard currently comes with only one type of field, text fields, but it is possible to build your own field types that can then be used to build new content types. + +This topic will teach you how to add such a new field type. You can find the source code for this tutorial here: [http://orcharddatetimefield.codeplex.com/](http://orcharddatetimefield.codeplex.com/). + +We will assume Visual Studio and a full source code enlistment are being used in this topic. It is possible to build this module without it by simply manipulating the csproj file and adding the relevant files in there. Please consult [Creating a module with a simple text editor](Creating-a-module-with-a-simple-text-editor) for an example of module building without Visual Studio. + + +# Objectives + +Learn the steps to add a new field type to Orchard. The goal is to have a Date and Time editor so that any existing or new Content Type can let the user select a Date or a Time very easily. + +![The date time field in the event editor](../Attachments/Creating-a-custom-field-type/EventEditor.PNG) + +# Creating a Module + +We will create the new field type inside a new Orchard module so that it can be easily distributed. We will use Code Generation feature for that. + +> **Important:** Before you can generate the file structure for your module, you need to download, install, and enable the **Code Generation** feature for Orchard. For more information, see [Command-line Code Generation](Command-line-scaffolding). + +Once the **Code Generation** feature has been enabled, you can type the following `codegen` command on the Orchard command-line. + + + codegen module CustomFields /IncludeInSolution:true + + +This should create a new **CustomFields** folder under Modules, pre-populated with a few folders and files. For example, you may open the **module.txt** manifest file and modify it: + + + Name: CustomFields + AntiForgery: enabled + Author: Me + Website: http://orcharddatetimefield.codeplex.com + Version: 0.6.1 + OrchardVersion: 0.8.0 + Description: A bunch of custom fields for use in your custom content types. + Features: + CustomFields: + Description: Custom fields for Orchard. + Category: Fields + DateTimeField: + Description: A date and time field with a friendly UI. + Category: Fields + Dependencies: CustomFields, Orchard.jQuery, Common, Settings + + +We are defining two features here because this module will eventually contain more fields and we want to distinguish between the default feature of the module (which has the same name as the module itself and has to exist in any module) and the date field feature. This also demonstrates categories and dependencies. + +# Modeling the Field + +Let's now create a **Fields** folder inside of our **CustomFields** folder and create the following **DateTimeField.cs** file in there: + + + using System; + using System.Globalization; + using Orchard.ContentManagement; + using Orchard.ContentManagement.FieldStorage; + using Orchard.Environment.Extensions; + + namespace CustomFields.DateTimeField.Fields { + [OrchardFeature("DateTimeField")] + public class DateTimeField : ContentField { + + public DateTime? DateTime { + get { + var value = Storage.Get(); + DateTime parsedDateTime; + + if (System.DateTime.TryParse(value, CultureInfo.InvariantCulture, + DateTimeStyles.AdjustToUniversal, out parsedDateTime)) { + + return parsedDateTime; + } + + return null; + } + + set { + Storage.Set(value == null ? + String.Empty : + value.Value.ToString(CultureInfo.InvariantCulture)); + } + } + } + } + + +The field is defined as a class that derives from `ContentField`, which gives us a few services for free, such as the storage of the value of the field. The fields will be stored as strings. The conversion of dates to and from strings could be handled automatically, but we are doing it explicitly here to give a good idea of how you would do things for more complex field types. + +# Creating a View Model + +It is good practice (although not mandatory) to create one or several view models that will be used as the model in the admin template that we will use to render instances of our field. Let's create the following **DateTimeFieldViewModel.cs** file in a new **ViewModels** folder: + + + namespace CustomFields.DateTimeField.ViewModels { + + public class DateTimeFieldViewModel { + + public string Name { get; set; } + + public string Date { get; set; } + public string Time { get; set; } + + public bool ShowDate { get; set; } + public bool ShowTime { get; set; } + } + } + + +This not only exposes the date and time as separate properties, it also has some parameters that can be passed into the view to customize the rendering. + +# Creating Settings for the Field + +This flexibility in rendering that we just introduced in the view model can be exposed as settings for the field. This way, administrators can configure fields on the content types they create in order to adapt them to their exact needs. + +Create a **Settings** folder and add the following **DateTimeFieldSettings.cs** file to it: + + + namespace CustomFields.DateTimeField.Settings { + + public enum DateTimeFieldDisplays { + DateAndTime, + DateOnly, + TimeOnly + } + + public class DateTimeFieldSettings { + public DateTimeFieldDisplays Display { get; set; } + } + } + + +We have defined here an enumeration describing the possible values of our display setting, which is the only setting for the field. The settings class itself is just an ordinary class with one property typed with that enumeration. + +# Writing the Driver + +Exactly like a part, a field has a driver that will be responsible for handling display and editing actions on the field when it's been added to a content type. + +Create a **Drivers** folder and add the following **DateTimeFieldDriver.cs**: + + + using System; + using JetBrains.Annotations; + using Orchard; + using Orchard.ContentManagement; + using Orchard.ContentManagement.Drivers; + using Contrib.DateTimeField.Settings; + using Contrib.DateTimeField.ViewModels; + using Orchard.ContentManagement.Handlers; + using Orchard.Localization; + + namespace CustomFields.DateTimeField.Drivers { + [UsedImplicitly] + public class DateTimeFieldDriver : ContentFieldDriver { + public IOrchardServices Services { get; set; } + + // EditorTemplates/Fields/Custom.DateTime.cshtml + private const string TemplateName = "Fields/Custom.DateTime"; + + public DateTimeFieldDriver(IOrchardServices services) { + Services = services; + T = NullLocalizer.Instance; + } + + public Localizer T { get; set; } + + private static string GetPrefix(ContentField field, ContentPart part) { + // handles spaces in field names + return (part.PartDefinition.Name + "." + field.Name) + .Replace(" ", "_"); + } + + protected override DriverResult Display( + ContentPart part, Fields.DateTimeField field, + string displayType, dynamic shapeHelper) { + + var settings = field.PartFieldDefinition.Settings + .GetModel(); + var value = field.DateTime; + + return ContentShape("Fields_Custom_DateTime", // key in Shape Table + field.Name, // used to differentiate shapes in placement.info overrides, e.g. Fields_Common_Text-DIFFERENTIATOR + // this is the actual Shape which will be resolved + // (Fields/Custom.DateTime.cshtml) + s => + s.Name(field.Name) + .Date(value.HasValue ? + value.Value.ToLocalTime().ToShortDateString() : + String.Empty) + .Time(value.HasValue ? + value.Value.ToLocalTime().ToShortTimeString() : + String.Empty) + .ShowDate( + settings.Display == DateTimeFieldDisplays.DateAndTime || + settings.Display == DateTimeFieldDisplays.DateOnly) + .ShowTime( + settings.Display == DateTimeFieldDisplays.DateAndTime || + settings.Display == DateTimeFieldDisplays.TimeOnly) + ); + } + + protected override DriverResult Editor(ContentPart part, + Fields.DateTimeField field, + dynamic shapeHelper) { + + var settings = field.PartFieldDefinition.Settings + .GetModel(); + var value = field.DateTime; + + if (value.HasValue) { + value = value.Value.ToLocalTime(); + } + + var viewModel = new DateTimeFieldViewModel { + Name = field.Name, + Date = value.HasValue ? + value.Value.ToLocalTime().ToShortDateString() : "", + Time = value.HasValue ? + value.Value.ToLocalTime().ToShortTimeString() : "", + ShowDate = + settings.Display == DateTimeFieldDisplays.DateAndTime || + settings.Display == DateTimeFieldDisplays.DateOnly, + ShowTime = + settings.Display == DateTimeFieldDisplays.DateAndTime || + settings.Display == DateTimeFieldDisplays.TimeOnly + + }; + + return ContentShape("Fields_Custom_DateTime_Edit", + () => shapeHelper.EditorTemplate( + TemplateName: TemplateName, + Model: viewModel, + Prefix: GetPrefix(field, part))); + } + + protected override DriverResult Editor(ContentPart part, + Fields.DateTimeField field, + IUpdateModel updater, + dynamic shapeHelper) { + + var viewModel = new DateTimeFieldViewModel(); + + if (updater.TryUpdateModel(viewModel, + GetPrefix(field, part), null, null)) { + DateTime value; + + var settings = field.PartFieldDefinition.Settings + .GetModel(); + if (settings.Display == DateTimeFieldDisplays.DateOnly) { + viewModel.Time = DateTime.Now.ToShortTimeString(); + } + + if (settings.Display == DateTimeFieldDisplays.TimeOnly) { + viewModel.Date = DateTime.Now.ToShortDateString(); + } + + if (DateTime.TryParse( + viewModel.Date + " " + viewModel.Time, out value)) { + field.DateTime = value.ToUniversalTime(); + } + else { + updater.AddModelError(GetPrefix(field, part), + T("{0} is an invalid date and time", + field.Name)); + field.DateTime = null; + } + } + + return Editor(part, field, shapeHelper); + } + + protected override void Importing(ContentPart part, Fields.DateTimeField field, + ImportContentContext context) { + + var importedText = context.Attribute(GetPrefix(field, part), "DateTime"); + if (importedText != null) { + field.Storage.Set(null, importedText); + } + } + + protected override void Exporting(ContentPart part, Fields.DateTimeField field, + ExportContentContext context) { + context.Element(GetPrefix(field, part)) + .SetAttributeValue("DateTime", field.Storage.Get(null)); + } + } + } + + +Let's enumerate a few things we're doing in this code in order to explain how it works. + +The driver derives from `ContentFieldDriver` in order to be recognized by Orchard and to give strongly-typed access to the field value from the driver's code. + +We start by injecting the localizer dependency (the `T` property) so that we can create localizable strings throughout the code. + +The static `GetPrefix` method is a conventionally defined method that is used to create unique column names in the database for instances of the field type. + +We then have two actions, `Display` and `Editor`, which start by fetching the `settings` and `value` for the field and build shapes out of them. + +> Note: The `UsedImplicitly` attribute is only here to suppress a warning from Resharper. It could be removed without much harm. + +The `shapeHelper` object provides some helper methods to create shapes, two of which can be seen in action here. + +The second `Editor` method is the one that is called when the admin form is submitted. Its job is to map the submitted data back into the field and then to call the first `Editor` method to render the editor on the screen again. + +# Writing the Templates + +We need to write the views that will determine how our field is represented in admin and front-end UI. + +Create a **Fields** and an **EditorTemplates** directory under **Views**. Then create another **Fields** directory under EditorTemplates. In **Views/Fields**, create the following **Custom.DateTime.cshtml**: + + +

@Model.Name: + @if(Model.ShowDate) { @Model.Date } + @if(Model.ShowTime) { @Model.Time } +

+ + +This code renders the name of the field, a colon and then the date and time according to the field's configuration. + +Now create a file of the same name under **Views/EditorTemplates/Fields** with the following contents: + + + @model CustomFields.DateTimeField.ViewModels.DateTimeFieldViewModel + + @{ + Style.Include("datetime.css"); + Style.Require("jQueryUI_DatePicker"); + Style.Require("jQueryUtils_TimePicker"); + Style.Require("jQueryUI_Orchard"); + + Script.Require("jQuery"); + Script.Require("jQueryUtils"); + Script.Require("jQueryUI_Core"); + Script.Require("jQueryUI_Widget"); + Script.Require("jQueryUI_DatePicker"); + Script.Require("jQueryUtils_TimePicker"); + } + +
+ + + @if ( Model.ShowDate ) { + + @Html.EditorFor(m => m.Date) + } + + @if ( Model.ShowTime ) { + + @Html.EditorFor(m => m.Time) + } + @if(Model.ShowDate) { @Html.ValidationMessageFor(m=>m.Date) } + @if(Model.ShowTime) { @Html.ValidationMessageFor(m=>m.Time) } +
+ + @using(Script.Foot()) { + + } + + +This template is registering a few styles and scripts (note that if other parts register the same files, they will still be rendered only once). Then, it defines the editor as a date picker and a time picker according to the field's configuration. The fields are regular text boxes that are unobtrusively enriched by date and time pickers using jQuery UI plug-ins. + +To specify the order and location where these templates will be rendered within the composed page, we need to add a placement.info file into the root of the module's directory: + + + + + + + + +# Managing the Field Settings + +We are not quite done yet. We still need to take care of managing and persisting the settings for the field. + +Add the following **DateTimeFieldEditorEvents.cs** file to the **Settings** folder: + + + using System.Collections.Generic; + using Orchard.ContentManagement; + using Orchard.ContentManagement.MetaData; + using Orchard.ContentManagement.MetaData.Builders; + using Orchard.ContentManagement.MetaData.Models; + using Orchard.ContentManagement.ViewModels; + + namespace CustomFields.DateTimeField.Settings { + public class DateTimeFieldEditorEvents : ContentDefinitionEditorEventsBase { + + public override IEnumerable + PartFieldEditor(ContentPartFieldDefinition definition) { + if (definition.FieldDefinition.Name == "DateTimeField") { + var model = definition.Settings.GetModel(); + yield return DefinitionTemplate(model); + } + } + + public override IEnumerable PartFieldEditorUpdate( + ContentPartFieldDefinitionBuilder builder, IUpdateModel updateModel) { + var model = new DateTimeFieldSettings(); + if (updateModel.TryUpdateModel( + model, "DateTimeFieldSettings", null, null)) { + builder.WithSetting("DateTimeFieldSettings.Display", + model.Display.ToString()); + } + + yield return DefinitionTemplate(model); + } + } + } + + +This is the equivalent of a driver, but for field settings. The first method gets the settings and determines the template to render, and the second updates the model with the values from the submitted form and then calls the first. + +The editor template for the field is defined by the following **DateTimeFieldSettings.cshtml** that you should create in a new **DefinitionTemplates** folder under **Views**: + + + @model CustomFields.DateTimeField.Settings.DateTimeFieldSettings + @using CustomFields.DateTimeField.Settings; + +
+ + + + @Html.ValidationMessageFor(m => m.Display) + +
+ + +This template creates a label for the setting and then a drop-down that enables the site administrator to pick one of the options for the setting. + +# Updating the Project File + +If you are using Visual Studio, you should skip this section as your project file has already been updated, provided you saved all (CTRL+SHIFT+S). Otherwise, in order for the Orchard dynamic compilation engine to be able to pick up our new module's cs files, we need to add them to the **CustomFields.csproj** file. Find the `` line in **CustomFields.csproj** and add the following right after it: + + + + + + + + + +# Adding the Style Sheet + +Create a **Styles** directory and create the following **datetime.css**: + + + html.dyn label.forpicker { + display:none; + } + + html.dyn input.hinted { + color:#ccc; + font-style:italic; + } + .date input{ + width:10em; + } + .time input { + width:6em; + } + + +# Using the Field + +In order to be able to use the new field, you must first make sure that the **Orchard.ContentTypes** feature is enabled. Also enable our new **DateTimeField** feature under **Fields**. Once it is, you can click on **Manage content types** in the admin menu. Click **Create new type** and give it the name "Event". Click **Add** next to fields and type in "When" as the name of the field. Select our new **DateTime** field type as the type of the field. + +Now in the type editor, you should see our new **When** field, and you should be able to deploy its settings section by clicking the "**>**" on its left: + +![Configuring the field](../Attachments/Creating-a-custom-field-type/ConfiguringTheField.PNG) +We chose to keep both date and time displayed. The settings for the field are also the opportunity to determine where the field will appear on the front end if you want to override the defaults. Let's skip that for now. Add the **Route** part so that our events can have a title, then hit Save. + +We can now add a new event by clicking **Create Event** in the admin menu. The editor that gets created for us has a when field with nice date and time pickers: + +![The date time field in the event editor](../Attachments/Creating-a-custom-field-type/EventEditor.PNG) +Create an event and save it. You can now view it on the site: + +![The event as displayed on the front end](../Attachments/Creating-a-custom-field-type/Dinner.PNG) + +# Getting the Code + +Download the code here: [CustomFields.zip](../Attachments/Creating-a-custom-field-type/CustomFields.zip). The code is also hosted on [http://orcharddatetimefield.codeplex.com/](http://orcharddatetimefield.codeplex.com/). diff --git a/Documentation/Creating-a-module-with-a-simple-text-editor.markdown b/Documentation/Creating-a-module-with-a-simple-text-editor.markdown new file mode 100644 index 00000000..a8094ee1 --- /dev/null +++ b/Documentation/Creating-a-module-with-a-simple-text-editor.markdown @@ -0,0 +1,355 @@ + +In this tutorial, you will learn how to develop a simple commerce module using only a text editor. + +If you do not have the [Web Platform Installer](http://www.microsoft.com/web/downloads/platform.aspx) on your computer, download it before beginning this tutorial. + + +# Setting Up the Orchard Site + +First, you will set up a new Orchard website. If you already have a site set up, you can skip this section and jump directly to [the code generation section](#codegen). To start the setup, open **IIS Manager**, right-click **Sites**, and click **Add Web Site**. + +![Figure 1. Creating the Orchard site](../Attachments/Creating-a-module-with-a-simple-text-editor/01_NewWebSite.PNG) + +In the **Add Web Site** dialog box, fill in the fields to point the new website to a folder, such as _\inetpub\wwwroot\Orchard_. Name the new site **Orchard** and give it an unused port, such as 90. Use the default application pool (.NET 4.0 integrated pipeline). Click **OK**. + +![Figure 2. Configuring the site](../Attachments/Creating-a-module-with-a-simple-text-editor/s_02_NewSiteSettings.png) + +From the Windows **Start** menu, launch **Web Platform Installer**, select **Orchard CMS**, click **Add**, and then click **Install**. + +![](../Upload/screenshots/orchard_install.png) + +After you accept the license terms, Orchard is installed. + +Open a command window and change the current directory to point to the root of the site. Then run `bin\orchard.exe`. + +![Figure 6. The Orchard command line](../Attachments/Creating-a-module-with-a-simple-text-editor/s_07_OrchardCLI.png) + +Type `help commands` to get the list of available commands. For now, only the `help` and `setup` commands are available. However, as Orchard is developed and modules are activated, new commands will become available. (The Orchard command-line executable actually discovers the commands from the modules inside of the application.) + +To set up the site, enter the following command: + + + setup /SiteName:Orchard /AdminUsername:admin /AdminPassword:123456 /DatabaseProvider:SqlCe + + +This is equivalent to setting up the site from the web interface. + +Leave the command window open. (In fact, don't close it until you have finished this tutorial.) + + +# Generating Code for the Module + +Now you are ready to start developing the commerce module. Orchard provides a code generation feature that sets up the structure of an empty module to help you get started. By default, code generation is disabled. So you must first enable the feature. + +To enable code generation, enter the following command in the command window: + + + feature enable Orchard.CodeGeneration + + +You will use a code-generation command to create a commerce module. Enter the following command: + + + codegen module SimpleCommerce + + +Open a Windows Explorer window and browse to the newly created _\inetpub\wwwroot\Orchard\Modules\SimpleCommerce_ folder. Open the _module.txt_ file using a text editor. + +Change the description to "A simple commerce module". Change the description of the feature to be "A simple product part". Save the file and close it. The following example shows the complete _module.txt_ file after the changes. + + + Name: SimpleCommerce + AntiForgery: enabled + Author: The Orchard Team + Website: http://orchardproject.net + Version: 0.5.0 + OrchardVersion: 0.5.0 + Description: A simple commerce module + Features: + SimpleCommerce: + Name: Simple Commerce + Description: A simple product part. + Category: Commerce + + +# Creating the Model for the Part + +Next, you will create a data model that is a repesentation of what will be stored in the database. + +In _Modules/SimpleCommerce/Models_, create a _Product.cs_ file and add the following content: + + + using System.ComponentModel.DataAnnotations; + using Orchard.ContentManagement; + using Orchard.ContentManagement.Records; + + namespace SimpleCommerce.Models { + public class ProductPartRecord : ContentPartRecord { + public virtual string Sku { get; set; } + public virtual float Price { get; set; } + } + + public class ProductPart : ContentPart { + [Required] + public string Sku { + get { return Record.Sku; } + set { Record.Sku = value; } + } + + [Required] + public float Price { + get { return Record.Price; } + set { Record.Price = value; } + } + } + } + + +This code has two properties, `Sku` and `Price`, that are virtual in order to enable the creation of a dynamic proxy that will handle persistence transparently. + +The code also defines a content part that derives from `ContentPart<ProductPartRecord>` and that exposes the SKU and price from the record as public properties. The properties have attributes that will surface in the UI as validation tests. + +In order for the application to pick up the new file, you need to add it to the module's project file. Open the _SimpleCommerce.csproj_ file and look for "assemblyinfo.cs". After that line, add the following: + + + + + +Save the file, but leave it open, because you will make additional changes to it throughout the tutorial. + +Navigate to the site in your browser to make sure the application's dynamic compilation feature picks up the new part and record. You will know that everything is working if you go to the **Features** administration screen and see the new **SimpleCommerce** feature. + +In the command window, enable the new feature using the following command: + + + feature enable SimpleCommerce + + +# Creating the Initial Data Migration File + +Data migration is a pattern that enables an application or component to handle new versions gracefully, without any data loss. The main idea is that the system keeps track of the current version installed and each data migration describes the changes to go from one version to the next. If the system detects that there is a new version installed and the current data is from a previous version, the administrator of the site is prompted to upgrade. The system then runs all necessary migration methods until the data version and the code version are in sync. + +Start by creating the initial migration for the new module, which will just create the data tables that are needed. In the command window, enter the following command: + + codegen datamigration SimpleCommerce + + +This creates the following _Migrations.cs_ file: + + using System; + using System.Collections.Generic; + using System.Data; + using Orchard.ContentManagement.Drivers; + using Orchard.ContentManagement.MetaData; + using Orchard.ContentManagement.MetaData.Builders; + using Orchard.Core.Contents.Extensions; + using Orchard.Data.Migration; + + namespace SimpleCommerce.DataMigrations { + public class Migrations : DataMigrationImpl { + + public int Create() { + // Creating table ProductPartRecord + SchemaBuilder.CreateTable("ProductPartRecord", table => table + .ContentPartRecord() + .Column("Sku", DbType.String) + .Column("Price", DbType.Single) + ); + + + + return 1; + } + } + } + + +The method name `Create` is the convention for the initial data migration. It calls the `SchemaBuilder.CreateTable` method that creates a _ProductPartRecord_ table that has _Sku_ and _Price_ columns in addition to the columns from the basic _ContentPartRecord_ table. + +Notice that the method returns 1, which is the version number for the migration. + +Add another migration step to this in order to illustrate how you can later alter the existing schema and type metadata as the module evolves. In this case, you will take this opportunity to add a feature that will enable the part to be attached to any content type. Add the following method to the data migration class: + + + public int UpdateFrom1() { + ContentDefinitionManager.AlterPartDefinition("ProductPart", + builder => builder.Attachable()); + return 2; + } + + +This new migration is named `UpdateFrom1`, which is the convention for upgrading from version 1. Your next migration should be called `UpdateFrom2` and return 3, and so on. + +Make sure the following line is present in the _.csproj_ file. (It should already have been added by the code generation command.) + + + + +Navigate to the **Features** screen in the dashboard. You see a warning that indicates that one of the features needs to be updated, and the **Simple Commerce** module is displayed in red. Click **Update** to ensure that the migrations are run and that the module is up to date. + +# Adding a Handler + +A handler in Orchard is analogous to a filter in ASP.NET MVC. It's a piece of code that is meant to run when specific events happen in the application, but that are not specific to a given content type. For example, you could build an analytics module that listens to the `Loaded` event in order to log usage statistics. To see what event handlers you can override in your own handlers, examine the source code for `ContentHandlerBase`. + +The handler you need in the module is not going to be very complex, but it will implement some plumbing that is necessary to set up the persistence of the part. We hope that this kind of plumbing will disappear in a future version of Orchard, possibly in favor of a more declarative approach such as using attributes. + +Create a _Handlers_ folder and add a _ProductHandler.cs_ file to it that contains the following code: + + + using Orchard.ContentManagement.Handlers; + using SimpleCommerce.Models; + using Orchard.Data; + + namespace SimpleCommerce.Handlers { + public class ProductHandler : ContentHandler { + public ProductHandler(IRepository repository) { + Filters.Add(StorageFilter.For(repository)); + } + } + } + + +Add the file to the _.csproj_ file so that dynamic compilation can pick it up, using the following line: + + + + +# Adding a Driver + +A driver in Orchard is analogous to a controller in ASP.NET MVC, but is well adapted to the composition aspect that is necessary in web content management systems. It is specialized for a specific content part and can specify custom behavior for well-known actions such as displaying an item in the front end or editing it in the administration UI. + +A driver typically has overrides for the display and editor actions. For the product part, create a new _Drivers_ folder and in that folder create a _ProductDriver.cs_ file that contains the following code: + + + using SimpleCommerce.Models; + using Orchard.ContentManagement.Drivers; + using Orchard.ContentManagement; + + namespace SimpleCommerce.Drivers { + public class ProductDriver : ContentPartDriver { + protected override DriverResult Display( + ProductPart part, string displayType, dynamic shapeHelper) + { + return ContentShape("Parts_Product", + () => shapeHelper.Parts_Product( + Sku: part.Sku, + Price: part.Price)); + } + + //GET + protected override DriverResult Editor(ProductPart part, dynamic shapeHelper) + { + return ContentShape("Parts_Product_Edit", + () => shapeHelper.EditorTemplate( + TemplateName: "Parts/Product", + Model: part, + Prefix: Prefix)); + } + + //POST + protected override DriverResult Editor( + ProductPart part, IUpdateModel updater, dynamic shapeHelper) + { + updater.TryUpdateModel(part, Prefix, null, null); + return Editor(part, shapeHelper); + } + } + } + + +The code in the `Display` method creates a shape to use when rendering the item in the front end. That shape has `Sku` and `Price` properties copied from the part. + +Update the _.csproj_ file to include the following line: + + + + +The `Editor` method also creates a shape named `EditorTemplate`. The shape has a `TemplateName` property that instructs Orchard where to look for the rendering template. The code also specifies that the model for that template will be the part, not the shape (which would be the default). + +The placement of those parts within the larger front end or dashboard must be specified using a _placement.info_ file that is located at the root of the module. That file, like a view, can be overridden from a theme. Create the _placement.info_ file with the following contents: + + + + + + + + +Add the _placement.info_ file to the _.csproj_ file using the following line: + + + + + +# Building the Templates + +The last thing to do in order for the new content part to work is to write the two templates (front end and admin) that are configured in the driver. + +Create the front-end template first. Create a _Parts_ folder under _Views_ and add a _Product.cshtml_ file that contains the following code: + + +
+ @T("Price"): $@Model.Price
+ @Model.Sku
+ + +This is very plain rendering of the shape. Notice the use of the `T` method call to wrap the "Price" string literal. This enables [localization](Creating-global-ready-applications) of that text. + +The administration view is a little heavier on HTML helper calls. Create an _EditorTemplates_ folder under _Views_ and a _Parts_ folder under that. Add a _Product.cshtml_ to the _Parts_ folder that contains the following code: + + + @model SimpleCommerce.Models.ProductPart +
+
+ @Html.TextBoxFor(m => m.Sku, new { @class = "text" })
+
+ @Html.TextBoxFor(m => m.Price, new { @class = "text" }) +
+ + +Add those two templates to the _.csproj_ file using the following lines: + + + + + + +# Putting it All Together into a Content Type + +The content part that you've put together could already be composed from the administration UI into a content type (see [Creating Custom Content Types](Creating-custom-content-types)), but per the goal of this topic, you will continue by writing code using a text editor. + +You will now build a new `Product` content type that will include the `Product` part and a number of parts that you can get from Orchard. So far, you have been focused on your specific domain. This will now change and you will start integrating into Orchard. + +To build the content type from a new migration, open the _Migrations.cs_ file and add the following method to the class: + + + public int UpdateFrom2() { + ContentDefinitionManager.AlterTypeDefinition("Product", cfg => cfg + .WithPart("CommonPart") + .WithPart("RoutePart") + .WithPart("BodyPart") + .WithPart("ProductPart") + .WithPart("CommentsPart") + .WithPart("TagsPart") + .WithPart("LocalizationPart") + .Creatable() + .Indexed()); + return 3; + } + + +Also add `using Orchard.Indexing;` to the top of the file. + +What you are doing is creating (or updating) the `Product` content type and adding to it the ability to have its own URL and title (`RoutePart`), to have a rich text description (`BodyPart`), to be a product, to be commented on (`CommentsPart`), to be tagged (`TagsPart`) and to be localizable (`LocalizationPart`). It can also be created, which will add a **Create Product** menu entry, and it will also enter the search index (`Indexed`). + +To enable your new module, open the Orchard dashboard and click **Modules**. Select the **Features** tab, find the **SimpleCommerce** module, and click **Enable**. + +![](../Upload/screenshots/simpleCommerce_enable.png) + +To add a new **Product** content type, click **Content** on the dashboard, select the **Content Types** tab, find **Product**, and click **Create New Product**. + +![](../Upload/screenshots_675/simpleCommerce_product_675.png) + +You now have a product editor that features your `Sku` and `Price` fields. + +The code for this module can be downloaded from the following page: [Orchard.Module.SimpleCommerce.0.5.0.nupkg](../Attachments/Creating-a-module-with-a-simple-text-editor/Orchard.Module.SimpleCommerce.0.5.0.nupkg) diff --git a/Documentation/Creating-custom-content-types.markdown b/Documentation/Creating-custom-content-types.markdown new file mode 100644 index 00000000..51726226 --- /dev/null +++ b/Documentation/Creating-custom-content-types.markdown @@ -0,0 +1,100 @@ + +Although Orchard includes the Page and Blog Post content types by default, it is very easy to create a custom content type (or even extend the definition of an existing content type) using the admin panel. By default, the **Content Types** feature is enabled. This feature must be enabled to create a custom content types. If needed, you can manually enable the feature in the **Manage Features** page. + +![](../Upload/screenshots_675/ContentTypes_enable.png) + +To create a content type, select the **Content Types** link in the admin panel. + +![](../Upload/screenshots/ContentTypes_startcustom.png) + +On this screen, you can see the available content types in the system. Notice that it is possible to create and list content items of some of these types (such as "Page"), whereas others only allow you to edit the definition of the type here (such as Comments and Widgets, since these have a dedicated/custom admin experience for creating and listing these items instead). + +![](../Upload/screenshots_675/ContentTypes_manage2.png) + +If you click "List Items", to list the items of the "Page" type, you can see the available content items of this type ("Page") in the site, similar to the "Manage Content" screen in the admin menu). + +![](../Upload/screenshots_675/manage_page_content2.png) + +You can also edit the definition of the Page type by clicking "Edit" for this type. + +![](../Upload/screenshots_675/edit_content_type_page.png) + +A content type in Orchard is made up of fields and parts. An good overview of these concepts is described in [Basic Orchard Concepts](Basic-Orchard-Concepts). A field is something specific to the type; for example, a Product type might have SKU and Price fields. A part, however, is a reusable component that can be attached to one or more types. For example, the Route part gives a type the ability to be addressed on the front-end via a route/url. In some ways, you can think of a type as _having_ fields, and _being_ made up of one or more parts. This is actually reflected in the underlying code in Orchard as well. To treat a blog post as a RoutePart and access it's RoutePart.Slug property, you would write something like this: post.As<RoutePart>.Slug. Fortunately you don't have to write code to have fun with types and parts. We are going to look at this in more detail by way of example in the next section. + +### Defining a New Content Type + +Let's define a custom content type. Suppose you wanted to define an "Event" type, for listing events with location and date fields. To do this in the **Manage Content Types** screen, click on **Create new type**. + +![](../Upload/screenshots/ContentTypes_createnew.png) + +Type the name "Event" for the content type. The **Content Type Id** field is automatically populated with "Event" which you can keep. + +![](../Upload/screenshots/ContentTypes_createname.png) + +Click **Add** to add a field. + +![](../Upload/screenshots_675/ContentTypes_addfield.png) + +Currently Orchard only includes a single field type (TextField), but [more can be created](Creating-a-custom-field-type) as extensions to Orchard (for example, CheckBoxField, EmailField, TextAreaField, DateTimeField, etc), and a number of additional fields are available under **Gallery** > **Modules** as optional downloads. Type "Location" for the name of the field, and click **Save**. + +![](../Upload/screenshots/ContentTypes_addfieldname.png) + +The field is now listed in the Event type screen. + +![](../Upload/screenshots/add_field3.png) + +Go ahead and repeat the previous two steps to add a second field named "Date". + +To add a part to your type, click "Add" in the "Parts" section of the Event type. + +![](../Upload/screenshots_675/add_part.png) + +Here you can see the available parts in Orchard (as of the current release). For our Event type, we want to be able to comment on the event ("Comments" part), tag the event ("Tags part"), access the event from the front-end via a URL/route ("Route" part), add the event to the main menu ("Menu" part), and be able to publish the event immediately, on a schedule, or as a draft ("PublishLater" part). + +Also add the "Common" part so that your items can appear in lists of content items. + +![](../Upload/screenshots_85/add_part2.png) + +Types, fields and parts can have settings as well. The specific settings that are available on the fields or parts is determined by the features that are activated in Orchard. If we have enabled the "Indexing" feature, there is a setting to "Index this content type for search" and on each field, a setting to "Include in the index". Select these options for the "Location" field of the custom "Event" type. This will enable visitors of your site to search by location on the front-end (when the "Search" feature is enabled). Hit Save. + +![](../Upload/screenshots_675/content_type_field_settings.png) + +Now that we have defined our custom content type, let's create a new item of this type. Notice the "Create New Event" link in "Manage Content Types". + +![](../Upload/screenshots_675/create_new_event.png) + +Similarly, there is a new admin menu link entitled **Event** under **New**. Click either one of these links to create a new "Event" content item. + +![](../Upload/screenshots/ContentTypes_newevent.png) + +We can see that the editor for our "Event" type has all the fields and parts we defined. It has a **Title** and **Permalink** because of the **RoutePart**, a **Location** and **Date** because of the fields we added, a **Tags** input from the **Tags** part, a **Show on main menu** checkbox from the **Menu** part, and the ability to enable comments from the **Comments** part. The fact that we can **Publish Now**, **Publish Later** or **Save As Draft** is given by the **Publish Later** part. Once you have filled in these fields, go ahead and publish the event. + +![](../Upload/screenshots_675/ContentTypes_adddinner.png) + +Looking at the "Manage Content" screen in the Orchard admin panel, we can see our event item listed among the pages in the site! + +![](../Upload/screenshots_675/manage_content_event.png) + +On the site's front-end notice the event has been added to the main menu (as expected), and that our fields and parts are being displayed correctly here as well. + +It is possible to customize the way the event appears and template its rendering. See [Template File Syntax Guide](Template-file-syntax-guide) for more information on how to do that. + +![](../Upload/screenshots/ContentTypes_displayevent.png) + +Let's try out the Search capability against our new content type. Make sure you have first enabled the **Indexing**, **Search**, and **Lucene** features in the **Features** admin screen. Now visit the **Search Index** page to view the available fields that are indexed. You should see the **event-location** field in the index as expected (if not, just rebuild the index and you'll see it). + +![](../Upload/screenshots_675/search_index_event.png) + +We can tell the Search feature to query this field by going to the **Settings** admin screen and adding this field to the Search settings. + +![](../Upload/screenshots_675/ContentTypes_addeventlocation.png) + +On the front-end type a keyword that matches the location of your event. + +![](../Upload/screenshots/ContentTypes_searchevent.png) + +Search indexing has indexed our Location field and our event appears in search results as expected! + +![](../Upload/screenshots_675/ContentTypes_searchresults.png) + +This concludes the tutorial on custom content types. If you are interested in delving further, check out the related tutorials on this site for how to build a custom type, field or part using code. diff --git a/Documentation/Creating-global-ready-applications.markdown b/Documentation/Creating-global-ready-applications.markdown new file mode 100644 index 00000000..7d72a4ed --- /dev/null +++ b/Documentation/Creating-global-ready-applications.markdown @@ -0,0 +1,203 @@ + +Orchard supports two kinds of localization: + +* Localization of text strings in the Orchard application and in installed modules. +* Localization of database-driven content items. + +This topic describes both of these features. + + +# Localizing the Orchard Application and Orchard Modules + +All strings in the Orchard application are output through a single `T()` method that can look up a translated string based on the default site culture. By default, Orchard includes strings for English (en-US), but you can add support for additional cultures. Translations for the dashboard UI and all static strings in the front end can also be added to the application through translation files in _.po_ format. To localize a site for a culture, you download and install the appropriate set of _.po_ files, and then you update your site settings as shown in this section. + +> **Note** In .NET Framework applications, localization is usually done using _.resx_ files and satellite assemblies. Orchard takes a more lightweight approach that uses _.po_ files. In Orchard, the number of translation files is the number of modules multiplied by the number of supported cultures. That number could rapidly grow, and the satellite-assembly design wasn't built for that kind of usage. On the other hand, _.po_ files can be loaded and unloaded on demand. Like _.resx_ files, _.po_ files are a standard format for which many tools exist. + +## Installing translation files + +As an example, download a set of _.po_ translation files for French (fr-FR). Browse to the page for the files at the following URL: + +. + +Click the link to download the _.po_ files and save the _.zip_ file to your computer. + +### Method 1: Extracting the zip + +Extract the downloaded _.zip_ file into the root folder of your website. Make sure you extract the contents to the actual Orchard root folder, and not to a subfolder named for the _.zip_ file. When Windows opens a **Confirm Folder Replace** window and asks whether you want to merge the extracted contents into the Orchard folders of the same names in your website, select **Do this for all current items** and then click **Yes** to merge in the translation files. + +This method of extracting the po files by expanding the zip file into your site's directory is very simple but if your site does not have all the translated modules that are in the file, you may end up with some additional directories that you don't need. In order to avoid that, you can use the following alternative method. + +### Method 2: Using Translation Manager + +The [Translation Manager](http://orchardproject.net/gallery/List/Modules/Orchard.Module.Vandelay.TranslationManager) module, available from the gallery, adds commands to install translation files more parsimoniously. + +Once you have the module installed and the po file that you want to install downloaded, enter the following command, replacing the path to the po file as necessary: + + + install translation c:\temp\fr-FR.zip + + +This should have only extracted those resources for the modules that are actually installed that it has translations for. If a module is not found, running the command won't create unnecessary directories and your Orchard site will remain clean. + +If you later install additional modules for which a translation exists, it is possible to re-run the command. + +## Switching the site to another culture + +To change the default culture for the application, go to the **Settings => General** screen in the Orchard dashboard. Under **Default Site Culture**, click **Add or remove supported cultures for the site**. + +![](../Upload/screenshots/add_cultures_settings.png) + +In the **Cultures** screen, select a culture from the **Add a culture** list (for example, **fr-FR**) and then click **Add**. The culture code is added under **Cultures this site supports**. To remove a culture, click the **x** button next to it. + +![](../Upload/screenshots/Culture_available_fr.png) + +After you've added one or more cultures, click **General** on the dashboard to return to the **Manage Settings** screen. + +In the **Default Site Culture** list, select the culture to set as the default. When you're done, click **Save**. + +![](../Upload/screenshots/Culture_newdefault_fr.png) + +Assuming that you have the appropriate set of _.po_ files installed, applying a new culture has the effect of translating the text in the dashboard menu and UI text. The following illustration shows the effect of changing the culture to **fr-FR**. + +> Note: The translation files might not be complete. + +![](../Upload/screenshots_675/default_site_culture_fr_675.png) + +Setting the default site culture to a specific culture won't have any effect unless you have a corresponding translation file installed. Orchard searches the following paths to find translation files, from most to least specific: + +* **Core localization file path** _~/Core/App\_Data/Localization/<culture-code>/orchard.core.po_ +* **Modules localization file path** _~/Modules/<module-name>/App\_Data/Localization/<culture-code>/orchard.module.po_ +* **Theme localization file path** _~/Themes/<theme-name>/App\_Data/Localization/<culture-code>/orchard.theme.po_ +* **Root localization file path** _~/App\_Data/Localization/<culture-code>/orchard.root.po_ +* **Tenant localization file path** _~/App\_Data/Sites/<tenant name>/Localization/<culture-code>/orchard.po_ + +## Translation availability + +You can download additional _.po_ files for other cultures from [http://orchardproject.net/localize](http://orchardproject.net/localize). Translations are provided by the community. If you don't find the culture you're looking for, please consider contributing it. It's a few hours of work and it will benefit the whole community. + +## Contributing new translations + +### Working with a plain text editor + +The localization tool available at [http://orchardproject.net/localize](http://orchardproject.net/localize) can prepare stub files for a specific language. Go to [http://orchardproject.net/Localize](http://orchardproject.net/Localize), select the desired culture in the drop-down and click "Create". This will take you to the page for that language, where none of the translations will be available. Click the link on the top of the page that says "Download the PO files". + +The downloaded _.zip_ file contains the set of _.po_ files that you can edit using a text editor. When you're done, please subscribe to our localization mailing list by sending email to , and then [send the zipped package of _.po_ files to the list](join-orchard-localization@lists.outercurve.org). + +Please make sure when working with _.po_ files that the files are saved in UTF-8 with Byte Order Mark. This is usually a setting in your text editor (in Notepad it is under the Encoding drop-down in the "Save As" dialog). + +#### Translation File Format + +The following illustration shows the format of a translation file. Each text string is represented by elements listed in the following table. + +A reference (see below) | `#: reference-string` +----------------------- | --------------------- +An ID, which is often the original (untranslated) string. After the ID is set, this string should not be changed even if the English string changes, so that existing translations continue to work even if they're not immediately updated. | `#| msgid "id-string"` +The current English string for reference. This helps the translator. | `msgid "English-string"` +The translated string. | `msgstr "translated-string"` + +![](../Upload/screenshots_675/fr_po_file.png) + +#### Resource String Reference + +The reference for a resource string in a _.po_ file (the `reference-string` value described in the previous section) is optional. If no reference is specified, the resource string will be used as a fallback whenever a resource with the same ID is queried with a reference that can't be found. This is a useful way to create generic resource strings that are used in multiple places in the application and are not context-sensitive. You can always override a generic fallback like this as needed. + +The reference strings can be stored in different locations, depending on how the string is used in the application: + +* **Strings from views**: Use the virtual path of the view from the root of the application (for example, _~/Themes/TheThemeMachine/Views/User.cshtml_). +* **Strings from _.cs_ files**: Use the fully qualified type name of the class where the string is being used (for example, `Orchard.Packaging.AdminMenu`). +* **Strings from module manifests or theme manifests**: Use the virtual path of the manifest from the root of the application (for example, _~Themes/TheThemeMachine/Theme.txt_). Note that module and theme manifest localization uses a path for fields as the key. For example, the Author field uses the key "Author" and the Description field of the Gallery feature would be under the key "Gallery Description". + +### Working with the online translation tool + +It is also possible to work on translations online. In order to do so, you must first obtain a login from us that has the rights on the language that you want to work on. This is a one-time step that is unfortunately necessary and that can be done by sending e-mail to . + +Once you have your login, please use it at [http://orchardproject.net/Account/LogOn?ReturnUrl=%2flocalize](http://orchardproject.net/Account/LogOn?ReturnUrl=%2flocalize). You may now navigate to a new or existing translation and start working. + +On the left of the page, you'll notice a list of the translation sections (core, modules, themes). Click the right item. + +![](../Attachments/Creating-global-ready-applications/LocalizationChooseFile.PNG) + +The list shows each string with its default culture version, its context (usually the path of the file that you would need to open to see the string in context, where it is defined) and the current translation if it exists: + +![](../Attachments/Creating-global-ready-applications/LocalizationStrings.PNG) + +The color of the default culture version reflect the status of the translation. + +* If the string is dark gray, the translation exists. +* If the string is orange, it means that a translation in the current culture exists but the string is not used by the application anymore. Usually you'll want to delete orange strings. +* If the string is red, the translation doesn't exist and needs to be written. + +On the right side of each string, you'll see an _Edit_ button and for the orange ones a _Delete_ button. + +If you choose to delete an obsolete orange string, you'll be presented with a confirmation dialog: + +![](../Attachments/Creating-global-ready-applications/LocalizationDelete.PNG) + +When you hit an _Edit_ button, you'll be able to modify or create a translation with the default culture version as a reference: + +![](../Attachments/Creating-global-ready-applications/LocalizationEdit.PNG) + +#### Keyboard shortcuts + +Because translating is such a repetitive task, keyboard shortcuts have been added to the online translation tool so that it should be possible to translate a whole file without touching the mouse. + +* To go to the next edit button, use the Tab key (SHIFT + Tab to go back). +* To switch to edit mode for the currently focused string, hit the space key. +* In the editor, hit CTRL + Enter to save, or Esc to cancel. + +### Contributing files for third party modules + +Our localization infrastructure is built to host translations for third party modules. If you are the author of a module or want to contribute translations for a module, you can generate po files for it using the [Translation Manager](http://orchardproject.net/gallery/List/Modules/Orchard.Module.Vandelay.TranslationManager) module. + +From an Orchard command line, type the following command (for the example of the Bing.Maps module): + + + extract default translation /Extensions:Bing.Maps /Output:\temp + + +This will create a new Orchard.en-us.po.zip file with the strings for the module. The command looks at the source code for the module and creates entries for T-wrapped strings, manifest strings and everything that should be localizable. + +Please send this file to so that we can add it to the online localization database. + +# Localizing Database-Driven Content Items + +In addition to application and module localization, Orchard provides the ability to translate content items that are stored in the database. To localize content items, you must enable the **Localization** feature. In the dashboard, click **Modules**, and then on the **Features** tab you will see **Localization**. Click the **Enable** link. + +![](../Upload/screenshots_675/Localize_enable_675.png) + +By default, both the **Page** and **Blog Post** content types are localizable, because they both contain the **Localization** part. You can add the **Localization** part to other content types that need translation. Click **Content** on the dashboard, and then view the items in the **Manage Content** screen. Notice the **+ New Translation** link for each content item. + +![](../Upload/screenshots_675/new_translation_675.png) + +> **Note** This link appears only if you have more than one culture enabled on the site (see previous section), and if you have enabled the **Localization** feature. + +Clicking the **+ New Translation** link allows you to define a translated version of the content item to be associated with the "parent" content item (in the site's default culture). Each translated content item is treated as a unique content item in the system. On the **Translate Content** editor screen, you can define the culture code for the content item. The permalink will change accordingly in order to ensure that URLs are unqiue for each translation. You can then translate the content item from the default site culture to the selected culture. + +![](../Upload/screenshots_675/Localize_content_675.png) + +Add some translation text in the body of the page, and then click **Save**. After the content item is saved, the current culture code is indicated, along with links to any related content items in different cultures. + +When you browse content items on the site, if there are translations available for a content item, links to those content items will be displayed. This makes it easy for your site visitors to switch between translations of the item. This is what the site looks like when you view the English (en-US) item: + +![](../Upload/screenshots_675/Localize_en_downloadpg_675.png) + +Click the culture code link to see translated version of the page. When you do, the original cultural code (en-US) appears as a link to the original page. + +![](../Upload/screenshots_675/Localize_fr_downloadpg_675.png) + +To enable localization for custom content types, add the **Localization** part to the content type. For example, to add localization to a custom content type named **MyEvent**, click **Content** on the dashboard, and then click the **Content Types** tab. Click **Edit** on the **MyEvent** type (this example assumes the custom type already exists). Click **Add** in the **Parts** section of the type. The **Add** screen is displayed, and you can select **Localization** or other parts to add. + +![](../Upload/screenshots/add_localization_part_MyEvent.png) + +For more information about creating and working with custom content types, refer to the [Creating Custom Content Types](Creating-custom-content-types) topic. + +> **Note** The localization feature is a work in progress, and not all parts of the Orchard application are yet localizable. For example, Orchard does not yet provide an automatic way to filter and display only content items in a given culture (one instance of this is the browser's default culture). We will address this in a future release. In the meantime you can provide your own implementation of `ICultureSelector` in a module. If you want to give us feedback on localization support in Orchard (for example, to help us understand the scenarios that are important for your site), please [join our mailing list](join-orchard-localization@lists.codeplex.org) and drop us a line! + + + +### Change History +* Updates for Orchard 1.1 + * 3-17-11: Updated for references to dashboard. + * 3-17-11: Updated screens and procedures in section on localizing database-driven content items. + * 3-18-11: Updated screens and procedures in section on localizing the Orchard application and modules. + * 4-12-11: Structure of the document modified. Added online tool tutorial. diff --git a/Documentation/Creating-lists.markdown b/Documentation/Creating-lists.markdown new file mode 100644 index 00000000..42e0cd2d --- /dev/null +++ b/Documentation/Creating-lists.markdown @@ -0,0 +1,209 @@ + +In Orchard, you can create custom content items and assign them as navigation menu entries. If you have more than a few custom content items, you'll probably want to organize them in lists. This topic walks you through this process. In the walkthrough, you'll create a custom content type and display its items in lists. (For information about how to create a custom content type, see [Creating Custom Content Types](Creating-custom-content-types).) + + + +# Creating a Custom Containable Content Type + +To begin, you will create a custom content type that represents a book review. + +On the dashboard, click **Content**, and then click the **Content Types** tab. Click **Create New Type**, and then in the **Display Name** field, enter the name "Book Review". (The **Content Type ID** field automatically generates an ID value that is based on what you entered for the display name, but without spaces.) Click **Create** to finish creating the new type. + +![](../Upload/screenshots_675/create_newcustom_contentType_675.png) + +A screen displays in which you can add content parts to the newly created content type. Select the check box for all of the following content parts to add them to your newly created content type. + +* **Body**. Adds a body section with a rich-text editor that you can use to enter reviews. +* **Comments**. Enables users to comment on the reviews. +* **Common**. Gives each review a base set of properties, including an owner, a container, versions, a creation date, a publication date, and a modification date. +* **Containable**. This part tells Orchard that the items of this type can be attached to a list and enables dashboard options to manage the relationship between the items and lists. This is the most important part for the purpose of this walkthrough. + > **Important** Always add the **Common** part when you add the **Containable** part. Otherwise you will not be able to add your items to a list. +* **Route**. Provides friendly URLs for book reviews. +* **Tags**. Lets you add tags to book reviews. + +> **Note** You can modify an existing content type to add the **Containable** part, which will allow the site administrator to attach items of that type to lists. + +The following illustration shows the new **Book Review** content type with all the parts selected: + +![](../Upload/screenshots_675/add_parts_bookreviewtype_675.png) + +Click **Save** to finish adding the content parts to the type. An edit screen displays the parts you just added to the type, and provides controls to add fields as well. + +In the **Edit Content Type** screen, click **Add** next to **Fields**. + +![](../Upload/screenshots_675/add_fields_bookreviewtype_675.png) + +Add each of the following fields by entering the field name in the **Add New Field** screen (no spaces allowed), and then click **Save**. + +* **Buy**. This field points to a commerce site where the book can be bought. +* **Verdict**. This field indicates a recommendation for the book, such as "Buy", "Read", or "Skip". + +![](../Upload/screenshots_675/add_fields_bookreviewtype_1_675.png) + +After you have added the fields, your custom type looks like the following illustration. Click **Save** to save the custom content type. + +![](../Upload/screenshots_675/completed_bookreview_contenttype_675.png) + +On the dashboard, expand the **New** menu. You see the **Book Review** content type. Don't click the new type on the dashboard yet. First you will create a book container to display book reviews in a list rather than as individual items. + +![](../Upload/screenshots/dashboard_bookreview_contenttype.png) + +# Creating a List of Books + +To create the **Book Review** list, in the **New** menu of the dashboard, click **List**. Name the new list "Book Reviews" and in the **Contains** field, select "Book Review" from the drop-down list. Select the **Show on main menu** option, and enter "Book Reviews" in the **Menu Text** field. When you're finished, save the new list. + +![](../Upload/screenshots_675/create_bookreview_list_675.png) + +# Creating Book Content Items + +Now you can start creating book reviews. + +In the dashboard, click the new **Book Review** menu item. Create a few book reviews to populate the list. For each review you create, add values to the following fields, and then click **Publish Now**. + +* **Add To**. Select **List: Book Reviews** from the drop-down list, so that the review is added to this list. +* **Title**. Enter the book title. A URL is generated based on the title. +* **Body**. Enter review comments. +* **Buy**. Add a URL to a site where the book can be purchased. +* **Verdict**. Add a value indicating your recommendation (buy, read, skip). +* **Tags**. Optionally, enter tags so that the list of reviews can be filtered. + +![](../Upload/screenshots_675/completed_bookreview_csnutshell_675.png) + +# Displaying the List + +To see the list of book reviews, return to the home page, and then click the new **Book Reviews** menu item. + +![](../Upload/screenshots_675/completed_bookreview_list_675.png) + +# Customizing How the List is Rendered + +The **Book Review** content type uses a text field for the **Buy** field, because that's the default option in Orchard. However, because this field is intended to contain URLs, a URL field would work better. No specialized URL field available, but you can modify the rendering of the text field to make it better suited for URLs. Create the following new text file in your Orchard site: + +_~/Themes/[Current theme for your site](Current theme for your site)/Views/Fields/Common.Text.cshtml_ + +Copy and paste the following code into the new file: + + + @using Orchard.Utility.Extensions; + @{ + string name = Model.Name; + string value = Model.Value; + } + @if (HasText(name) && HasText(value)) { +

+ @if (name == "Buy") { + Buy this book + } + else { + @name.CamelFriendly(): + @value + } +

+ } + + +This template looks at the name of the field, and if the name is "Buy", the template changes the rendering to be a link to the value of the field. + +In addition to customizing how fields render in a custom content type, you can change what's displayed and where it's displayed by using a _placement.info_ file. If you already have a _placement.info_ file at the root of your site's current theme folder, edit it and add the **Match** element shown in the following example before the `</Placement>` closing tag. If you don't already have a _placement.info_ file, create a new file and add the following content: + + + + + + + + + + + + + + +This placement file affects only the **Book Review** content type, as specified in the first **Match** element. Inside the first **Match** element there are two child **Match** elements that match the **Detail** and **Summary** display types. Those matches specify how book reviews are rendered in two cases: the details view and the list view. + +When the details are displayed, the placement file specifies that the body of the review should appear at the beginning of the **Content** zone, the tags at the end of the same zone, and the comments in the **Footer** zone. If you are currently signed in as an admin user, temporarily sign out so that you can see the book reviews as a user would. Click one of the book reviews to see how the module that you added changes the rendering. + +![](../Upload/screenshots_675/bookreview_details_customrender_675.png) + +When the whole list of books is displayed, you want to display a more abbreviated view, such as the title and summary only for each book. To suppress the display of the comment count, the tags, the metadata and the fields, the _placement.info_ file sends those shapes to the "Nowhere" zone. The "Nowhere" zone is not actually a defined Orchard zone, it is simply a standard way in **.info** files of suppressing elements you want to hide by sending them to an undefined zone. The summary is sent to the **Content** zone. Click the **Book Reviews** menu entry to view the updated rendering of your list of reviews. + +![](../Upload/screenshots_675/bookreview_list_placementinfo_675.png) + +> **Note** The zones referred to in this section of the topic are not layout-level widget zones, but rather local zones. As an example of how these are defined, check out the _/Core/Contents/Views/Items/Content.Summary.cshtml_ file. + +# Displaying Book Lists as Widgets + +The next task is to display the latest book review in a right-hand sidebar on the home page of the site. You will use a container widget object to do that. + +Sign back into your site, and on the dashboard click **Widgets**. On the **Widgets** screen, in the drop-down list under **Current Layer**, select the **TheHomePage** layer. In the list of zones, find the zone named **Aside Second** and click **Add** next to the zone. In the **Choose a Widget** screen, click **Container Widget**. The **Add Widget** screen is displayed. + +![](../Upload/screenshots_675/bookreview_sidebar_addwidget_675.png) + +In the **Title** field, enter "Latest Book Review". Under **Show items from**, make sure that **List: Book Reviews** is selected. Then save the widget. + +Return to the home page, and notice that the latest reviews from your book reviews list are now displayed in the sidebar. + +![](../Upload/screenshots_675/bookreview_list_rightsidebar_675.png) + +# Creating a Custom List Widget + +Using the filter feature, you can filter the values of custom properties named **Custom1**, **Custom2**, and **Custom3**. This in turn lets you filter what items from a list are displayed in a page. Now you will add some custom properties that will let you filter the display of your reviews. + +In the dashboard, click **Content**, and then click the **Content Types** tab. Click **Edit** next to **Book Review**. On the **Edit Content Type** screen, click **Add Parts**. + +![](../Upload/screenshots/bookreview_contenttype_addCustomProperties.png) + +Select the **Custom Properties** part, and click **Save**. + +Now return to the **Book Reviews** page in your site and edit one of your book reviews. You will see text fields for the three new properties. Enter "Featured" into **Custom One**, and then save the updated review. + +![](../Upload/screenshots/bookreview_contenttype_editCustomProperties.png) + +You can repeat the last step for any other reviews you'd like to feature on the home page. + +To filter the reviews so that only featured reviews are displayed on the home page, click **Widgets** on the dashboard, and in the **Widgets** screen, select the **TheHomePage** layer from the **Current Layer** drop-down list. Then click the **Latest Book Review** widget that you created earlier. + +In the **Edit Widget** screen, select the **Filter items** option, select the **Custom 1** property from the first drop-down list, select **is equal to** from the second drop-down list, and enter "Featured" in the third drop-down list. This filters reviews so that only featured reviews are displayed on the home page. When you're finished, save the updated widget. + +![](../Upload/screenshots/bookreview_featuredsidebar_filter.png) + +Browse to your home page. Notice that only the book reviews for which you entered "Featured" in the **Custom 1** field are displayed. + +![](../Upload/screenshots_675/bookreview_homepagesidebar_featuredfilter_675.png) + +Now click **Widgets** on the dashboard, return to the **Widgets** screen, and again select the **TheHomePage** layer from the **Current Layer** drop-down list. Add another widget to the **TheHomePage** layer as you did previously by clicking **Add** next to the **AsideSecond** zone, and then click **Container Widget** to add it. This time in the **Add Widget** screen, set the **Position** value to 6 so that the new list appears below the first one. Set the **Title** property to "Featured Reviews", set the **Maximum number of items to display** value to 2, and select the **Filter items** option. Set the filter criterion to "Custom 1 is equal to Featured". Save your changes. + +![](../Upload/screenshots/bookreview_homepagesidebar2_addwidget.png) + +On the **Widgets** screen, click the **Latest Book Review** widget to edit it. Clear the **Filter items** check box, which means that it no longer filters reviews. Save the widget. + +The following illustration shows what the home page looks like with the two widgets that you configured. It displays both the latest reviews ordered by date, and the featured review in which you added the value "Featured" to the Custom 1 property field for a specific book, and filtered for that property. + +![](../Upload/screenshots/bookreview_homepagesidebar_bothwidgets.png) + +# Pagination + +The list feature has built-in support for pagination on list pages. + +On the dashboard, click **Content**, and then click **Edit** next to **Book Reviews**. In the **Edit list** screen, change the page size to a number that is smaller than the number of reviews you've added to the system. Leave **Show paging controls** selected. Save the changes. + +![](../Upload/screenshots/bookreview_editList_paging.png) + +Go back to the **Book Reviews** page. Notice that there is an **Older** button that you can click to see older book reviews. + +![](../Upload/screenshots_675/bookreview_editList_paging_bookreviews_675.png) + +> **Note** Pagination is available only on list pages and not on list widgets. This is by design, because pagination within a widget would allow multiple pagers on the same page, which could be confusing. + + + + +# Change History +* Updated for Orchard 1.1 + * 3-18-11: Updated all screens, menu options, and procedures for working with lists. diff --git a/Documentation/Creating-types-from-code.markdown b/Documentation/Creating-types-from-code.markdown new file mode 100644 index 00000000..e69de29b diff --git a/Documentation/Custom-permissions.markdown b/Documentation/Custom-permissions.markdown new file mode 100644 index 00000000..e69de29b diff --git a/Documentation/Custom-settings.markdown b/Documentation/Custom-settings.markdown new file mode 100644 index 00000000..e69de29b diff --git a/Documentation/Customizing-Orchard-using-Designer-Helper-Tools.markdown b/Documentation/Customizing-Orchard-using-Designer-Helper-Tools.markdown new file mode 100644 index 00000000..45e910d0 --- /dev/null +++ b/Documentation/Customizing-Orchard-using-Designer-Helper-Tools.markdown @@ -0,0 +1,39 @@ + +Orchard provides a designer tool named **Shape Tracing** that enables you to customize the appearance of your site. The **Shape Tracing** module provides tools that you can use to select sections of your website and discover information about the rendering code. + +## Getting Started with Shape Tracing +To use **Shape Tracing**, first enable the **Shape Tracing** feature in the dashboard. The **Shape Tracing** feature comes with the [Designer Tools](http://orchardproject.net/gallery/List/Modules/Orchard.Module.Orchard.DesignerTools) module, that you may have to install. After you enable the feature, you will notice a narrow frame across the bottom of the web page when you navigate to your site, similar to the following illustration: + +![](../Upload/screenshots_675/ShapeTracing_ExpandFrame_675.png) + +When the **Shape Tracing** frame is collapsed, your site functions as it would normally. However, when you click the icon, the frame expands and displays **Shape Tracing** features. + +## Shape Information +When the **Shape Tracing** frame is expanded, you can hold the mouse pointer over a section of a page and that section is highlighted. Click the highlighted section to display information about the shape and how it is rendered. + +![](../Upload/screenshots_675/ShapeTracing_HighlightShape_675.png) + +The left side of the frame displays which shape is selected. It also enables you to select which shape to highlight by providing a navigable tree for the shapes. + +![](../Upload/screenshots/ShapeTracing_SelectShape.png) + +The right side displays information about the selected shape and enables you to select which type of information to display. + +![](../Upload/screenshots/ShapeTracing_ShapeInfo.png) + +The **Shape Tracing** pane displays the following information: + +* **Shape**. Information about the shape and the template to render the shape. Includes the option of creating alternates as described later in this article. +* **Model**. Information about the model for this shape. +* **Placement**. The _placement.info_ file. +* **Template**. The code in the template file +* **HTML**. The HTML for rendering this shape. + +## Creating Alternate Templates +The **Shape Tracing** interface displays links that let you automatically create alternate templates for a shape. The interface displays the available alternate templates and includes a link titled **Create** to generate that template. + +![](../Upload/screenshots_675/ShapeTracing_CreateAlternate_675.png) + +The **Create** option only creates the template in the specified directory. You must customize the template to render the shape as needed. If you are using Visual Studio, you must include the template in your project by selecting **Add** > **Existing Item** in **Solution Explorer**. + +For more information about how to create alternates, see [Alternates](Alternates). diff --git a/Documentation/Customizing-the-default-theme.markdown b/Documentation/Customizing-the-default-theme.markdown new file mode 100644 index 00000000..cb770637 --- /dev/null +++ b/Documentation/Customizing-the-default-theme.markdown @@ -0,0 +1,100 @@ + +The default Orchard theme is called the Theme Machine, and it is designed to be a versatile starting point for customizing and developing new themes. + +This article introduces you to the Theme Machine and demonstrates how you can create your own theme by customizing the Theme Machine style sheet (Site.css). + + +# Introducing the Theme Machine +The Theme Machine provides a flexible and powerful foundation to base themes upon. The following image shows the file structure of the Theme Machine. + + +![](../Upload/screenshots/ThemeMachine_structure.PNG)The files at the heart of the Theme Machine are the layout page (Layout.cshtml) and the style sheet (Site.css). + + +# Overview of the Layout Page +The layout page defines multiple zones using conditional statements. The conditional statements cause only the zones to be rendered for which content is provided. If you don't provide the content, the rendered page will not contain the zone. The following images shows the zones defined in the layout page. + +![All the zones in The Theme Machine](../Attachments/Anatomy-of-a-theme/TheThemeMachineZoneScreenshot.PNG) + +You will typically provide content for selected zones by using the Admin Panel. + + +# Overview of the CSS Styles +The style sheet (Site.css) for the Theme Machine provides an extensive set of styles for fine-grained control of the look and feel of your website. The style sheet groups styles to make it easier for you to locate a style that you want to customize. The following table shows the groupings and describes the type of styles available to you. + +Grouping | Description +--------- | ------------------------------------------------------------------------------------------------------------ +General | Contains the default styles for the body, headings, lists, and text elements. +Forms | Contains styles related to HTML forms, such as **form**, **legend**, **fieldset**, **label**, and **input**. +Structure | Contains page layout styles for each of the zones defined in the Theme Machine. +Main | Contains styles defined for blog posts, comments, tagged search, and search results. +Secondary | Contains additional layout styles for secondary content in aside zones, tripel zones, and footer quad zones. +Widgets | Contains styles for selected widgets such as the search widget, edit-mode widgets, and content mode. +Pager | Contains styles related to a pager shape. +Misc | Contains styles for miscellaneous formatting, such as small, large, quiet, and highlight. + +# Creating a Child Theme +You can create your own theme by customizing the Theme Machine. However, you should not edit the Theme Machine files directly. Instead, you should create a child theme and copy any files that you intend to change into the child theme. You don't need to copy any files that you do not intend to change -- a child theme inherits from its parent theme, and overrides just the files from the parent theme that you have customized. When your child theme is active as the current theme, Orchard first looks to that theme to resolve files, and if not found, it will look to the parent (BaseTheme) to find the files instead (and so on... even your parent theme can have it's own parent). + +The process of creating a child theme is this: + +1. Generate the child theme's code structure using the command-line CodeGen utility. +2. Copy the files you want to change from the Theme Machine to your child theme. +3. Edit the files in the new child theme. +4. Apply the new theme to your website. + + +## Generating the Theme Structure +To generate the code structure for your new theme, we are going to use the **Code Generation** feature, which can be obtained from the **Gallery** > **Modules** page in the admin panel. Once you have installed and activated the code generation feature, you will be able to generate a new theme from the Orchard command-line. Refer to the [Using the command-line interface](Using-the-command-line-interface) topic if you need to know more about using commands in Orchard. + +Open the Orchard command-line utility and enter the following command: + + + codegen theme MyTheme /BasedOn:TheThemeMachine + + +If you are using Visual Studio for editing (or if you plan for your Theme to eventually contain code files too), you may also want specify the CreateProject and IncludeInSolution options as follows: + + + codegen theme MyTheme /BasedOn:TheThemeMachine /CreateProject:true /IncludeInSolution:true + + + +This line tells Orchard to create the code structure for a new theme, sets the name of the theme to _MyTheme_, and directs Orchard to base the theme on _TheThemeMachine_. The CodeGen command generates the following folder structure: + +![](../Upload/screenshots/NewTheme_structure.PNG) + +The only files created are the Theme.txt and Views\Web.config files. The Theme.txt file (the theme manifest) is where the Admin Panel looks for information such as the name of the theme. This is also where your BaseTheme is specified. Web.config is a configuration file that ASP.NET MVC requires for rendering any views placed in the Views folder. You seldom have to make changes in the Web.config file. + + +## Copying Files from the Theme Machine +To keep this example simple, the only file you will customize will be the Site.css file. Copy the Site.css file from TheThemeMachine\Styles folder to the MyTheme\Styles folder. + +Currently, you must also copy the TheThemeMachine\Views\Layout.cshtml file to the MyTheme\Views folder. (It's anticipated that this step will not be required in later releases.) + + +## Customizing Theme Files +After copying the files you want to customize into your new theme folder, you can make changes to those files. You can also create new files as needed. In this example, the only change you will make is the background color for the body of the page. + +In the Site.css file that you copied, find the **body** style in the **General** section. Then change the background color from **#fff** to **#fff8dc** as shown in the following example: + + body { + font-size: 81.3%; + color: #434343; + background: #fff8dc; + font-family: Tahoma, "Helvetica Neue", Arial, Helvetica, sans-serif; + } +This will change the background color to cornsilk, which is a light yellow. + +You can also provide a thumbnail image of your new theme in the theme's root folder. The image file must be named Theme.png. The image will be displayed in the Admin Panel to help users select a theme. + +The following image was copied from TheThemeMachine and changed to show the light-yellow background color. +![](../Upload/screenshots/NewTheme_thumbnail.PNG) + +## Applying Your New Theme +In the Admin Panel, under **Site Design**, select **Themes**. The **Manage Themes** page is displayed, and the new theme is listed under **Available Themes**: + + +![](../Upload/screenshots/themes_available.png)Click **Set Current**. The **Manage Themes** page is redisplayed showing **MyTheme** as the current theme. + +You can now go to your website to see the new theme in action. diff --git a/Documentation/Definitions.markdown b/Documentation/Definitions.markdown new file mode 100644 index 00000000..9d5579f9 --- /dev/null +++ b/Documentation/Definitions.markdown @@ -0,0 +1,138 @@ + + +## Application +An application is a packaged and ready to use specialized web site. + +#### Examples +Our CMS application is one example of an application. Other examples include Blog, Wiki, Forum or Media Gallery. + +#### Contents +An application can be downloaded as source code by developers, but the most common form will include a precompiled dll, images, stylesheets, theme files and possibly a selection of plug-ins. + +An application typically includes one or several packages (see definition below). + +#### Packaging +Orchard applications can be deployed using WebPI, i.e. as MS-Deploy packages. They can also be xcopied into a web site. + +## Package +A package is the deployment vehicle for all extensions. It is a versioned zip archive. + +## Theme +A theme is a packaged look and feel for the front-end of the application. + +![](../Upload/definitions%2fThemeDefinedStyles.PNG) +Themes are also sometimes called skins. +The most obvious way to personalize an application, themes provide a simple way to modify the structure and styling of the application markup. They should be easy to create, modify, install and switch. They should enable radical changes in presentation to the point where it would be difficult to tell what application technology is powering the site by looking at its UI or its markup. + +#### Contents +A theme usually consists of a file that contains the meta-data and possibly some helpers, a CSS file, images and markup files. Some if not most of the markup files are templates. + +#### Packaging +The theme can either be exploded into its constituent files or can be uploaded under zipped form. + +## Template +A template is a file that contains only structural markup, but no content-specific markup. For example, a template file may describe a two-column layout. In that case, it would contain a place holder for each of the two columns but it does not specify what contents goes into them. This enables templates to be used to display a wide variety of contents. It enables the separation of layout from contents. + +#### Contents +A template is usually one aspx file that defines the markup for the template and the meta-data of the template (author, available zones, etc.). It can have stylesheet, image or other dependencies. + +#### Packaging +A template is deployed as part of the views of the application, or as part of a theme or package. + +## Widget +A widget is a self-contained piece of UI that can be injected into specific placeholders in application pages. + +![](../Upload/definitions%2fWidgets.PNG)Widgets are similar to WebParts, and like WebParts can be added to predefined zones on the page but they are much simpler in implementation. +Widgets may surface the features of a plug-in or other feature of the application, and in many cases depend on underlying application or extended features. + +#### Examples +Examples of widgets include: +* category list +* latest posts +* ads +* blogroll +* search field +* rating UI + +#### Contents +A widget is implemented as a code file (containing meta-data and code), a manifest and at least one user control (also sometimes called partial view in the context of MVC), and optionally an admin user control and resources such as CSS and image files. A widget may have its own controller and routes. + +#### Packaging +A widget can be either exploded into its different constituent files or packaged into a zip file and uploaded to the application under this form. +A widget may be packaged together with its dependencies (such as a plug-in or other type of extension). + +## Plug-in +A Plug-in is a piece of code that hooks into a specific extensibility point of the application to add new features. + +Plug-ins are sometimes called add-ons, extensions or modules in other CMS platforms. + +Plug-ins do not typically expose UI of their own, but may come with one or several specialized widgets whose purpose is to surface their features. + +#### Examples +Examples of plug-ins include: +* replacing emoticon character sequences with images +* spam protection +* profanity filters +* order validation rules +* comments +* ratings +* search +* payment +* shipping + +#### Code +The code of a simple plug-in looks like this: + + public class LiberalBiasPlugin { + public string ProcessHTML(string input) { + return input.Replace("fox", "NPR"); + } + } + + +#### Contents +A plug-in is typically a single file written in C# (or in another .NET language). Other plug-in managers than the default reflection-based plug-in manager will be able to handle plug-ins written in IronPython or IronRuby, as well as plug-ins that are deployed as precompiled dlls. + +#### Packaging +A plug-in may be deployed as a simple code file into app_code or as a class in a compiled dll deployed in bin or even in the GAC (although that last option is somewhat unlikely). + +A plug-in's code file or dll may be distributed and installed as part of a packaged zip file that may contain one or several widgets and corresponding resources. + +## Content-type +A content-type is a top-level feature of the application such as blog or wiki, a collection of top-level content entities.. + +#### Examples +Examples of content-types include: +* Blog +* Wiki +* Forum +* Product +* Media + +#### Packaging +A content-type is typically deployed as part of a package. + +## Content Item +A content item is a unit of contents in a content-type. + +An item is a concept that is close to an entity but more centered around the idea of contents (as in contents management). An item can appear in a list but will also typically have its own page in the site. + +#### Examples +Examples of items include: +* Blog post +* Product +* Photo +* Video +* CMS page + +#### Contents and packaging +Items cannot be dissociated from their type. + +## Content part +A content part is a feature that can enrich any existing content-types without prior knowledge of the content part by the content-type or by the content-type from the content part. + +#### Examples +Examples of content parts include: +* Search +* Tagging +* Comments diff --git a/Documentation/Deploying-Orchard-to-Windows-Azure.markdown b/Documentation/Deploying-Orchard-to-Windows-Azure.markdown new file mode 100644 index 00000000..8ebfd567 --- /dev/null +++ b/Documentation/Deploying-Orchard-to-Windows-Azure.markdown @@ -0,0 +1,132 @@ +Orchard supports building and deploying to the Windows Azure environment. If you don't want or need to build the package by yourself, a binary version of the Windows Azure package is available on the [CodePlex site](http://orchard.codeplex.com/releases/view/50197). This topic describes the steps that you can take to build and packages of Orchard and deploy them to Azure. + +Before you begin this tutorial, you need a [Microsoft SQL Azure](http://www.microsoft.com/en-us/sqlazure/default.aspx?WT.srch=1&WT.srch=1) account as well as the [Windows Azure Storage](http://www.microsoft.com/windowsazure/storage/default.aspx) service. Windows Azure Storage provides a BLOB (Binary Large Object) service, which is how binary content (such as files) are stored on Azure to be acccessed across multiple servers. + + + +# Building and Deploying to Azure +To begin, install [Windows Azure Tools for Microsoft Visual Studio 1.4 (March 2011)](http://www.microsoft.com/downloads/en/details.aspx?FamilyID=7a1089b6-4050-4307-86c4-9dadaa5ed018), which includes the Windows Azure SDK. Download and install VSCloudService.exe which contains both the SDK and the Cloud Services. If you do not already have a local instance of Microsoft SQL Server, install [Microsoft SQL Server 2008 R2 RTM - Express with Management Tools](http://www.microsoft.com/downloads/en/details.aspx?familyId=967225EB-207B-4950-91DF-EEB5F35A80EE&hash=CDEb%2fJRDkSXIcb5rEbkx2M7RlSbrPNqmx7hbB%2bWHG5DbEBxcq9rXHwK4JS2uDdtvAYo2C8xBh%2fnA7yzNC8xD8w%3d%3d). A local SQL Server instance is required in order to work with the Azure Storage Emulator. Management tools are recommended for administering your SQL Azure instance later. + +You can build a deployable package for Azure from [the Visual Studio 2010 command line](http://msdn.microsoft.com/en-us/library/ms229859.aspx). You will need a [source tree enlistment](Setting-up-a-source-enlistment) of Orchard to do this. Run `ClickToBuildAzurePackage.cmd` from the command line in order to build the package. (Depending on your environment, you might need to run the script as an administrator.) ClickToBuildAzurePackage is not in the current 1.2 Azure package but can be obtained from [the Source Code tab on CodePlex](http://orchard.codeplex.com/SourceControl/list/changesets). + +![](../Upload/screenshots_675/click_to_build_azure_package.png) + +When the command completes successfully, you will have an Azure package under the _artifacts_ folder (_artifacts\Azure\AzurePackage.zip_). + +![](../Upload/screenshots_675/click_to_build_azure_package_success.png) + +Unzip the _AzurePackage.zip_ file and edit the _ServiceConfiguration.cscfg_ file. This file contains a sample configuration. + +![](../Upload/screenshots_675/azure_package.png) + +The following example shows the sample configuration. + + + + + + + + + + + + + +To update the configuration with your account details, edit the `value` attribute for DataConnectionString. + + + + +Log in to the [Windows Azure Developer Portal](http://msdn.microsoft.com/en-us/windowsazure/default.aspx). + +![](../Upload/screenshots_675/developer_portal_login.png) + +On the home page, view your projects and services. + +![](../Attachments/Deploying-Orchard-to-Windows-Azure/developer_portal_home.png) + +To find your primary and secondary access keys, view the **Storage Accounts** details by selecting a **Storage Account** in the main screen and then clicking **View** under **Properties** on the right. (This is the account key that you copied to the `DataConnectionString` attributes in the _ServiceConfiguration.cscfg_ file.) + +![](../Attachments/Deploying-Orchard-to-Windows-Azure/developer_portal_storage.png) + +View the details for your SQL Azure service. + +![](../Attachments/Deploying-Orchard-to-Windows-Azure/developer_portal_sqlazure.png) + +Create a new SQL Azure database for Orchard. The example below assumes that you're using the name "orcharddb", but you can name it whatever you like. + +![](../Attachments/Deploying-Orchard-to-Windows-Azure/sqlazure_create_db.png) + +View the details for your Windows Azure Hosted Service. From here you will deploy your package. Click **New Staging/Production Deployment** for either the **Staging** or **Production** node. + +![](../Attachments/Deploying-Orchard-to-Windows-Azure/developer_portal_deploy.png) + +Browse to the package and configuration files that you built from the Orchard command line. Name the deployment and then click **OK**. + +![](../Attachments/Deploying-Orchard-to-Windows-Azure/developer_portal_deploy2.png) + +The Azure Developer Portal uploads the files. + +When the upload is complete, the deployment is in a "Initializing" state. When the state changes to "Ready", you can start using your website. If the process loops between "Initializing", "Busy", and "Stopping", you might have made a mistake in your configuration file and should check it. + +![](../Attachments/Deploying-Orchard-to-Windows-Azure/developer_portal_deploy3.png) + +If all went well, you will see the Orchard setup screen. In order to use Orchard in Azure, you need to configure it against the SQL Azure database in order to ensure that application state is retained while Azure recycles instances of your site during load balancing. + +![](../Attachments/Deploying-Orchard-to-Windows-Azure/azure_setup.png) + +After completing the setup step, you arrive at the familiar Orchard home page and can being configuring your site. + +> **Note** The **Recipe** feature is not available on Azure at this time. To learn more about Orchard recipes, see [Making a Website Recipe](Making-a-Web-Site-Recipe). + +# Redeploying to Azure +When you redeploy to Azure using the same storage, you should clear the contents of the SQL Azure database (or just delete and re-create it). You also need to delete the contents of your Windows Azure Storage (BLOB) to ensure a fresh state. Orchard uses BLOB storage to write your site settings (which in a non-Azure installation are stored on the file system under _~/App_Data_). You can access your BLOB storage from [http://www.myazurestorage.com](http://www.myazurestorage.com). + +![](../Attachments/Deploying-Orchard-to-Windows-Azure/myazurestorage_delete.png) + +You can also use [Cloud Berry Azure Explorer](http://cloudberrylab.com/default.aspx?page=explorer-azure) or [Azure Storage Explorer](http://azurestorageexplorer.codeplex.com) which are client applications. +# Changing the Machine Key +When you deploy to Azure, it is recommended that you define the machine key from the _web.config_ file in the **Orchard.Azure.Web** project before packaging and deploying. + + +# Deploying Orchard to Azure with Optional Modules +The package that you deploy to Azure does not have to be limited to the default modules that are distributed with Orchard. You can include third-party modules or your own modules and then deploy them to Orchard. + +The only constraint is that the modules cannot be installed dynamically from the gallery as you would do with a regular deployment of Orchard, because of the distributed nature of Azure. The local file system is not automatically replicated across instances; instances might get out of sync if this were allowed. + +In order to work around this constraint and to allow you to deploy your own selection of modules to Azure, you can build your own package that includes the modules that you need. + + +## Adding a Module to the Distribution +To add a module to the distribution, edit the Azure solution located in _src/Orchard.Azure/Orchard.Azure.sln_. The following steps use `Contrib.Taxonomies` as an example. + +Copy the module's files to _src/Orchard.Web/Modules/_. + +![](../Attachments/Deploying-Orchard-to-Windows-Azure/azure_module_source.png) + +Open the Azure solution in Visual Studio 2010 and add the project for this module in the _Modules_ folder. + +![](../Attachments/Deploying-Orchard-to-Windows-Azure/azure_module_solution.png) + +In the project named `Orchard.Azure.Web`, add a reference to the newly included project. + +![](../Attachments/Deploying-Orchard-to-Windows-Azure/azure_module_project.png) + +When this is done, launch the build script as described earlier. The resulting package will contain your additional modules. After you've deployed the new package to Azure, you can go to the features screen and enable the features. + + +## Adding a Theme to the Distribution +To add a theme to the distribution, edit the Azure solution located in _src/Orchard.Azure/Orchard.Azure.sln_. The following steps use `Classic` as an example. + +Copy the theme's files to _src/Orchard.Web/Themes_. + +![](../Attachments/Deploying-Orchard-to-Windows-Azure/azure_theme_source.png) + +Open the Azure solution in Visual Studio 2010 and add the files for this theme in the `Themes` project. + +![](../Attachments/Deploying-Orchard-to-Windows-Azure/azure_theme_solution.png) + +When this is done, launch the build script as described earlier. The resulting package will contain your additional themes. + +After you've deployed the new package to Azure, you can go to the themes screen and enable the themes in order to start using them. diff --git a/Documentation/Deploying-to-production.markdown b/Documentation/Deploying-to-production.markdown new file mode 100644 index 00000000..e69de29b diff --git a/Documentation/Developer-FAQ.markdown b/Documentation/Developer-FAQ.markdown new file mode 100644 index 00000000..e8aecbaa --- /dev/null +++ b/Documentation/Developer-FAQ.markdown @@ -0,0 +1,159 @@ + + +## What are the dependencies? +Orchard uses a number of external libraries. They can all be found under \lib directory in your enlistment, as well as are enumerated in [Orchard dependencies and libraries](Orchard-dependencies-and-libraries). + +## What framework versions does Orchard support? +Orchard currently supports the 4.0 version of the .NET framework. + +## What are the default and dev branches? Which one should I be using? +Those are the 2 branches corresponding to trunk (default) and development (dev). + +Feature work in Orchard is being done in 3 week iterations. All the active feature work is being done by the core team in the dev branch. At the end of the iteration, changes get pushed from dev to default. default is a stable branch and is normally always in a "green" state. This should be the branch you would ideally work on. dev is the most recent branch in terms of activity but it can at times be unstable due to ongoing work. Everything in dev in terms of the public surface is also more volatile: APIs can be changed at will and daily, making a potential external contributor working on the branch more difficult. For these reasons, it is advised to use default for your development purposes, and dev only if you're interested in checking out how brand new features are being developed. The delta between the 2 branches will be 3 weeks in the worst case. + +## What types of extensions can I write? +Orchard Modules and Themes are supported extensions today. Note that the module and themes API is a work-in-progress, and although it's possible to build these extensions today, you should expect changes that may break extensions built on the current codebase. Regular MVC 2 Areas are also supported as modules. + +## Where are Modules physically located? +The projects in the "Modules" folder are physically located under the "src\Orchard.Web\Modules" folder. This allows modules to contain ASP.NET views (aspx, ascx) and static content without having to copy files between projects to be able to run the project. + +The Core modules are physically located under the "\src\Orchard.Web\Core" folder. + +## What is a Module.txt file? +This is the module manifest. It has to be present at the root of the module's directory for Orchard to recognize it as a module and load it. It is a YAML-format file. Example module.txt with all possible supported fields: + + + name: AnotherWiki + author: Coder Notaprogrammer + website: http://anotherwiki.codeplex.com + version: 1.2.3 + orchardversion: 1 + antiforgery: enabled + features: + AnotherWiki: + Description: My super wiki module for Orchard. + Dependencies: Versioning, Search + Category: Content types + AnotherWiki Editor: + Description: A rich editor for wiki contents. + Dependencies: TinyMCE, AnotherWiki + Category: Input methods + AnotherWiki DistributionList: + Description: Sends e-mail alerts when wiki contents gets published. + Dependencies: AnotherWiki, Email Subscriptions + Category: Email + AnotherWiki Captcha: + Description: Kills spam. Or makes it zombie-like. + Dependencies: AnotherWiki, reCaptcha + Category: Spam + + +## What is the AdminMenu.cs file? +This file has an implementation of the Orchard interface called INavigationProvider. It lets modules hook themselves into the admin menu in the backend. This is typically where you declare what links should your module inject into the Admin menu and what controller actions these links invoke. + +## What is the Permissions.cs file? +This file has an implementation of the Orchard interface called IPermissionProvider. It lets modules declare a set of permissions as well as attach those permissions to default Orchard roles. Once you add a new permission type to your module here, you will be able to use the Orchard authorization APIs to check that permission against the current user. You will also be able to manage which custom roles the permission belongs to in the Roles administration page. + +## How do I do authorization inside my module against current user/roles? +Orchard comes with a default services implementation of the IOrchardServices interface. Simply include IOrchardService in your constructor and you will get the default implementation injected. Like + + + public AdminController(IMyService myService, IOrchardServices orchardServices) { + _myService = myService; + Services = orchardServices; + } + + +At this point, services gives you Authorizer for authorization, Notifier for writing out notifications, ContentManager for access to the Orchard content manager and TransactionManager. At this point, to check if the current user has a certain permission, you would simply do: + + + Services.Authorizer.Authorize(Permissions.SomeModulePermission, T("Some operation failed")); + + +## What are Core Modules? +Core Modules are Orchard Modules you can find under \src\Orchard.Web\Core. They also constitute the Orchard.Core project in the solution. These are modules that are always enabled and come with the default Orchard installation. See "Why are Core modules modules?" and "Why are Core Modules Core Modules?" for more detailed information. + +## Why are Core modules modules? +The difference is similar to OS concepts of monolithic vs micro-kernel: it was pretty obvious during high level design of Orchard that an extensibility point such as modules was needed. Everything else would constitute the core framework. Take the Common module for example, which introduces the BodyPart, a core concept common to many types of content types, such as blog posts or pages. Now we could've implemented this as part of the Orchard framework dll, and have modules depend on it. But then it wouldn't get the benefit of being a module, such as being able to hook up handlers, drivers, views, routes etc. This also relates to MVC and areas, where everything that belongs to an area is under the same directory. It was pretty clear that the right choice was to get some core concepts out of the framework dll into a separate dll, and have them be modules. This is very similar to non-monolithic operating systems where parts of the core functionality is implemented as modules outside the kernel, talking to it via the same exact interfaces as the more higher level modules. + +## Why are Core Modules Core Modules? +Now that we want core concepts to be implemented as modules, why not put them into the modules directory along with the rest of the more obvious Orchard modules, such as the comments module. Well, this time it's about dependencies. In Orchard, modules that are in the modules directory can be disabled, uninstalled or otherwise updated in a breaking way. We prefer modules that are self-contained and don't require other non-core modules as dependencies, as much as possible. That's part of the entire dynamism behind the content type architecture. Pages and Blog posts, which belong to Pages and Blog modules, don't reference Comments or Tags modules, but it's possible to attach comments or tags to pages and blogposts. This decoupled behavior is ensured by the underlying content type architecture and not by direct reference from one or the other modules. Core modules are part of the Orchard framework and it's ok for modules to depend on them. They will be distributed by us and for all practical purposes are integral parts of the Orchard framework. Modules can depend on them and directly access their public surface. + +## How do I write and run tests? +Orchard comes with a solution folder called Tests. This hosts 2 types of tests: + +* **Unit Tests**: These are NUnit test fixtures. To write a fixture for a module, simply create a new directory under Orchard.Tests.Modules and populate it with your tests. +* **Integration Tests**: These are also NUnit tests, generated using SpecFlow ([http://www.specflow.org](http://www.specflow.org)) .feature files. Your integration tests would go under Orchard.Specs and there are a multitude of examples there you can look at if you are new to the BDD approach. + +Running the unit tests is a matter of right clicking the solution or appropriate project and choose Run Unit Tests. + +> Note: this applies to writing tests for the modules that come with the standard source code distribution of Orchard. To write code for your own third-party modules, please work in your own separated directory. We will provide guidance on setting up a third-party module development environment. + +## How do I contribute my changes to Orchard? +Orchard is a community project and has a number of external contributors. To ensure the patch is accepted to Orchard, there are a few points to highlight: + +* **Code Conventions**: Orchard code conventions and style guidelines are explained in [Code conventions](Code-conventions). The source tree also contains a ReSharper ([http://www.jetbrains.com/resharper](http://www.jetbrains.com/resharper)) file at \src\Orchard.4.5.resharper that's going to considerably simplify you working with the Orchard conventions. + +* **Patch submission process:** Is detailed in [Contributing patches](Contributing-patches). Although .patch files are still supported as explained there, it is preferred to use forks and use the CodePlex UI to submit a pull request. For smaller changes patch files are also OK, however there is no CodePlex UI to manage them so you would have to attach them to bugs and hope they don't get lost. Also, always use the default branch for patches. + +## How to build a WCF service that exposes Orchard functionality? + +To host a WCF Service in Orchard, with all of its goodies coming from IoC you have to: + +Create a SVC file for your service with the new Orchard Host Factory: + + + <%@ ServiceHost Language="C#" Debug="true" + Service="Orchard.Service.Services.IService, Orchard.Service" + Factory="Orchard.Wcf.OrchardServiceHostFactory, Orchard.Framework" %> + + +Register the service normally as an IDependency. + + + using System.ServiceModel; + + namespace Orchard.Service.Services { + [ServiceContract] + public interface IService : IDependency { + [OperationContract] + string GetUserEmail(string username); + } + } + + +Provide implementation (i.e.: Service : IService). + +## What's in App_Data? + +The App_Data folder is used to store various kinds of data. Contents of App_data are never served. The contents are organized this way: + +* File:**cache.dat** is a cache XML document describing what features are enabled for each tenant in the site. This being only a cache, modifying it may have unpredictable results. +* File:**hrestart.txt** is a file that is touched by the system to indicate a need to restart the application. +* Folder:**Dependencies** is used by dynamic compilation to store compiled dlls and has an XML file, dependencies.xml that tracks how each module was compiled (dynamically or not). +* Folder:**Exports** contains export XML files generated by the import/export feature. +* Folder:**Localization** contains localization po files. +* Folder:**Logs** contains log files. +* Folder:**RecipeQueue** is used during setup to queue the recipes to execute. +* Folder:**Sites** contains one folder per tenant. The default tenant is in the Default folder, which is all there is if no tenant was created. Each folder contains the following: + * **mappings.bin** is a binary serialized cache of nHibernate mappings. + * **Orchard.sdf** is the SQL CE database file for the tenant. + * **reports.dat** is a legacy log file. + * **Settings.txt** describes the low-level settings for the tenant (database provider, connection string, etc.) +* Folder:**Warmup** contains cached versions of pages generated by the warmup module, and a warmup.txt file that contains the timestamp for the last warmup file generation. + +## Understanding bug status and triage + +When you submit a bug, the team (or anybody subscribing to notifications) receives an e-mail. We do regular triage meetings with a small committee, sometimes as often as daily and usually at least once a week. + +When we do triage, we make a query that returns all bugs in "Proposed" state, ordered by number of votes. This means that we are always looking at the most voted bugs first. If you care about a bug, you should vote for it, and it won't fall on deaf ears. + +A bug that is still in "Proposed" state has not been triaged yet. When we look at a bug, several things can happen. We may close it if it doesn't reproduce, if it's by design or if it was fixed since submitted. We may ask for more information (and leave it in "Proposed" state). Or finally, we may move it to the "Active" bucket. + +A bug that is in "Active" state has been triaged and should have been assigned a release. The release usually is one of the planned releases. Planned releases are usually the ones we are currently working on, plus a "Future Versions" release that we use for bugs and features that we want to handle but don't think we can do in the current cycle. The "Assigned to" field is only set when the bug is scheduled to be fixed in the current iteration or cycle. If it's in "Future Versions" it is usually unassigned. + +Impact is usually set during triage but a "Low" value does not necessarily mean much: this is the default value so it might just mean that it hasn't been touched. It's OK to investigate with the team on the impact of a bug you care about. + +## Developer Troubleshooting + +* **Record Names**: Your implementations of the ContentPartRecords shouldn't have properties that are known keywords to NHibernate. Examples include Identity, Version. diff --git a/Documentation/Documentation-plan.markdown b/Documentation/Documentation-plan.markdown new file mode 100644 index 00000000..e795f47f --- /dev/null +++ b/Documentation/Documentation-plan.markdown @@ -0,0 +1,99 @@ + +* **Getting Started** + * [Installing Orchard](Installing-Orchard) + * [Building your first Orchard site](Getting-Started) + +* **Authoring Web Sites** + * [Getting around the admin panel](Getting-around-the-admin-panel) + * [Adding pages to your site](Adding-pages-to-your-site) + * [Adding a blog to your site](Adding-a-blog-to-your-site) + * [Blogging with LiveWriter](Blogging-with-LiveWriter) + * [Adding and managing media content](Adding-and-managing-media-content) + * [Saving, scheduling and publishing drafts](Saving-scheduling-and-publishing-drafts) + * Using the rich-text editor + * [Navigation and menus](Navigation-and-menus) + * [Organizing content with tags](Organizing-content-with-tags) + * [Creating global-ready applications](Creating-global-ready-applications) + * [Search and indexing](Search-and-indexing) + * [Creating custom content types](Creating-custom-content-types) + +* **Customizing Web Sites** + * [Previewing and applying a theme](Previewing-and-applying-a-theme) + * [Installing themes](Installing-themes) + * Modifying an existing theme + * Adding widgets to your site + * Building a mobile version of a site + +* **Managing Web Sites** + * [Enabling and disabling features](Enabling-and-disabling-features) + * [Using the command-line interface](Using-the-command-line-interface) + * [Installing and upgrading modules](Installing-and-upgrading-modules) + * [Module gallery feeds](Module gallery feeds) + * [Modifying site settings](Modifying-site-settings) + * [Moderating comments](Moderating-comments) + * [Managing users and roles](Managing-users-and-roles) + * Understanding permissions + * Managing version history + * Understanding updates +Application updates, module updates, why do I need to do that? + * Optimizing for search engines (SEO) + * Analyzing the traffic on your site + +* **Hosting and Deploying Web Sites** + * [Deploying Orchard from staging/development to production servers](Deploying-Orchard-from-staging-development-to-production-servers) + * [Configuring Orchard in shared hosting environments](Configuring-Orchard-in-shared-hosting-environments) + * [Deploying Orchard to Windows Azure](Deploying-Orchard-to-Windows-Azure) + * [Setting up a multi-tenant Orchard site](Setting up a multi-tenant Orchard site) + * Deploying with Visual Studio + * Deploying with Web Matrix + +* **Extending Orchard** + * [How Orchard works](How-Orchard-works) + * [Content types, parts, and fields](Content-types-parts-and-fields) + * [Command-line scaffolding](Command-line-scaffolding) + * [Creating a module with a simple text editor](Creating-a-module-with-a-simple-text-editor) + * [Creating a module in Visual Studio](Creating-a-module-in-Visual-Studio) + * [Writing a content part](Writing-a-content-part) + * [Writing a content field](Creating-a-custom-field-type) + * [Packaging and sharing a module](Packaging-and-sharing-a-module) + * [Understanding data access](Understanding-data-access) + * [Understanding content handlers](Understanding-content-handlers) + * [Understanding content drivers](Understanding-content-drivers) + * [Writing data migrations](Writing-data-migrations) + * [Adding admin panel menu items](Adding-admin-panel-menu-items) + * [Adding custom settings](Adding-custom-settings) + * [Adding-custom-permissions](Adding-custom-permissions) + * [Exposing and handling events](Exposing-and-handling-events) + * [Creating content types in code](Creating-content-types-in-code) + * [Writing a command-line handler](Writing-a-command-line-handler) + * [Localizing modules](Localizing-modules) + * Writing a theme + * Packaging and sharing a theme + +* **Developer Tools and Guidelines** + * [Developer FAQ](Developer-FAQ) + * [Setting up a source enlistment](Setting-up-a-source-enlistment) + * [Source code organization](Source-code-organization) + * [Dependencies and libraries](Orchard-dependencies-and-libraries) + * [Code conventions](Code-conventions) + * [Continuous integration](Continuous-integration) + +* **Additional Topics** + * [Working with Orchard in WebMatrix](Working-with-Orchard-in-WebMatrix) + * [Orchard dynamic compilation](Orchard-module-loader-and-dynamic-compilation) + +* **Troubleshooting** + * [Common issues](Common-issues) + * [Filing bugs](Filing-bugs) + +* **Getting Involved** + * [Orchard community resources](Orchard-community-resources) + * [Contributing documentation](Contributing-documentation) +*** [Documentation style guidelines](Documentation-style-guidelines) + * [Contributing modules](Contributing-modules) +*** UI guidelines for module authors + * [Contributing translations](Contributing-translations) + * [Contributing patches](Contributing-patches) + * [Getting involved in forums](Getting-involved-in-forums) + * Contributing themes +*** UI guidelines for theme authors diff --git a/Documentation/Documentation-style-guidelines.markdown b/Documentation/Documentation-style-guidelines.markdown new file mode 100644 index 00000000..0be1bb16 --- /dev/null +++ b/Documentation/Documentation-style-guidelines.markdown @@ -0,0 +1,90 @@ + + +# Structure +Topics should begin with a brief summary explaining what audience it targets and their key takeaways. + +If the topic is not complete enough to fulfill its goals, the top of the document should specify \(\(\(Draft topic\)\)\). + +After the summary, the table of contents should be included using \{TOC\}. + +After the table of contents, the actual contents of the document should all be under section headers, and the top section headers should be in header 1 style: ==This is a top header==. Subsections should be one level deeper than their parent section. + +Do use explicitly named anchors when building links to a specific section of the document. Anchors are created -preferably in a header- using the syntax ==How to build awesome documentation\[anchor|\#how\-to\-build\-awesome\-documentation\]==. To link to an anchor within the document, use the \[\#how\-to\-build\-awesome\-documentation|Follow this link to learn how to build awesome documentation\] syntax. If the anchor is in another document, use the \[name\-of\-the\-linked\-document\#how\-to\-build\-awesome\-documentation|Follow this link to learn how to build awesome documentation\] syntax. + +The text within a section should be structured in short paragraphs. Don't forget to include an empty line in wiki markup between paragraphs. + +# Styles +Topics should use standard [ScrewTurn wiki markup](http://www.screwturn.eu/Help.WikiMarkup.ashx) and should avoid inline HTML styles. + +## Bolding and Italics +Do not use header styles for emphasis. + +Use '''triple quotes''' for bold. Bold is applied to UI elements. + +Use ''double quotes'' for emphasis/italics. Italics is applied to folder/file/path names and to new terms. + +Use \(\(\(triple parentheses\)\)\) to highlight a whole paragraph -- that is, to create an alert paragraph. + +## Code +Inline code should be surrounded by `double curly braces`, and multi-line code samples should be enclosed in double at signs +. + +Try to break code lines so that the code blocks do not have horizontal scroll bars. + +### Escaping Wiki Markup +If you need to use sequences of characters in your text that would normally be parsed as wiki markup, such as `, == or @@ but that you want to appear as they are without being parsed, surround those sequences with {{<nowiki>` and `</nowiki>`. You can look at the source for this document for many examples of this. + +## Images +Images should not be wider than 675 pixels if they are going to be embedded into a topic. Wider images are acceptable as targets of a link from a page. The link to such a wide image should itself be a 675 pixel-wide thumbnail of the image. When including a large image, do it as a 675 pixels wide image linking to the high-resolution version. Images narrower than 675 pixels should be included with their natural width and should not be enlarged. + +It is possible to let ScrewTurn resize images for you. To do that, click edit next to your uploaded image and choose the resize option. You can then enter a width of 675 and ScrewTurn will compute the height that will respect the original aspect ratio of your image. Uncheck "Save as new file" before you save so that the resized image replaces the full-resolution one. + +Images should have a caption. If the document contains more than one image, the captions should include a figure number in the form "Figure 1. This is the caption." + +The typical markup to include an image is \[imageauto|Figure 1\. This is the caption for my image|\{UP\}topic\-name/myImageSmall\.png|topic\-name/myImage\.png\] if it is a link to a higher resolution, and \[imageauto|Figure 1\. This is the caption for my image|\{UP\}topic\-name/myImage\.png\] otherwise. When using that markup, the caption will appear below the image. + +Acceptable image formats are PNG, JPG and GIF. Images should be reasonably compressed. + +## Links +References to other topics on this wiki can be made using \[topic\-name|Text for the link\]. Links to external content can be added using \[http://somesite/somepage|Text of the link\]. + +Do use links to specific sections of a document where relevant (see the [structure section](#structure)) + +## Capitalization +In topic titles and in section headings, use title-style capitalization (as opposed to sentence style). When referring to UI elements, follow the capitalization style used in the UI elements themselves. + +## Tables +Tables should be built to fit into the standard width of pages on this site. The markup to create a table is this:\{| cellspacing="2" cellpadding="2" border="1" +\! Header A \!\! Header B \!\! Header C +|\- +| Cell A\.1 || Cell B\.1 || Cell C\.1 +|\- +| Cell A\.2 || Cell B\.2 || Cell C\.2 +|\- +| Cell A\.3 || Cell B\.3 || Cell C\.3 +|\} + +This markup will create the following table: + + + + + + + + + + + + + + + + + + + + +
Header AHeader BHeader C
Cell A.1Cell B.1Cell C.1
Cell A.2Cell B.2Cell C.2
Cell A.3Cell B.3Cell C.3
+ +The style information in that markup is unfortunate and we'll work at making it unnecessary, but in the meantime it ensures that tables will have visible borders. For details of table syntax see [WikiMarkup Tables Reference](http://www.screwturn.eu/Help.WikiMarkup-Tables.ashx). diff --git a/Documentation/Enabling-and-disabling-features.markdown b/Documentation/Enabling-and-disabling-features.markdown new file mode 100644 index 00000000..7b0c2760 --- /dev/null +++ b/Documentation/Enabling-and-disabling-features.markdown @@ -0,0 +1,39 @@ + +You can add additional functionality to your site by enabling and disabling features exposed by the modules that are installed to Orchard. To view the available features, click **Features** under the **Configuation** heading in the Orchard admin panel. + +![](../Upload/screenshots_675/features_admin_675.png) + +The **Manage Features** screen displays the available features that can be enabled or disabled. Depending on which features are enabled or disabled, your site will have different admin panel options, front-end user interface elements, and other behaviors. The default view of available features displays in "Box" view (to maximize the number of features displayed at a glance). + +You can also switch views to "List" view if you prefer to see your features as a list of items with more verbose descriptions. + +![](../Upload/screenshots_675/features_admin_list_675.png) + +To enable a feature, simply click **Enable** for that feature. + +![](../Upload/screenshots_675/enable_localization.png) + +When a feature is enabled a message appears at the top of the **Manage Features** screen telling you the feature was enabled successfully. + +![](../Upload/screenshots_675/enable_localization2.png) + +A feature can depend on one or more other features (listed under the feature name). When a feature with dependencies is enabled, the dependencies are also automatically enabled. For example, the **Gallery** feature depends on the **Packaging** feature, which in turn depends on **Packaging Services**. + +![](../Upload/screenshots_675/enable_gallery_675.png) + +Enabling **Gallery** will enable **Packaging** and **Packaging Services**. + +![](../Upload/screenshots_675/gallery_enabled_675.png) + +Enabling a feature (such as **Gallery**), will sometimes add additional menu items in the admin panel, as shown in the previous image. + +Orchard also provides a command-line interface, from which you can also list, enable, and disable features. You can find the Orchard command-line tool in the bin directory of the application, and run it from the root of the website by typing `bin\orchard.exe` at the Windows command-prompt. To list available features, type `feature list` or `feature list /Summary:true` at the command-prompt. + +![](../Upload/screenshots_85/features_cmd.png) + +Enable a feature from the command-line by `typing feature enable <feature-name>`, for example: `feature enable Gallery`. + +![](../Upload/screenshots_85/features_cmd2.png) + +For more information about the Orchard command-line interface, see [Using the command-line interface](Using-the-command-line-interface). + diff --git a/Documentation/Exposing-and-handling-events.markdown b/Documentation/Exposing-and-handling-events.markdown new file mode 100644 index 00000000..e69de29b diff --git a/Documentation/Feature-roadmap.markdown b/Documentation/Feature-roadmap.markdown new file mode 100644 index 00000000..13fe5a46 --- /dev/null +++ b/Documentation/Feature-roadmap.markdown @@ -0,0 +1,80 @@ + +In the near term, we'll be focused on servicing the V1 release and planning for the next version. The feature roadmap is subject to change as the project evolves, and we welcome your input. + +We have a discussion open on the 2.0 roadmap here: [Orchard 2.0 roadmap](http://orchard.codeplex.com/discussions/266268). + +### Current Priorities + +* Planning for 2.0 +* Tokens +* Autoroute +* Projector +* Setup improvements +* Gallery improvements +* Commerce + +### Currently Implemented (Partially or in Full) + +* Basic admin panel and login +* CMS page creation and management +* Content zones within pages +* Content - Different content types/metadata, viewers and editors for content +* Content editing and publication (drafts, scheduling, preview) +* Extensibility - Initial content type and composability infrastructure (based on MVC2 areas) +* Media management (basic support for uploading and rendering images in content) +* Users, roles, membership and profile data (Users/Roles/Permissions, Mgmt) +* XML-RPC (Live Writer, MetaWebBlog) support for blogs +* Basic blog (create and manage blogs and posts, RSS/Atom, draft/publish, archives) +* Comments - Associate comments with content types, manage comments, spam protection +* Tags - Associate tags with content types, browse by tag +* Settings - App-level, extension-level settings definition and UI/management +* Themes - Theming model, UI to install/remove themes, preview themes +* Setup +* Simple navigation +* Multi-tenancy +* Azure support +* Command-line tooling +* Event model (a.k.a. plugins) +* App Localization (of admin panel, modules, themes) +* Content Localization (multi-lingual sites) +* Search and Indexing +* Module extensibility API and packaging +* Scaffolding of Modules (cmd-line) +* Creation of arbitrary content types and items - fields, parts +* Define content types, parts, and fields using the admin panel or code +* Add fields to content types using the admin panel or code +* Associate content parts to types using the admin panel or code +* Add fields or parts to existing content types using the admin panel or code +* Command-line support (bin/orchard.exe) +* Enabling features of modules +* Data migrations on module activation/upgrade +* Reporting (event logs) +* Search (based on Lucene) +* Module packaging +* Dynamic compilation of modules +* Theme re-foundation: Razor integration, Page Object Model, naming conventions and helpers +* Script and stylesheet registration +* Theme packaging +* Content item lists +* Medium trust +* Email notifications +* Widgets - Admin UI and management for widgets, widget groups, mapping to zones +* Marketplace - Ability to browse/install extensions from online gallery +* Editor-integrated media picker +* Setup recipes +* Module Recipes +* Import/Export + +### Areas of Focus for Future Iterations (Backlog, Not in Priority Order) + +* Publishing - Workflow/permissions, draft approval, history (restore from) +* Multiple templates for pages +* SEO - Semantic URLs, metas/keywords, Web standards, sitemap +* Navigation - Navigation management, front-end UI (menus, breadcrumbs) +* Admin - UI improvements, dashboard, notifications/email +* Profiles - User profiles, avatars, reputation system +* Themes - Additional themes improvements (in-browser editing, etc) +* Performance - Caching, optimization, script combining/minification +* Analytics - Reporting, site-use statistics +* Mobile - Support for management, moderation, publishing from mobile device +* Other Domain-specific packages - Commerce, Wiki, Forums, Ads, etc diff --git a/Documentation/Filing-bugs.markdown b/Documentation/Filing-bugs.markdown new file mode 100644 index 00000000..e69de29b diff --git a/Documentation/First-steps-into-Orchard.markdown b/Documentation/First-steps-into-Orchard.markdown new file mode 100644 index 00000000..1ce721f7 --- /dev/null +++ b/Documentation/First-steps-into-Orchard.markdown @@ -0,0 +1,80 @@ + + +The goal of this article is to ease you into Orchard. There are so many concepts to understand that I think it is necessary to give a high level view of the whole thing before digging in. So, this article starts with a common ground that any web user should understand and progressively deepens while introducing relevant technical terms. + +When you finish reading this, you should have a good enough understanding to start playing with Orchard (as a designer/developer) without getting confused by its high level architecture and its terminology. When introduced, each new term is put in bold so that you make sure to understand it before moving forward. + +This article also contains a lot of links to other pages with more specific explanation; so you can use it as a starting point. To answer some general questions about what Orchard is and where it comes from, read the [Frequently Asked Questions](frequently-asked-questions). For a more technical presentation, read [How Orchard works](How-Orchard-works). + + +# Looking at Orchard as... +The best way to introduce the basics of Orchard is to look at the roles that a user can have when access it: Normal user (aka reader/visitor/guest), administrator, designer and developer. + +## User +As a **user**, an Orchard website is just like any **website**: It starts with a front page, from which you can access other pages by following links. Depending on what the website is about, the content will vary (can be static pages, blog, wiki, e-commerce, etc.) + +Figure 1. Picture of a website with a tree of linked boxes: front end static page at the top, below: blog box (below: comments box), wiki box, etc. + +## Administrator +The **administrator** has access to a few more aspects of the website: + +1. When [installing Orchard](Installing-Orchard), he will see the Installation page. This step results in the creation of a database where all the content and settings of the website are stored. +Figure 2. Screenshot of the setup page +1. Of course, as a user, he can see the front-end as well +2. He can open the **[dashboard](Getting-Around-the-Admin-Panel)** (aka control panel/back-end) for two reasons: + 1. [Configure the website](Getting-Started): Edit settings around the behavior and look of the website (or install/disable/upgrade them) +Figure 3. Screenshot of the settings page + 1. [Edit the content](Getting-Started) of the website +Figure 4. Screenshot of editing a blog post +1. **[Command line](Using-the-command-line-interface)**: It is possible to script most admin stuff from the command line, making it easy to automate certain operations +Figure 5. Screenshot of Orchard.exe running help command + +## Designer +The **designer** can modify the [look of the website](Previewing-and-applying-a-theme). He can edit the settings of an existing theme (if provided) or create one. +A **[theme](Anatomy-of-a-theme)** is everything that plays in the visual representation of the website. It is sometimes called skin or template. It transforms the **content** (user-generated data) into HTML that can be displayed in a browser. Eg: When you write a blog post, the theme defines where and how to show the menu, title, body, comments, etc. + +Depending on how much customization is required, the designer may [edit some or all elements of the theme](Customizing-the-default-theme). These elements are of the following types: + +* Documents defining the **layout** and its zones: This is the overall representation of a page on the website (without any actual content). Eg: It says if the website should have one, two or three columns. So, a **zone** is a container that is part of the layout and ready to receive any content. Note that a flexible theme (like the one provided by Orchard) can adapt to hide empty zones. So, although Figure 6 shows a lot of zones, most of them will not be visible on actual pages because they aren't being used. +Figure 6. Diagram of a theme with zones as boxes (Cf. The Theme Machine) +* **Views**: Visual representation of a specific content. A view is typically a file with the extension .CSHTML or .ASPX. It provides the HTML code to use when displaying a specific type of content. So, a page with many contents (menu, blog post, comments, etc) will be created by using the composition of all the relevant individual views. +Figure 7. Screenshot of a page with each content view highlighted +* **Stylesheets**, **Javascript** and Media files: They are used to modify the look defined in the views. They are files like "Site.css", jQuery or the images for background, borders and icons +* **[Widget](Managing-widgets)**: A web page typically presents one main content (like a blog post), but it often also has small pieces of information on the sides. Eg: a tag cloud, a list of recent posts, a twitter feed, etc +* Layers and the binding between content to specific zones: A **layer** is like the description of a group of pages. Once defined, you can tell where to put each content (or widget). Eg: A layer grouping all the blog posts can be defined, then we can make a Tag cloud widget appear on the side +Figure 8. Diagram of a theme with its zones filled by various content + +More advanced themes may also include some programming code to further customize the look. + +## Developer +The **developer** has a complete insight of the architecture of Orchard and can extend it. +Orchard is organized in modules. Each **module** provides a building block (aka add on/plugin) to the website with a high level distinct goal. For example, you can have: + +* **Extension** module: Adds some (low-level) **features** that will benefit the website. Eg: Ability to [search your content](Search-and-indexing) or to [use an external editor to write blog posts (like Live Writer)](Blogging-with-LiveWriter) +* Content module: Adds everything (code and visual) required to view/edit some type of content (like blog posts) +* Widget module: Adds a small visual content that can be displayed on the side of existing content modules (like a Tag cloud next to a blog) +* Theme module: Changes the look of existing content modules (This is what the designer would typically create) +* All the above: A module can have many extensions, content types, widgets and themes all in one package + +Orchard is designed to be highly extensible; this means that almost anything that you interact with can be extended, replaced or disabled. +Out of the box, Orchard comes with a number of modules to provide a good user/administrator experience; but a designer/developer can change them or [create more](Building-a-hello-world-module). It is also possible to [share your modules](Packaging-and-sharing-a-module) with the Orchard community and to [install modules](Installing-and-upgrading-modules) developed by others. + +Orchard v0.8 comes with only one theme (called "[The Theme Machine](Anatomy-of-a-theme)"). However, it has enough zones to allow various arrangements. This is important because, by default, a site can only have one theme (unless you develop a module allowing more), so the theme must be flexible enough to allow pages to have different layouts. If you are not satisfied, you can copy it and add more zones. + +[The Orchard Gallery](Gallery-overview) contains a lot more themes and modules ready to install. Make sure to browse it to find out what extra features are available. + +# Content +In order to fill your website, Orchard allows you to edit and display content. It comes with the ability to create pages and blog posts out of the box. But it also allows you to define your own content. This is important because you may want to have events or profiles or anything else that isn't supported out of the box. This section explains the various elements that plays into providing that capability. + +* Content: Data that is typically displayed on the front-end website. I use this term as a generic way of calling anything that is user-generated. +* [Content Type & Item](Creating-custom-content-types): A **content type** is like a dynamic class; it defines a structure of data for a specific type of content. That structure can be changed, even by the administrator. A **content item** is an instance of content type. So, BlogPost can be a content type, and when you write one, that one is a content item. +* **[Content Part](Writing-a-content-part)**: Because many content types share many aspects; these aspects can be created independently and reused in each content type. That's what a content part is. Eg: A blog post can have comments; a photo can also have comments; so, instead of implementing the "comments" feature twice, we can create it as a content part and reuse it for both content types. +* **[Content Field](Creating-a-custom-field-type)**: In the same spirit of reusability, we can have smaller types that must behave in a certain way. Eg: Most content types will need Date, phone number, email address, etc. They aren't simple properties since we can attach some behavior (like validation rules) but they aren't content parts either (too "small"). +* **Record**: In order to be able to save a content type/part (in a SQL database), it needs to be "linked" to a record. It is a class with all the properties that should be saved. Eg: A Map part must save its coordinates (Latitude & Longitude), so it will be linked to a record with these two properties; and Orchard will do the rest to load/save it. You will not have to deal with records unless you [develop your own module](Building-a-hello-world-module). But it is useful to understand this concept in case you encounter it. + +Note that a content type can only have one of each kind of content parts. But it can have many fields of the same kind. The reason is in the semantic meaning of these concepts. For example, a blog post can only have one commenting aspect and it can have many dates (creation date, last update date, etc.). + +Since Orchard is an [open source project](frequently-asked-questions), feel free to [contribute](Contributing-patches) any feature/module you would like. + +# Conclusion +We are going to stop here. At this point, you should have a good understanding of what is Orchard. Any article talking about [how to use it](MainPage) should be easier to understand. The next step is to get into a bit more details about modules, themes and the [low-level architecture of Orchard](How-Orchard-works). This would be useful when you start learning [how to extend Orchard](Building-a-hello-world-module). diff --git a/Documentation/Frequently-asked-questions.markdown b/Documentation/Frequently-asked-questions.markdown new file mode 100644 index 00000000..21bad79e --- /dev/null +++ b/Documentation/Frequently-asked-questions.markdown @@ -0,0 +1,35 @@ + + +### What is Orchard? +Orchard is a free, open source, community-focused project aimed at delivering applications and reusable components on the ASP.NET platform. It will create shared components for building ASP.NET applications and extensions, and specific applications that leverage these components to meet the needs of end-users, scripters, and developers. Additionally, it will provide help for existing .NET applications to be successful in achieving their goals. Orchard is currently licensed under a New BSD license, which is approved by the OSI. The intended output of the Orchard project is three-fold: + +* Individual .NET-based applications that appeal to end-users, scripters, and developers +* A set of re-usable components that makes it easy to build such applications +* Partnerships with the .NET community to help define these applications and extensions + +In the near term, the Orchard project is focused on delivering a .NET-based CMS application that will allow users to rapidly create content-driven Websites, and an underlying framework that will allow developers and customizers to provide additional functionality through extensions and themes. + +### What is the Orchard CMS application? How does it compare with Microsoft SharePoint? +Orchard CMS is an open source project which aims to provide a simple solution for small web agencies who want to quickly create Internet-facing Web sites. For corporations wanting a fully-featured, Microsoft-supported, enterprise-level CMS solution out-of-the-box, including Workflow, Digital Asset Management, Advanced Search, Web Analytics, and Social Networking, Microsoft SharePoint™ is a more natural choice. SharePoint also provides capabilities beyond CMS including Team Collaboration, Document and Records Management, Business Process Integration and Business Intelligence. + +Microsoft SharePoint is the Business Collaboration Platform for the Enterprise and the Web. SharePoint today runs many large Internet-facing websites that require the robust CMS, Search, Workflow and Analytics capabilities that SharePoint provides. Examples include Kraft, Viacom, Hawaiian Airlines, US Government, and United States Marine Corp. + +### What is Microsoft's involvement in Orchard? Is Orchard a Microsoft-supported project? +Orchard is a community-focused open source project delivered through the Outercurve Foundation. Like any open source project, we intend to expand the project through community contributions and enlist new members from many different organizations. Although Microsoft is sponsoring this project by providing full-time development resources to the effort, the Orchard CMS is not officially supported through Microsoft. Orchard is supported primarily by the project team through community forums and email. If you are looking for a Microsoft-supported CMS product, Microsoft SharePoint is a better choice. + +### What is the status of the Orchard project? What is available to use today? +The Orchard project shipped a version 1 release in January 2011, published on our Orchard CodePlex website and Microsoft Web Application Gallery, and installable by the Web Platform Installer. This is a production-ready release for powering live sites, and is the result of over a year of development effort and contribution from the Orchard Team and our active community. Orchard V1 also includes a flexible extensibility model to customize the behavior of Orchard using modules and themes, and a gallery website (and related open source project) for uploading and sharing your custom extensions with others. The focus of the project team is currently is on supporting users of V1 and planning for the next release. We invite community participation and feedback, so that we can publicly validate our designs and development approach as the project evolves. + +### Who is the audience for the Orchard effort? Are you focused on developers, users, or both? +Orchard seeks to appeal to a variety of audiences, from end-users who want to quickly build a site using only an application's interface, to designers, scripters and developers who want to extend the application though markup or code customizations in the form of themes or modules. It also aims to appeal to Web development and consulting shops who build and customize sites for small-to-medium sized businesses, starting with an open source CMS. At this early stage of the project, we are primarily engaging with a .NET developer audience, as Orchard is firmly rooted in ASP.NET MVC and other .NET Framework technologies. + +### Will Orchard applications run well in shared hosting environments? +Orchard is tailored for today's shared hosting environments, where users potentially have less control over what software is running on the server. As an open source solution, Orchard will retain the flexibility to run on a number of different technologies, making it suitable for a wide range of hosters running different platforms or database servers. In dedicated hosting environments where it is possible to run the entire Windows, .NET + IIS + SQL Server stack, SharePoint offers an optimized solution that takes advantage of the unique strengths of this combined platform. + +### How does Orchard compare with DotNetNuke®? What is Microsoft's relationship with existing partners? +DNN is a mature and successful .NET-based project, a key partner for Microsoft, and a vital contributor to the .NET open source ecosystem. Our hope is that new technology investments made by Orchard will serve existing applications like DNN in the long run, and ultimately provide infrastructure and components that our partners can leverage to enrich their own offerings. + +Orchard aims to help our .NET partners, not to compete directly with them. Orchard is already working with several partners in the .NET open source space, including DNN, to identify opportunities to work together for mutual benefit. In addition to providing shared infrastructure that can be leveraged within existing apps, we will continually seek opportunities for the Orchard team to contribute to existing projects and help our partners be successful in achieving their own goals. Orchard's extensibility model also presents partners with another vehicle for delivering their solutions and expanding their audience. + +### What about Oxite? Aren't they building a CMS application too? How does Oxite relate to the Orchard effort? +Oxite started out as a blogging engine to support the Mix '09 conference website, and has since evolved into a mature open source project in its own right. Oxite recently began introducing general extensibility support (modules, plug-ins) and some lightweight CMS content-editing features, and Orchard began partnering with them to share scenarios and code. Ultimately we concluded our efforts were better served by working together, and two of the principal developers on Oxite, Erik Porter and Nathan Heskew, have officially joined the Orchard team. Together we will take the lessons learned from early Orchard prototyping and Oxite development, borrowing code where appropriate from those efforts, to deliver a fundamentally new architecture that is the Orchard CMS. We have deliberately chosen to start development anew, with the guidance and contribution from the community, rather than build on the existing code, in order to involve the community up-front as well as create a sustainable architecture that can meet the ambitious Orchard project goals. diff --git a/Documentation/Fundamentals-doctype.markdown b/Documentation/Fundamentals-doctype.markdown new file mode 100644 index 00000000..5f10f417 --- /dev/null +++ b/Documentation/Fundamentals-doctype.markdown @@ -0,0 +1,26 @@ +The choice of a doctype is such a choice that we have to make for our own default themes. +This page presents the main points and results of our debate about the choice of a doctype. + +* Theme authors will ultimately be free to pick any DTD/doctype they want, this only describes the default ones and the ones that we'll build. +* Cross-browser compatibility is a must. +* HTML 5 is the future-proof choice. +* XHTML is important to many. +* IE6 support is hopefully on its way out but is probably still necessary for the front-end. +* For the back-end (the admin interface), we have decided to drop IE6 support. +* IE has never really supported XHTML at all but merely tolerated it (it just renders it because XHTML is constrained HTML with some extra stuff that is getting ignored). +* XHTML specs recommend serving XHTML with the right MIME type and discourage using several features such as custom namespaces unless that is the case. Unfortunately, that fails in IE. +* HTML 5 does have an XHTML 5 flavor, but it has been considerably scaled down and is now little more than a serialization format. +* The XHTML team at W3C is getting dissolved. +* No existing browser supports all of HTML5 yet. +* The part of HTML5 markup that is not new will just work on past, present and future browsers. +* HTML5 and past, present and future browsers are resilient to XHTML syntax such as self-closing tags. It will validate against HTML5. +* In reality, browsers ignore the doctype, they have only two modes: quirks and standard (except IE8, which also has IE7 mode, off topic here), pretty much determined by the presence of a doctype, not by its value. +* We are going to operate in standard mode no matter what our choice of doctype is. +* We should use the subset of HTML 5 that will work in today's browsers. +* We should use markup that is XHTML-compatible (self-closing tags, etc.) even if we don't use a true XHTML doctype. +* We should make sure our markup validates on the W3C validators. + +In summary, we're recommending the use of the HTML 5 doctype, using the subset of HTML 5 that is compatible with today's browsers and using the XHTML-compatible style. + +## References +1. [The future of XHTML explained as a comic book](http://media1.smashingmagazine.com/wp-content/uploads/images/xhtml2-html5/comic-960px.jpg) diff --git a/Documentation/Gallery-overview.markdown b/Documentation/Gallery-overview.markdown new file mode 100644 index 00000000..efb4d1cd --- /dev/null +++ b/Documentation/Gallery-overview.markdown @@ -0,0 +1,25 @@ + +Orchard is a modular web-based CMS that's designed to be extended by installing additional module packages and by enabling features contained in those modules. A module package consists of a ZIP file in the [.nupkg](http://nuget.codeplex.com) format. In Orchard, a theme is also a module. To facilitate sharing for modules and themes, Orchard lets you search for modules and themes online and install them directly to your site. + +## Browsing the Gallery Web Site +To find available modules and themes and download them to your computer, you can browse the [Orchard Gallery](http://orchardproject.net/gallery) website. For more information, see [Browsing the Gallery Website](Browsing-the-gallery-web-site). + +## Installing Modules and Themes from the Gallery +You can also access the Gallery from within your Orchard site in order to download or install modules and themes. To do so, click **Themes** or **Modules** on the dashboard and then click the **Gallery** tab. + +> **Note:** The **Gallery** feature is enabled by default. For more information about working with the **Gallery** feature, including how to enable or disable it, see [Installing Modules and Themes from the Gallery](Installing-modules-and-themes-from-the-gallery). + +## Contributing a Module or Theme to the Gallery +If you are a developer who writes modules or themes for Orchard, you are probably interested in sharing your module with others in the gallery. For information about how to do this, see [Contributing a Module or Theme to the Gallery](Contributing-a-module-or-theme-to-the-gallery). + +## Registering Additional Gallery Feeds +The Orchard Gallery is just one gallery that you can browse. By default, a single feed is exposed from [http://orchardproject.net/gallery/server/FeedService.svc](http://orchardproject.net/gallery/server/FeedService.svc/Packages). Orchard allows you to register additional feeds for other galleries. To register a feed, expand the dashboard **Settings** section and then click **Gallery**. On the **Gallery Feeds** page you can add new feeds or delete existing ones. For more information, see [Registering Additional Gallery Feeds](Module gallery feeds). + +If you want to set up your own gallery, a reference implementation for exposing a gallery feed and website is available on [OrchardGallery.CodePlex.com](http://orchardgallery.codeplex.com) and [GalleryServer.CodePlex.com](http://galleryserver.codeplex.com). + + + + +# Change History +* Updates for Orchard 1.1 + * 3-22-11: Updated dashboard and UI references in the text. diff --git a/Documentation/Getting-Started.markdown b/Documentation/Getting-Started.markdown new file mode 100644 index 00000000..3ada034f --- /dev/null +++ b/Documentation/Getting-Started.markdown @@ -0,0 +1,159 @@ + +This walkthrough provides a glimpse of the features that Orchard has to offer, provided as a step-by-step guide. If this is your first time using Orchard, this document is for you! + +This topic assumes that you have already installed Orchard and set up your website. If you haven't, follow the instructions in [Installing Orchard](Installing-Orchard). + + +### Customizing the Orchard Home Page + +When you're logged in as an administrator, on the home page you'll notice the various zones that can contain content. By holding the mouse pointer over any of these zones and clicking the **Edit** link (at the top right), you can edit the content of the zone. + +![](../Upload/screenshots_675/home_page_675.png) + +Click the **Edit** link for the main zone of the home page. Orchard displays the **Edit Page** screen, which provides a rich-text editor for customizing contents. + +![](../Upload/screenshots/edit_page_2.png) + +Edit the page title, add some content for the site, and then click **Publish Now** at the bottom of the page. The home page is redisplayed. + +Now you can add content to the zones at the bottom of the page. For purposes of this walkthrough, you'll add an image to each of the zones. + +Click **Edit** for the zone named "First Leader Aside". The **Edit Widget** screen is displayed. + +Change the title, and optionally, change or remove the existing body text for the zone. Then click the **Insert/Update Media** button. + +![](../Upload/screenshots_675/edit_widget_media_1_675.png) + +The **Pick Image** dialog box is displayed. Browse to an image file on your computer and click **Upload** to upload it to your Orchard site. + +![](../Upload/screenshots/pick_image.png) + +After uploading the image, click **Insert** to insert it into the zone. + +> **Note:** Before you insert the uploaded image, it is helpful to specify width and height attributes for the image, for example 200 pixels wide by 150 pixels high, so that the image fits correctly into its zone. + +Click **Save** to save the changes to the widget. The home page is displayed with the updated zone. + +![](../Upload/screenshots_675/edit_widget_tulip_675.png) + +Now edit each of the other "Aside" zones. Repeat the process of adding an image to each zone, so that all three zones on the bottom of the home page have an image. + +After you have added an image to each "Aside" zone, inserted a title for each zone, and removed the body text from the zone, the updated home page looks like the following example: + +![](../Upload/screenshots_675/playground_1_675.png) + +### Adding a New Page to Your Site + +Next, you'll add a new page to the site. Click the **Dashboard** link at the bottom of the home page. + +![](../Upload/screenshots/dashboard_link.png) + +In the Orchard dashboard, under **New**, click **Page**. The **Create Page** screen is displayed. + +![](../Upload/screenshots_675/create_new_page_0_1_675.png) + +Fill in details for the new page. When you enter a title for the page (for example, "Download"), the permalink (URL) for the page is filled in automatically ("download"). You can edit this link if you prefer a different URL. + +![](../Upload/screenshots_675/create_new_page_1_1_675.png) + +Add some content to the page body and then fill in some of the other options, such as tags and comments. In the **Tags** field, add comma-separated tags such as "download" and "Orchard" so that you can search and filter using those tags later. If you select the **Show on main menu** check box, you can enter the menu text to use in the site's main menu. + +![](../Upload/screenshots_675/create_new_page_2_1_675.png) + +When you've finished customizing the new page, click **Publish Now** to publish it. You can also save the page as a draft (to edit later before publishing), or you can choose to publish the page at a specific date and time. + +Now click the **Your Site** link in the upper-left side of the dashboard. This returns you to your home page so that you can view the changes to your site. + +![](../Upload/screenshots/your_site_1.png) + +Notice that the **Downloads** tab has been added to the main menu, and that you can click it to view your page. Also notice that the new page has a slightly different layout from the home page. Orchard provides the ability for pages to have different layouts. Some of the built-in themes use this feature to differentiate the home page and subpages. + +![](../Upload/screenshots_675/playground_new_page_1_675.png) + +### Adding a Blog to Your Site + +Now you'll add a blog to the site. Return to the Orchard dashboard and click **Blog**. Orchard displays the **Create New Blog** screen. + +![](../Upload/screenshots_675/blog_create_1_675.png) + +Add a title, description, and menu text for the blog and click **Save**. A page for managing the blog is displayed. + +![](../Upload/screenshots_675/blog_new_post_1_1_675.png) + +Click **New Post** to create a new blog entry. The **Create New Blog Post** screen is displayed. + +![](../Upload/screenshots_675/blog_new_post_2_1_675.png) + +Creating a blog post is nearly the same as creating a page. Add some details for your post, such as a title, permalink, and body content. Also add some tags (separated by commas) to your blog post in the **Tags** field. Notice that the check box next to **Allow new comments** is checked by default. When you're done editing the post, click **Save** to save it as a draft. + +In the dashboard, click **Manage Blog** to view the list of posts in your blog. + +![](../Upload/screenshots_675/blog_manage_1_675.png) + +In the list of posts, you can see that the post is saved as a draft, which means it is not yet visible to visitors of your site. Click **Publish** to allow site visitors to see the post. + +A screen shows that the post was published successfully. + +![](../Upload/screenshots_675/publish_draft_post_675.png) + +Click **Your Site** to view the site's home page again. + +Click the **Our Blog** tab on the home page. This time, you can see a blog has been added to your menu and that the blog shows the post that you published. + +![](../Upload/screenshots_675/playground_blog_1_675.png) + +### Using Comments and Tags + +To see more details about the post, click the **more** link. Because you enabled comments for the post, you can enter a comment. + +![](../Upload/screenshots_675/blog_comment_1_675.png) + +Orchard provides settings for moderating comments as well. Return to the Orchard dashboard and under **Settings**, click **Comments**. You see an option to require comments to be approved by an administrator before they appear, and another option for enabling spam protection. For more details about these features, see the [Moderating Comments](Moderating-comments) topic. + +![](../Upload/screenshots_675/manage_settings_comments_1_675.png) + +Orchard provides the ability to browse content by the tags that you define when you create content. Click one of the tags (for example, click "Orchard") to see a list of all content that has that tag. For more information about managing tags, see [Organizing Content with Tags](Organizing-content-with-tags). + +![](../Upload/screenshots_675/tagged_contents_1_675.png) + +Notice the URL for browsing tagged content as well. + +![](../Upload/screenshots/tags2.png) + +> **Note:** If you reduce the URL to just the _/Tags/_ portion, you can see a list of available tags in your site. + +### Selecting a Theme + +You probably want to customize the look and feel of your site. On the Orchard dashboard, click **Themes**. The **Themes** screen is displayed. You can also install new themes. To do that, go to the **Gallery** tab, install an additional theme, and then return to the **Installed** tab. After a theme has been installed it appears as an option in the **Available** section on the **Installed** tab. In the following illustration, the **Contoso** theme has been installed so it appears in the **Available** section. (The current theme for the site is **The Theme Machine**.) + +![](../Upload/screenshots_675/themes_manage_1_675.png) + +Orchard makes it easy to preview installed themes. Try previewing an available theme, and then click **Set Current** to apply the theme to your site. For more details, see [Previewing and Applying a Theme](Previewing-and-applying-a-theme) and [Installing Themes](Installing-themes). + +### Extending Orchard with Modules and Features + +A key feature of Orchard is the ability to add new features in order to extend the functionality of your site. The primary way to do this is by installing modules. You can think of a module as a package of files (in a .zip folder) that can be installed on your site. To view the modules that are included with Orchard, in the Orchard dashboard, click **Modules** and then click the **Installed** tab in the **Modules** screen. + +![](../Upload/screenshots_675/installed_modules_1_675.png) + +Orchard provides some built-in modules, and you can install new modules. For details, see [Installing and Upgrading Modules](Installing-and-upgrading-modules) and [Registering additional gallery feeds](Module gallery feeds). + +Individual modules can expose features that can be independently enabled or disabled. To view the features exposed by the built-in modules in Orchard, click the **Features** tab in the **Modules** screen. + +![](../Upload/screenshots_675/features_link_675.png) + +Each feature has an **Enable** or **Disable** link (depending on its current state), as well as an optional list of dependencies that must also be enabled for a specific feature. The documentation throughout this site describes the variety of features in Orchard and how you can use them to customize your site's user interface and behavior. + +Try enabling a feature such as remote blog publishing. This feature lets the blog author create posts using a client application like [Windows Live Writer](http://explore.live.com/windows-live-writer). For more information about how to use this features, check out the [Blogging with LiveWriter](Blogging-with-LiveWriter) topic. + +![](../Upload/screenshots_675/enable_remoteblog_675.png) + +This concludes the Getting Started tutorial for Orchard. We hope we've captured your imagination and you've started thinking of ways to build your next awesome site. + + + + + +### Change History +* Updates for Orchard 1.1 + * 3-14-11: Updated screen shots showing updated menus, and updated dashboard and settings options. diff --git a/Documentation/Getting-around-the-dashboard.markdown b/Documentation/Getting-around-the-dashboard.markdown new file mode 100644 index 00000000..299f0054 --- /dev/null +++ b/Documentation/Getting-around-the-dashboard.markdown @@ -0,0 +1,31 @@ + +The Orchard dashboard lets you manage your website, change its appearance, add content, and enable and disable Orchard features. When you are logged into your website, you can access the dashboard by clicking the **Dashboard** link at the bottom of your default home page. + +When you open the dashboard, you see a list of application features and settings on the left side of the page. This list is divided into sections of related features. Each expandable section can be collapsed to show only the section title. If you click a section title, the first feature in that section is selected. This list changes as you enable and disable Orchard features. For example, the **Blog** section will have a set of additional collapsible items under it (as shown) after you actually create a blog. The **New** section allows you to create new instances of default content types as well as any custom content types that you define. The right side of the page displays the settings that are available for the selected feature. The following image shows the contents of the dashboard. + +![](../Upload/screenshots_675/dashboard_1_675.png) + +# Feature Settings Available in the Dashboard + +The following table shows each of the dashboard sections and briefly describes the available settings. + +Section Title | Description +------------- | ----------- +Dashboard | Contains the dashboard and displays the main ("Welcome to Orchard") page. This page contains a number of helpful links for working with Orchard. The page also shows the Orchard version that is running, and displays advisories from [http://orchardproject.net](http://orchardproject.net) (when advisories are available) that can notify you when a new version is available or when an important update needs to be applied. +New | Lets you create new instances of default content types or of custom content types that you define in the **Content => Content Types** screen. For more information, see [Creating Custom Content Types](Creating-custom-content-types). +Blog | Lets you add a blog to your website, create new blog posts, and manage your blog. For more information, see [Adding a Blog to Your Site](Adding-a-Blog-to-Your-Site). +Content | Lets you add new pages, edit or remove existing pages, and publish pages. This is also where you can create and manage your own content types if you have enabled that feature. For more information, see [Adding Pages to Your Site](Adding-pages-to-your-site) and [Content Types](content-types). +Comments | If your website is configured to allow users to post comments, lets you manage the posted comments. For more information, see [Moderating Comments](Moderating-comments). +Widgets | Lets you manage the widgets that appear on the pages of your site. For more information, see [Managing widgets](Managing-widgets). +Media | Lets you add or remove folders that contain media. For more information, see [Adding and Managing Media Content](Adding-and-Managing-Media-Content). +Navigation | Lets you add or remove items in the main menu and define additional navigation menus. For more information, see [Navigation and Menus](Navigation-and-Menus). +Tags | Lets you add or remove content tags for your site. For more information, see [Organizing Content with Tags](Organizing-content-with-tags). +Modules | Lets you download, install, and manage modules and features on your site. For more information, see [Installing Modules and Themes from the Gallery](Installing-modules-and-themes-from-the-gallery), [Enabling and Disabling Features](Enabling-and-Disabling-Features), and [Installing and Upgrading Modules](Installing-and-Upgrading-Modules). +Themes | Lets you install new themes and apply themes to your site. For more information, see [Installing Themes](Installing-Themes) and [Previewing and Applying a Theme](Previewing-and-Applying-a-Theme). +Users | Lets you manage users and roles for your site. For more information, see [Managing Users and Roles](Managing-Users-and-Roles). +Reports | Lets you manage and view reports that Orchard generates for your site. +Settings | Lets you configure a variety of site settings such as the site name and culture, the default number of items per page, URLs for Gallery feeds, whether user-added comments must be approved, media file types that can be uploaded, and user registration settings. For more information see [Modifying Site Settings](Modifying-Site-Settings). + +### Change History +* Updated for Orchard 1.1 + * 3-15-11: Updated screen shot and table to show 1.1 version of the dashboard. diff --git a/Documentation/Getting-involved-in-forums.markdown b/Documentation/Getting-involved-in-forums.markdown new file mode 100644 index 00000000..e69de29b diff --git a/Documentation/How-Orchard-works.markdown b/Documentation/How-Orchard-works.markdown new file mode 100644 index 00000000..5dedceba --- /dev/null +++ b/Documentation/How-Orchard-works.markdown @@ -0,0 +1,256 @@ + +Building a Web CMS (Content Management System) is unlike building a regular web application: it is more like building an application container. When designing such a system, it is necessary to build extensibility as a first-class feature. This can be a challenge as the very open type of architecture that's necessary to allow for great extensibility may compromise the usability of the application: everything in the system needs to be composable with unknown future modules, including at the user interface level. Orchestrating all those little parts that don't know about each other into a coherent whole is what Orchard is all about. + +This document explains the architectural choices we made in Orchard and how they are solving that particular problem of getting both flexibility and a good user experience. + + +# Architecture + + + + + + + + + +
Modules +
Core +
Orchard Framework +
ASP.NET MVC +NHibernate +Autofac +Castle +
.NET +ASP.NET +
IIS or Windows Azure +
+ +# Orchard Foundations + +The Orchard CMS is built on existing frameworks and libraries. Here are a few of the most fundamental ones: +* [ASP.NET MVC](http://www.asp.net/mvc): ASP.NET MVC is a modern Web development framework that encourages separation of concerns. +* [NHibernate](http://nhforge.org/): NHibernate is an object-relational mapping tool. It handles the persistence of the Orchard content items to the database and considerably simplifies the data model by removing altogether the concern of persistence from module development. You can see examples of that by looking at the source code of any core content type, for example Pages. +* [Autofac](http://code.google.com/p/autofac/): Autofac is an [IoC container](http://en.wikipedia.org/wiki/Inversion_of_control). Orchard makes heavy use of dependency injection. Creating an injectable Orchard dependency is as simple as writing a class that implements IDependency or a more specialized interface that itself derives from IDependency (a marker interface), and consuming the dependency is as simple as taking a constructor parameter of the right type. The scope and lifetime of the injected dependency will be managed by the Orchard framework. You can see examples of that by looking at the source code for IAuthorizationService, RolesBasedAuthorizationService and XmlRpcHandler. +* [Castle Dynamic Proxy](http://www.castleproject.org/dynamicproxy/index.html): we use Castle for dynamic proxy generation. + +The Orchard application and framework are built on top of these foundational frameworks as additional layers of abstraction. They are in many ways implementation details and no knowledge of NHibernate, Castle, or Autofac should be required to work with Orchard. + +# Orchard Framework + +The Orchard framework is the deepest layer of Orchard. It contains the engine of the application or at least the parts that couldn't be isolated into modules. Those are typically things that even the most fundamental modules will have to rely on. You can think of it as the base class library for Orchard. + +## Booting Up Orchard + +When an Orchard web application spins up, an Orchard Host gets created. A host is a singleton at the app domain level. + +Next, the host will get the Shell for the current tenant using the ShellContextFactory. Tenants are instances of the application that are isolated as far as users can tell but that are running within the same appdomain, improving the site density. The shell is a singleton at the tenant level and could actually be said to represent the tenant. It's the object that will effectively provide the tenant-level isolation while keeping the module programming model agnostic about multi-tenancy. + +The shell, once created, will get the list of available extensions from the ExtensionManager. Extensions are modules and themes. The default implementation is scanning the modules and themes directories for extensions. + +At the same time, the shell will get the list of settings for the tenant from the ShellSettingsManager. The default implementation gets the settings from the appropriate subfolder of App_data but alternative implementations can get those from different places. For example, we have an Azure implementation that is using blob storage instead because App_data is not reliably writable in that environment. + +The shell then gets the CompositionStrategy object and uses it to prepare the IoC container from the list of available extensions for the current host and from the settings for the current tenant. The result of this is not an IoC container for the shell, it is a ShellBlueprint, which is a list of dependency, controller and record blueprints. + +The list of ShellSettings (that are per tenant) and the ShellBluePrint are then thrown into ShellContainerFactory.CreateContainer to get an ILifetimeScope, which is basically enabling the IoC container to be scoped at the tenant level so that modules can get injected dependencies that are scoped for the current tenant without having to do anything specific. + +## Dependency Injection + +The standard way of creating injectable dependencies in Orchard is to create an interface that derives from IDependency or one of its derived interfaces and then to implement that interface. On the consuming side, you can take a parameter of the interface type in your constructor. The application framework will discover all dependencies and will take care of instantiating and injecting instances as needed. + +There are three different possible scopes for dependencies, and choosing one is done by deriving from the right interface: +* Request: a dependency instance is created for each new HTTP request and is destroyed once the request has been processed. Use this by deriving your interface from IDependency. The object should be reasonably cheap to create. +* Object: a new instance is created every single time an object takes a dependency on the interface. Instances are never shared. Use this by deriving from ITransientDependency. The objects must be extremely cheap to create. +* Shell: only one instance is created per shell/tenant. Use this by deriving from ISingletonDependency. Only use this for objects that must maintain a common state for the lifetime of the shell. + +### Replacing Existing Dependencies + +It is possible to replace existing dependencies by decorating your class with the OrchardSuppressDependency attribute, that takes the fully-qualified type name to replace as an argument. + +### Ordering Dependencies + +Some dependencies are not unique but rather are parts of a list. For example, handlers are all active at the same time. In some cases you will want to modify the order in which such dependencies get consumed. This can be done by modifying the manifest for the module, using the Priority property of the feature. Here is an example of this: + + + Features: + Orchard.Widgets.PageLayerHinting: + Name: Page Layer Hinting + Description: ... + Dependencies: Orchard.Widgets + Category: Widget + Priority: -1 + + + +## ASP.NET MVC + +Orchard is built on ASP.NET MVC but in order to add things like theming and tenant isolation, it needs to introduce an additional layer of indirection that will present on the ASP.NET MVC side the concepts that it expects and that will on the Orchard side split things on the level of Orchard concepts. + +For example, when a specific view is requested, our LayoutAwareViewEngine kicks in. Strictly speaking, it's not a new view engine as it is not concerned with actual rendering, but it contains the logic to find the right view depending on the current theme and then it delegates the rendering work to actual view engines. + +Similarly, we have route providers, model binders and controller factories whose work is to act as a single entry point for ASP.NET MVC and to dispatch the calls to the properly scoped objects underneath. + +In the case of routes, we can have n providers of routes (typically coming from modules) and one route publisher that will be what talks to ASP.NET MVC. The same thing goes for model binders and controller factories. + +## Content Type System + +Contents in Orchard are managed under an actual type system that is in some ways richer and more dynamic than the underlying .NET type system, in order to provide the flexibility that is necessary in a Web CMS: types must be composed on the fly at runtime and reflect the concerns of content management. + +### Types, Parts, and Fields + +Orchard can handle arbitrary content types, including some that are dynamically created by the site administrator in a code-free manner. Those content types are aggregations of content parts that each deal with a particular concern. The reason for that is that many concerns span more than one content type. + +For example, a blog post, a product and a video clip might all have a routable address, comments and tags. For that reason, the routable address, comments and tags are each treated in Orchard as a separate content part. This way, the comment management module can be developed only once and apply to arbitrary content types, including those that the author of the commenting module did not know about. + +Parts themselves can have properties and content fields. Content fields are also reusable in the same way that parts are: a specific field type will be typically used by several part and content types. The difference between parts and fields resides in the scale at which they operate and in their semantics. + +Fields are a finer grain than parts. For example, a field type might describe a phone number or a coordinate, whereas a part would typically describe a whole concern such as commenting or tagging. + +But the important difference here is semantics: you want to write a part if it implements an "is a" relationship, and you would write a field if it implements a "has a" relationship. + +For example, a shirt **is a** product and it **has a** SKU and a price. You wouldn't say that a shirt has a product or that a shirt is a price or a SKU. + +From that you know that the Shirt content type will be made of a Product part, and that the Product part will be made from a Money field named "price" and a String field named SKU. + +Another difference is that you have only one part of a given type per content type, which makes sense in light of the "is a" relationship, whereas a part can have any number of fields of a given type. Another way of saying that is that fields on a part are a dictionary of strings to values of the field's type, whereas the content type is a list of part types (without names). + +This gives another way of choosing between part and field: if you think people would want more than one instance of your object per content type, it needs to be a field. + +### Anatomy of a Content Type + +A content type, as we've seen, is built from content parts. Content parts, code-wise, are typically associated with: +* a Record, which is a POCO representation of the part's data +* a model class that is the actual part and that derives from ContentPart<T> where T is the record type +* a repository. The repository does not need to be implemented by the module author as Orchard will be able to just use a generic one. +* handlers. Handlers implement IContentHandler and are a set of event handlers such as OnCreated or OnSaved. Basically, they hook onto the content item's lifecycle to perform a number of tasks. They can also participate in the actual composition of the content items from their constructors. There is a Filters collection on the base ContentHandler that enable the handler to add common behavior to the content type. +For example, Orchard provides a StorageFilter that makes it very easy to declare how persistence of a content part should be handled: just do `Filters.Add(StorageFilter.For(myPartRepository));` and Orchard will take care of persisting to the database the data from myPartRepository. +Another example of a filter is the ActivatingFilter that is in charge of doing the actual welding of parts onto a type: calling `Filters.Add(new ActivatingFilter<BodyAspect>(BlogPostDriver.ContentType.Name));` adds the body content part to blog posts. +* drivers. Drivers are friendlier, more specialized handlers (and as a consequence less flexible) and are associated with a specific content part type (they derive from ContentItemDriver<T> where T is a content part type). Handlers on the other hand do not have to be specific to a content part type. Drivers can be seen as controllers for a specific part. They typically build shapes to be rendered by the theme engine. + +## Content Manager +All contents are accessed in Orchard through the ContentManager object, which is how it becomes possible to use contents of a type you don't know in advance. + +ContentManager has methods to query the content store, to version contents and to manage their publication status. + +## Transactions + +Orchard is automatically creating a transaction for each HTTP request. That means that all operations that happen during a request are part of an "ambient" transaction. If code during that request aborts that transaction, all data operations will be rolled back. If the transaction is never explicitly cancelled on the other hand, all operations get committed at the end of the request without an explicit commit. + + +## Request Lifecycle + +In this section, we'll take the example of a request for a specific blog post. + +When a request comes in for a specific blog post, the application first looks at the available routes that have been contributed by the various modules and finds the blog module's matching route. The route can then resolve the request to the blog post controller's item action, which will look up the post from the content manager. The action then gets a Page Object Model from the content manager (by calling BuildDisplay) based on the main object for that request, the post that was retrieved from the content manager. + +A blog post has its own controller, but that is not the case for all content types. For example, dynamic content types will be served by the more generic ItemController from the Core Routable part. The Display action of the ItemController does almost the same thing that the blog post controller was doing: it gets the content item from the content manager by slug and then builds the POM from the results. + +The layout view engine will then resolve the right view depending on the current theme and using the model's type together with Orchard conventions on view naming. + +Within the view, more dynamic shape creation can happen, such as zone definitions. + +The actual rendering is done by the theme engine that is going to find the right template or shape method to render each of the shapes it encounters in the POM, in order of appearance and recursively. + +## Widgets + +Widgets are content types that have the Widget content part and the widget stereotype. Like any other content types, they are composed of parts and fields. That means that they can be edited using the same edition and rendering logic as other content types. They also share the same building blocks, which means that any existing content part can potentially be reused as part of a widget almost for free. + +Widgets are added to pages through widget layers. Layers are sets of widgets. They have a name, a rule that determines what pages of the site they should appear on, and a list of widgets and associated zone placement and ordering, and settings. + +The rules attached to each of the layers are expressed with IronRuby expressions. Those expressions can use any of the IRuleProvider implementations in the application. Orchard ships with two out of the box implementations: url and authenticated. + +## Site Settings +A site in Orchard is a content item, which makes it possible for modules to weld additional parts. This is how modules can contribute site settings. + +Site settings are per tenant. + +## Event Bus + +Orchard and its modules expose extensibility points by creating interfaces for dependencies, implementations of which can then get injected. + +Plugging into an extensibility point is done either by implementing its interface, or by implementing an interface that has the same name and the same methods. In other words, Orchard does not require strictly strongly typed interface correspondence, which enables plug-ins to extend an extensibility point without taking a dependency on the assembly where it's defined. + +This is just one implementation of the Orchard event bus. When an extensibility point calls into injected implementations, a message gets published on the event bus. One of the objects listening to the event bus dispatches the messages to the methods in classes that derive from an interface appropriately named. + +## Commands + +Many actions on an Orchard site can be performed from the command line as well as from the admin UI. These commands are exposed by the methods of classes implementing ICommandHandler that are decorated with a CommandName attribute. + +The Orchard command line tool discovers available commands at runtime by simulating the web site environment and inspecting the assemblies using reflection. The environment in which the commands run is as close as possible to the actual running site. + +## Search and Indexing + +Search and indexing are implemented using Lucene by default, although that default implementation could be replaced with another indexing engine. + +## Caching + +The cache in Orchard relies on the ASP.NET cache, but we expose a helper API that can be used through a dependency of type ICache, by calling the Get method. Get takes a key and a function that can be used to generate the cache entry's value if the cache doesn't already contains the requested entry. + +The main advantage of using the Orchard API for caching is that it works per tenant transparently. + +## File Systems + +The file system in Orchard is abstracted so that storage can be directed to the physical file system or to an alternate storage such as Azure blob storage, depending on the environment. The Media module is an example of a module that uses that abstracted file system. + +## Users and Roles +Users in Orchard are content items (albeit not routable ones) which makes it easy for a profile module for example to extend them with additional fields. +Roles are a content part that gets welded onto users. + +## Permissions + +Every module can expose a set of permissions as well as how those permissions should be granted by default to Orchard's default roles. + +## Tasks + +Modules can schedule tasks by calling CreateTask on a dependency of type IScheduledTaskManager. The task can then be executed by implementing IScheduledTaskHandler. The Process method can examine the task type name and decide whether to handle it. + +Tasks are being run on a separate thread that comes from the ASP.NET thread pool. + +## Notifications + +Modules can surface messages to the admin UI by getting a dependency on INotifier and calling one of its methods. Multiple notifications can be created as part of any request. + +## Localization + +Localization of the application and its modules is done by wrapping string resources in a call to the T method: <%: T("This string can be localized") %>. See [Using the localization helpers](Using-the-localization-helpers) for more details and guidelines. Orchard's resource manager can load localized resource strings from PO files located in specific places in the application. + +Content item localization is done through a different mechanism: localized versions of a content item are physically separate content items that are linked together by a special part. + +The current culture to use is determined by the culture manager. The default implementation returns the culture that has been configured in site settings, but an alternate implementation could get it from the user profile or from the browser's settings. + +## Logging + +Logging is done through a dependency of type ILogger. Different implementations can send the log entries to various storage types. Orchard comes with an implementation that uses [Castle.Core.Logging](http://api.castleproject.org/html/N_Castle_Core_Logging.htm) for logging. + +# Orchard Core + +The Orchard.Core assembly contains a set of modules that are necessary for Orchard to run. Other modules can safely take dependencies on these modules that will always be available. + +Examples of core modules are feeds, navigation or routable. + +# Modules +The default distribution of Orchard comes with a number of built-in modules such as blogging or pages, but third party modules are being built as well. + +A module is just an ASP.NET MVC area with a manifest.txt file that is extending Orchard. + +A module typically contains event handlers, content types and their default rendering templates as well as some admin UI. + +Modules can be dynamically compiled from source code every time a change is made to their csproj file or to one of the files that the csproj file references. This enables a "notepad" style of development that does no require explicit compilation by the developer or even the use of an IDE such as Visual Studio. + +# Themes + +It is a basic design principle in Orchard that all the HTML that it produces can be replaced from themes, including markup produced by modules. Conventions define what files must go where in the theme's file hierarchy. + +The whole rendering mechanism in Orchard is based on shapes. The theme engine's job is to find the current theme and given that theme determine what the best way to render each shape is. Each shape can have a default rendering that may be defined by a module as a template in the views folder or as a shape method in code. That default rendering may be overridden by the current theme. The theme does that by having its own version of a template for that shape or its own shape method for that shape. + +Themes can have a parent, which enables child themes to be specializations or adaptations of a parent theme. Orchard comes with a base theme called the Theme Machine that has been designed to make it easy to use as a parent theme. + +Themes can contain code in much the same way modules do: they can have their own csproj file and benefit from dynamic compilation. This enables themes to define shape methods, but also to expose admin UI for any settings they may have. + +The selection of the current theme is done by classes implementing IThemeSelector, which return a theme name and a priority for any request. This allows many selectors to contribute to the choice of the theme. Orchard comes with four implementations of IThemeSelector: +* SiteThemeSelector selects the theme that is currently configured for the tenant or site with a low priority. +* AdminThemeSelector takes over and returns the admin theme with a high priority whenever the current URL is an admin URL. +* PreviewThemeSelector overrides the site's current theme with the theme being previewed if the current user is the one that initiated the theme preview. +* SafeModeThemeSelector is the only selector available when the application is in "safe mode", which happens typically during setup. It has a very low priority. + +An example of a theme selector might be one that promotes a mobile theme when the user agent is recognized to belong to a mobile device. diff --git a/Documentation/Installing-Orchard-Using-Web-PI.markdown b/Documentation/Installing-Orchard-Using-Web-PI.markdown new file mode 100644 index 00000000..2c5ef63e --- /dev/null +++ b/Documentation/Installing-Orchard-Using-Web-PI.markdown @@ -0,0 +1,56 @@ + +There are a few ways to install the latest Orchard release: + +1. You can install Orchard by simply downloading and extracting the Release zip file to a local IIS directory, then launching your browser to the appropriate URL. Make sure you download the appropriate zip for yur machine environment (32-bit or 64-bit). +2. You can also extract to a local folder, open the included Orchard.WebPI.csproj file in Visual Studio, and press Ctrl-F5 to run it under the ASP.NET Development Server (Cassini). Make sure to download the 32-bit zip of Orchard, since Cassini runs as a 32-bit process. +3. You can install using the Web Platform Installer (Web PI). + +**For options 1 and 2, download the zips from our CodePlex site: [http://orchard.codeplex.com/releases](http://orchard.codeplex.com/releases)** + +**This document describes option 3 - the steps to install using Web PI.** + +First, download the Web Platform Installer from [http://www.microsoft.com/web](http://www.microsoft.com/web) Click the "Options" link to configure Web PI to use the Orchard private feed. + + + +Type the URL to the private feed: http://www.orchardproject.net/privatedrops/orchardfeed.xml + + + +Click the "Add Feed" button to add the feed URL. + + + +Click OK to confirm the Options dialog. A new Orchard tab appears in Web PI. + + + +You can click the link to install recommended products to grab the latest Orchard release build. Alternatively, you can click "Customize" to view the available Orchard builds. + + + +Clicking the "info" icon will display details for a given release (along with the build number). To install an Orchard release build, select the checkbox and click "Install" + + + +Accept the license terms (New BSD) to proceed. + + + +Type the name of the application directory in IIS where you want Orchard to be installed (defaults to "http://localhost/orchard") + + + +When the installation is complete, click the "Launch Orchard CMS (Latest Build)" link + + + + + +In your browser, you will be presented with the Orchard setup screen. Answer these questions and click "Finish Setup" when done. + + + +You are now on the Orchard home page and can begin configuring your site. Enjoy! + + diff --git a/Documentation/Installing-Orchard.markdown b/Documentation/Installing-Orchard.markdown new file mode 100644 index 00000000..bb48cbea --- /dev/null +++ b/Documentation/Installing-Orchard.markdown @@ -0,0 +1,74 @@ + +There are four ways you can install Orchard. You can: + +* Install it using the Microsoft Web Platform Installer. +* Install it from Microsoft WebMatrix as shown in [Working with Orchard in WebMatrix](Working-with-Orchard-in-WebMatrix). +* Download the Orchard [.zip file](http://orchard.codeplex.com/releases/view/59918) and install it as described in [Manually Installing Orchard Using a zip File](Manually-installing-Orchard-zip-file). +* [Enlist](Setting-up-a-source-enlistment) in the Orchard source code and build Orchard from the command line or in Visual Studio. + +This topic shows how to install Orchard using the Microsoft Web Platform Installer. + + +# Requirements +The minimum requirements for running Orchard are the following: +* ASP.NET 4 +* A web server such as IIS Express 7.5 or IIS 7.x. + +> **Important**: If you previously installed any pre-release versions of WebMatrix, ASP.NET Web Pages, or ASP.NET MVC 3, you must uninstall those products before Orchard will run correctly on your computer. Also, if you plan to use Visual Studio 2010 with Orchard, it is suggested that prior to installing Orchard, you install the ASP.NET MVC 3 Tools Update from the Web Platform Installer. + +To develop Orchard sites, many developers will want to use a database such as SQL Server, and a web page programming environment such as WebMatrix or Visual Studio 2010. The following installation using the Web Platform Installer includes Orchard and IIS Express 7.5, and also includes optional applications for Orchard development, including WebMatrix and SQL Server Compact 4.0. + +# Installing Orchard + +To begin, download and install the [Web Platform Installer](http://www.microsoft.com/web/downloads/platform.aspx). When you're done, run it. + +Find **Orchard CMS** and then click **Add** to include Orchard as an item to install. The following image shows the Web Platform Installer with the ASP.NET MVC 3 Tools Update already installed and Orchard selected. + +![](../Upload/screenshots_675/webpi_install_675.png) + +Click **Install**. Accept the license terms in order to continue. + +![](../Upload/screenshots_675/Install_acceptterms.png) + +When the installation is complete, the dialog shows the list of installed tools in addition to Orchard. Click the **Launch** link to open the site in WebMatrix. + +![](../Upload/screenshots_675/Install_success.png) + +# Running Orchard in WebMatrix + +After WebMatrix starts, click the **Files** workspace to see the contents of the Orchard site. Launch Orchard in a browser by clicking the **Run** drop-down button, and selecting which browser to use. + +![](../Upload/screenshots_675/launch_Orchard_WebMatrix_675.png) + +When you launch Orchard in your browser, you see the Orchard setup screen. + +![](../Upload/screenshots/get_started_dialog_1.png) + +By default, Orchard includes a built-in database that you can use without installing a separate database server. However, if you are running SQL Server or SQL Server Express, you can configure Orchard to use either of those products instead by specifying a connection string. Optionally, you can enter a table prefix so that multiple Orchard installations can share the same database but keep their data separate. + +![](../Upload/screenshots_85/setup_sqlserver.png) + +The setup screen also includes a section where you can choose an Orchard recipe to set up your site. You can choose from the following Orchard recipes: + +* **Default**. Sets up a site with frequently used Orchard features. +* **Blog**. Sets up a site as a personal blog. +* **Core**. Sets up a site that has only the Orchard framework for development use. + +![](../Upload/screenshots/get_started_recipe.png) + +For information about recipes and how to make a custom recipe, see [Making a Web Site Recipe](http://orchardproject.net/docs/Making-a-Web-Site-Recipe.ashx). + +After you've entered the required information on the setup screen, click **Finish Setup**. When the setup process is complete, your new site's home page is displayed. + +![](../Upload/screenshots_675/playground_new_page_675_1.png) + +You can now begin configuring your site. + + + + +# Change History +* Updates for Orchard 1.1 + * 4-12-11: Updated screens for 1.1 installation. + * 3-14-11: Added information about recipes in the setup screen. + diff --git a/Documentation/Installing-and-upgrading-modules.markdown b/Documentation/Installing-and-upgrading-modules.markdown new file mode 100644 index 00000000..e76fe5eb --- /dev/null +++ b/Documentation/Installing-and-upgrading-modules.markdown @@ -0,0 +1,85 @@ + +Orchard is a modular web-based CMS, designed to be extended easily by installing additional modules and enabling module features. A _module_ is a package that can be installed and uninstalled. A _package_ consists of a ZIP file in the [.nupkg](http://nuget.codeplex.com) file format.) A _feature_ is a behavior that's exposed by an installed module that you can individually enable or disable. + +This topic shows you how to install or download modules from the online gallery, how to install a module from your local computer, and how to work with the features of an installed module. It also shows you how to update installed modules. + +> **Note** If your site is running under IIS, make sure you have granted read/write permissions to the _~/Themes_ folder under the root of your site for the service account that is being used as the IIS application pool identity. However, you should remove the write permissions on a production server. + + +# Viewing Installed Modules + +To view the modules that have been installed for your site, click **Modules** on the dashboard, and then in the **Modules** screen, click the **Installed** tab. + +![](../Upload/screenshots_675/modules_installedTab_upload_675.png) + +The **Installed** tab displays a list of the modules that are included with Orchard, along with properties of each module such as version, author, a description, and a list of features. It also provides a link that you can use to upload and install a module package. + +You can add modules to Orchard in two ways. The first and easiest is to install a module from the online gallery. The second is to upload a module package from your local computer and install it in your site. If you simply want to use an existing module in your Orchard site, you can install the module directly from the gallery to your site. If you want to modify a module package, or if you want to upload it to multiple Orchard sites, you will probably want to download the module from the gallery to your local computer. + +# Installing a Module from the Gallery + +When you install a module, its package file is downloaded from the gallery, and the source files are extracted from the package and added to your site. After you install a module, its features are available for use. + +To install a module from the gallery, click **Modules** on the dashboard, then click the **Gallery** tab. The **Gallery** tab displays a list of available online modules from the gallery feed (or feeds) registered for your site. + +![](../Upload/screenshots_675/browse_modules_gallery_675.png) + +The gallery displays the aggregated list of modules exposed by all [registered feeds](Module gallery feeds). You can also use the **Feed** drop-down list in the **Gallery** tab to display all feeds or to filter and display only the modules from a particular feed. + +To install a module, click the **Install** link for the module. This topic uses the **Bing.Maps** module as an example. + +![](../Upload/screenshots_675/install_link_bing_675.png) + +After the module has been installed, Orchard prompts you to enable features in the module. Select the features you want to enable and then click **OK**. + +![](../Upload/screenshots_675/install_enable_bing_675.png) + +When you return to the **Installed** tab, you can see the module that you just installed. + +# Downloading a Module from the Gallery + +At times you may want to simply download a module package to your computer rather than installing it in a site. To download a module, return to the **Gallery** tab and click **Download** for a specific module. (For example, download the **Contact Form** module.) The download process lets you save the _.nupkg_ file that contains the module contents to your local machine. You can then optionally modify the module, or install it in an Orchard site. + +![](../Upload/screenshots_675/download_module_contactform_675.png) + +# Installing a Module from your Local Computer + +To install a module from your local computer to an Orchard site, go to the **Modules > Installed** tab and then click the link to **Install a module from your computer**. + +![](../Upload/screenshots_675/upload_localmodule_675.png) + +Browse to the local module (a _.nupkg_ file), select it, and then click **Install**. This installs the module package to your site the same way that clicking **Install** does for an online module in the gallery. + +![](../Upload/screenshots_675/install_localmodule_675.png) + +# Working with Module Features + +When you install a module in an Orchard site, the module contains one or more features. You can enable or disable each feature individually, either when you first install the module, or later. The **Bing.Maps** module used as an example in the previous section contains a single feature, also called **Bing.Maps**. (Remember that a module can have one or many features, and that the features do not have to have the same name as their parent module.) In this section, you'll see how to enable or disable an individual feature (the **Bing.Maps** feature), and how to add that feature to a content type, such as a page. + +Begin by observing how to enable or disable the **Bing.Maps** feature. To do this, go to the **Modules > Features** tab, find the **Bing.Maps** feature. Note that it is enabled, and that you can disable it by clicking a **Disable** link on the feature. If the feature is disabled, then an **Enable** link appears for enabling the feature. Leave the feature enabled for this tutorial. + +![](../Upload/screenshots/disable_module_feature_bingmaps.png) + +Now you can add a new content part (a **Bing Map** part, which is included in the disabled **Bing.Maps** feature) to the page content type. On the dashboard, click **Content**, and then click the **Content Types** tab. Find the **Page** content type, and then click **Edit** next to the type. In the **Edit Content Type** screen, click **Add Parts** in the **Parts** section. The **Add Parts to Page** screen is displayed. + +![](../Upload/screenshots_675/add_bingmap_pageContentType_675.png) + +Select the **Bing Map** content part from the list of available parts, and then save the updated page content type. + +Now you can see the effect of adding the **Bing Maps** content part to the page type. On the dashboard in the **New** menu, click **Page** to create a new page. Because you installed the **Bing Maps** module, enabled the feature, and added the **Bing Map** content part to the page, when you create a new page instance, a number of map-related fields appear. + +![](../Upload/screenshots_675/newpage_bingmap_enabled_675.png) + +# Updating an Installed Module + +Occasionally modules will be updated with fixes or new features. You can update an installed module by clicking **Modules** on the dashboard and then clicking the **Updates** tab. If there are no updates available for your installed modules, the **Updates** tab is empty. If there are updates available, you can install or download the updates the same way that you installed the module originally. + +![](../Upload/screenshots_675/modules_installed_updates_675.png) + + + + +# Change History +* Updated for Orchard 1.1 + * 3-23-11: Reordered sections of the topic, added new section on enabling and disabling features, plus another section on updating a module. Updated screens and text in existing sections. + diff --git a/Documentation/Installing-modules-and-themes-from-the-gallery.markdown b/Documentation/Installing-modules-and-themes-from-the-gallery.markdown new file mode 100644 index 00000000..305837a4 --- /dev/null +++ b/Documentation/Installing-modules-and-themes-from-the-gallery.markdown @@ -0,0 +1,57 @@ + +Orchard makes it easy to browse available modules and themes from an online gallery and install them using the Orchard dashboard. This topic shows how to install both modules and themes from the gallery. + +> **Note:** If your site is running under IIS, make sure you have granted read/write permissions to the ~/Themes folder under the root of your site for the service account that is being used as the IIS application pool identity. However, you should remove the write permissions on a production server. + + +# Accessing and Enabling the Gallery + +The gallery feature is enabled by default in Orchard. When the gallery is enabled, a **Gallery** tab appears at the top of the both the **Themes** screen and the **Modules** screen in the dashboard. + +![](../Upload/screenshots/gallery_default_enabled.png) + +> Note: If the gallery feature has been disabled, there will be no **Gallery** tab visible in the **Themes** or **Modules** dashboard screens. To enable the gallery, click **Modules** in the dashboard, find the gallery feature, and then click **Enable** on the feature. + +# Installing a Theme from the Gallery + +To access the gallery for themes, click **Themes** in the dashboard. On the **Themes** screen click the **Gallery** tab. A set of themes appears with a pair of **Install** and **Download** links next to each theme. + +![](../Upload/screenshots_675/themes_themeGallery_675.png) + +If you install a theme, it becomes available to apply to your site. If you download a theme, you save the theme package file to your local computer. You can then use the **Themes** screen in the Orchard dashboard to install the downloaded theme package. For more information, see [Installing Themes](Installing-themes). + +## Previewing and Applying an Installed Theme + +After installing a new theme, you can preview, enable, and apply that theme to your site by clicking **Themes** in the dashboard. For more information, see [Previewing and Applying a Theme](Previewing-and-applying-a-theme). + +# Installing a Module from the Gallery + +To access the gallery for modules, click **Modules** on the dashboard and then click the **Gallery** tab. A set of modules appears with a pair of **Install** and **Download** links next to each module. + +![](../Upload/screenshots_675/modules_browse_gallery_675.png) + +As with themes, if you install a module it becomes available to use on your site. If you download a module, you save the module package file to your local computer. You can then go to the **Modules** screen on the dashboard, click the **Installed** tab, and then click **Upload** to install the module in an Orchard site. For more information about how to activate a module after installing it, see [Installing and Upgrading Modules](Installing-and-upgrading-modules) and [Enabling and Disabling Features](Enabling-and-disabling-features). + +On the dashboard **Modules** screen, click the **Installed** tab. This tab displays all the modules that are installed in an Orchard site. + +![](../Upload/screenshots_675/modules_installedtab_upload_675.png) + +Notice that on every page in the **Installed** tab, there is a link that lets you upload a module package to the site. + +# Displaying Additional Gallery Feeds + +The **Gallery** tabs on the **Modules** page and the **Themes** page of the dashboard together display the aggregated list of themes and modules exposed by all feeds registered on your site. On the **Gallery** tabs for both themes and modules, you can use the **Feed** drop-down list to filter the display so that it shows all available items, or only the items from a selected feed. (This is only useful if you have multiple feeds registered.) + +![](../Upload/screenshots_675/modules_gallerytab_filterbyfeed_675.png) + +By default, the [Orchard Gallery feed](http://orchardproject.net/gallery/) is registered for an Orchard site. To register additional gallery feeds see [Registering Additional Gallery Feeds](Module gallery feeds). + + + + + +# Change History +* Updates for Orchard 1.1 + * 3-22-11: Updated screen shots and menu or UI options. + + diff --git a/Documentation/Installing-themes.markdown b/Documentation/Installing-themes.markdown new file mode 100644 index 00000000..246c25ba --- /dev/null +++ b/Documentation/Installing-themes.markdown @@ -0,0 +1,46 @@ + +There are two ways to add a theme to Orchard. The first and easiest is to use the **Gallery** tab on the **Themes** page in the dashboard to browse and install themes from an online feed of available themes. The second is to go to the dashboard **Themes** page and click the link to install a theme, which allows you to browse for a theme package on your local computer and install it. + +> **Note** If your site is running under IIS, make sure you have granted read/write permissions to the _~/Themes_ folder under the root of your site for the service account that is being used as the IIS application pool identity. However, you should remove the write permissions on a production server. + + +# Installing a Theme from the Gallery + +When the gallery feature is enabled, as it is by default in Orchard, a **Gallery** tab appears at the top of the both the **Themes** screen and the **Modules** screen in the dashboard. + +![](../Upload/screenshots/Themes_gallery_enabled.png) + +> Note: If the gallery feature has been disabled, there will be no **Gallery** tab visible in the **Themes** or **Modules** dashboard screens. To enable a disabled gallery, click **Modules** in the dashboard, and click **Enable** on the Gallery feature. + +In the **Themes** screen of the dashboard, click the **Gallery** tab. A set of themes appears with a pair of **Install** and **Download** links next to each theme. + +![](../Upload/screenshots_675/Gallerythemes_installing_675.png) + +To install a theme in your site, click the **Install** link next to the theme. Installing a theme adds it to your site in the **Available** list of themes on the **Themes** page in the dashboard. From there, you can preview a theme or set it as the current site theme, as described [Previewing and Applying a Theme](Previewing-and-applying-a-theme). + +# Installing a Theme from your Local Computer + +To install a theme from your local computer, in the **Themes** screen of the dashboard, click the link to **Install a theme from your computer**. This displays a screen that lets you install a theme. + +![](../Upload/screenshots/themes_installnew_upload.png) + +Browse to a local package file that contains a theme (the file will have a _.nupkg_ extension), select it, and then click **Install**. The theme package is installed in your site, and you will see the theme listed in the **Available** section of the **Themes** screen. + +> **Note** A theme contains a number of files and folders packaged in a ZIP file that has a _.nupkg_ file extension. The packaging feature is provided by the NuGet package management system. Packaging themes and other add-ons is beyond the scope of this topic, but you can learn more at [http://nuget.codeplex.com/](http://nuget.codeplex.com/). + +The following illustration shows the Terra theme, which was previously downloaded to the local computer from the Gallery, after clicking the **Install a theme from your computer** link and installing it to an Orchard site. The installed theme appears in the **Available** section. + +![](../Upload/screenshots_675/theme_addLocal_install_675.png) + +To use an example theme to test this feature, download an existing theme from the **Gallery** tab on the **Themes** page, then browse to the saved _.nupkg_ file on your computer and install it as described previously. + +When a theme is installed, the theme files are placed in the _~/Themes_ folder. You can see the installed themes in your site by checking the **Available** section on the **Themes** page in the dashboard. For more information about how to preview themes and apply them to your site, see [Previewing and Applying a Theme](Previewing-and-applying-a-theme). + + + + +# Change History +* Updates for Orchard 1.1 + * 3-21-11: Updated screen shots and text for installing themes. + + diff --git a/Documentation/Linkback.markdown b/Documentation/Linkback.markdown new file mode 100644 index 00000000..952fe0e0 --- /dev/null +++ b/Documentation/Linkback.markdown @@ -0,0 +1,63 @@ + +Orchard should send linkbacks when contents gets created, and should receive refbacks, trackbacks and pingbacks. It should put all three through spam filters and should provide admin UI to manage the linkbacks and configure their moderation (moderation required or not, etc.). + + +# Sending linkbacks + +The Linkback module, when activated for a given content type, should act as a filter on save actions. It should be looking for A tags in the body of the content item and extract the href attribute for each. It should then schedule trackback and pingback pings for each extracted URL. + +> **Issue:** should only body be scanned for URLs or should we rely on a more generic definition of content text? + +> **Note:** linking back to local contents can be considered like a regular linkback, but some site authors like to only show external ones. For this reason, there should be a setting to only send trackback notifications to external URLs. + +## Sending refback + +For refbacks, there isn't anything to do from the sender's end. The first visitor to click the link will implicitly notify the target site. + +## Sending trackback + +On the scheduled job, the linkback module should do a GET on the linked URL and then scan the results for embedded RDF for the ping URL. If such a ping URL is found, the module should send the trackback ping, according to [the trackback specification](http://www.sixapart.com/pronet/docs/trackback_spec). + +## Sending pingback + +The GET request that is being made to search for trackback RDF can be re-used to look for pinkback HTTP headers or link tags, according to [the pinkback specification](http://www.hixie.ch/specs/pingback/pingback). If such a pingback URL is discovered, it should be pinged according to spec. + +## When both trackback and pingback are supported + +When both pingback and trackback are discovered to be supported, we should only send the pingback notification. +# Embedding trackback and pingback auto-discovery + +In order to comply with trackback and pingback specifications, we must include auto-discovery information in any document that must be able to be linked back to. For pingback, there is a choice of using an HTTP header or a link tag. We will use link tags because they are more explicit and easier to fit in our overall UI composition engine. + +The linkback module, when activated on the main content item being displayed, will inject the auto-discovery markup for both trackback and pingback into the page, using the same composition engine that is being used for the rest of the page. That markup will point the linkback clients to trackback and pingback actions on the linkback controller. + +# Receiving linkback pings + +The linkback controller will receive all notifications for pingback and trackback. + +For refback, the linkback module will have to act as a filter in order to handle all incoming GET actions that have a referrer that is different from the current URL. + +In all three cases, the linkback module will verify that the targeted content item has linkback enabled (it has a linkback part), and it will then add a record to the list of linkback URLs on the linkback part for that item, if that URL is not already in the list. + +The items in the list of linkback URLs have a URL, a title (the extracted title of the linking page), a summary (the summary meta of the linking page if available, null otherwise) and a date (the date the linkback was received). + +# Moderation and spam filtering + +Each linkback to a content item should be moderated and filtered for spam like comments are. See [comment specification](comments). + +# Settings + +It should be possible eventually to configure what content items accept linkbacks. That will be part of the general configuration of parts on content types. That work has not been done yet. + +It should be possible to enable or disable each of the three linkback protocols, on the ways in or out. + +There should be a setting to enable or disable local/internal linkbacks. + +# Permissions +In this context, the owner is the owner of the content item being linked back to (the container of the linkbacks). + + +Permission | Anon. | Authentic. | Owner | Admin. | Author | Editor +------------------------------------------------ | ----- | ---------- | ----- | ------ | ------ | ------ +Moderate linkbacks (implies all others) | No | No | Yes | Yes | Yes | Yes +Disable linkbacks | No | No | Yes | Yes | Yes | Yes diff --git a/Documentation/Localizing-modules.markdown b/Documentation/Localizing-modules.markdown new file mode 100644 index 00000000..e69de29b diff --git a/Documentation/Making-a-Web-Site-Recipe.markdown b/Documentation/Making-a-Web-Site-Recipe.markdown new file mode 100644 index 00000000..fb530e00 --- /dev/null +++ b/Documentation/Making-a-Web-Site-Recipe.markdown @@ -0,0 +1,204 @@ + +Orchard simplifies the process of setting up a new website by letting you use _website recipes_. A recipe is an XML file that contains the startup configuration for an Orchard website. When you start Orchard for the first time, you can select a recipe that best matches the type of site you want to set up. For example, if you want your website to be a blog, you can select the **Blog** recipe, and much of the configuration work will be done for you. + +You can create your own recipes and customize the process of setting a website and configuring Orchard features. Recipes can also instruct Orchard to download and install modules and themes from the Orchard Gallery during website setup. + +This article describes how to use recipes, how to create custom recipes, export or import recipes, and how to create a specialized distribution of Orchard using recipes. + + +# Using a Recipe to Create a Website + +When you first set up an Orchard website, the setup page that is displayed contains a list of recipes. You can choose a recipe to base your new website on. + +![](../Upload/screenshots/recipes_get_started.png) + +The initial list contains the following recipes: + +* **Default**. The default recipe for an Orchard site that includes pages, blogs, custom content types, comments, tags, widgets, and basic navigation. +* **Blog**. A recipe that provides an installation profile with features for a personal blog. +* **Core**. A recipe that provides the Orchard framework with limited end-user functionality that can be used during development. + +After you choose a recipe and click **Finish Setup**, Orchard creates the website using the selected recipe and opens the home page. + +# How Recipes Work + +An Orchard recipe is an XML file that contains website configuration information. The following example shows the contents of the default recipe file. + + + + + + Default + The default recipe for an Orchard site that includes pages, blogs, custom content types, comments, tags, widgets and basic navigation. + The Orchard Team + http://orchardproject.net + + 1.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + layer create Default /LayerRule:"true" + layer create Authenticated /LayerRule:"authenticated" + layer create Anonymous /LayerRule:"not authenticated" + layer create Disabled /LayerRule:"false" + layer create TheHomepage /LayerRule:"url '~/'" + page create /Slug:"welcome-to-orchard" /Title:"Welcome to Orchard!" /Path:"welcome-to-orchard" /Homepage:true /Publish:true /UseWelcomeText:true + widget create HtmlWidget /Title:"First Leader Aside" /Zone:"TripelFirst" /Position:"5" /Layer:"TheHomepage" /UseLoremIpsumText:true + widget create HtmlWidget /Title:"Second Leader Aside" /Zone:"TripelSecond" /Position:"5" /Layer:"TheHomepage" /UseLoremIpsumText:true + widget create HtmlWidget /Title:"Third Leader Aside" /Zone:"TripelThird" /Position:"5" /Layer:"TheHomepage" /UseLoremIpsumText:true + menuitem create /MenuPosition:"1" /MenuText:"Home" /Url:"" /OnMainMenu:true + + + + +The following sections of a recipe file are the elements that are most important to understand: + +* **Recipe**. This section contains metadata about the recipe, such as its name and description. +* **Feature**. This section lists module features that Orchard will enable. +* **Metadata**. This section provides configuration for the types, parts, and fields that Orchard contains. +* **Settings**. This section provides a way to configure website settings. +* **Command**. This section lists commands that Orchard will run against your website in order to complete the setup. For more information about Orchard commands, see [Using the Command-line Interface](Using-the-command-line-interface). + + +# Creating a Custom Recipe + +You can create your own recipe, which can then be added to the setup page or to your own module. Recipes added to the setup page can be selected by the user only during site setup; recipes added to a module can be executed by the user after site setup. + +To get started with creating a custom recipe, you can select an existing recipe that you can tailor to your purposes. The following example shows how to start with the default recipe _(default.recipe.xml)_ and add the **Bing.Maps** module and a theme, both of which will be downloaded and enabled during setup. The recipe also creates a blog and a page that displays the map widget. Finally, the recipe adds layers and menu tabs for the blog and map page. + + + + + + Custom Recipe + A recipe that includes a landing page with blog on a second tab. + The Orchard Team + http://orchardproject.net + + 1.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + layer create Default /LayerRule:"true" + layer create Authenticated /LayerRule:"authenticated" + layer create Anonymous /LayerRule:"not authenticated" + layer create Disabled /LayerRule:"false" + layer create TheHomepage /LayerRule:"url '~/'" + layer create Blog /LayerRule:"url '~/Blog'" + layer create Maps /LayerRule:"url '~/Maps'" + page create /Slug:"welcome-to-orchard" /Title:"Welcome to Orchard!" /Path:"welcome-to-orchard" /Homepage:true /Publish:true /UseWelcomeText:true + blog create /Slug:"blog" /Title:"Blog" /Homepage:false /Description:"This is your Orchard Blog." + page create /Slug:"maps" /Title:"Bing Maps" /Path:"bing-maps" /Homepage:false /Publish:true /UseWelcomeText:false + widget create HtmlWidget /Title:"First Leader Aside" /Zone:"TripelFirst" /Position:"5" /Layer:"TheHomepage" /UseLoremIpsumText:true + widget create HtmlWidget /Title:"Second Leader Aside" /Zone:"TripelSecond" /Position:"5" /Layer:"TheHomepage" /UseLoremIpsumText:true + widget create HtmlWidget /Title:"Third Leader Aside" /Zone:"TripelThird" /Position:"5" /Layer:"TheHomepage" /UseLoremIpsumText:true + menuitem create /MenuPosition:"1" /MenuText:"Home" /Url:"" /OnMainMenu:true + menuitem create /MenuPosition:"2" /MenuText:"Blog" /Url:"~/Blog" /OnMainMenu:true + menuitem create /MenuPosition:"3" /MenuText:"Maps" /Url:"~/Maps" /OnMainMenu:true + + + + +Note the following about the changes made to the default recipe: + +* **Module** element. This element identifies a module that will be downloaded from the Orchard Gallery on the website. This does not enable the features in the module; it only downloads it. To enable a module feature, add it to the `Feature` element as shown in the example. +* **Theme** element. This element identifies a theme that will be downloaded from the Orchard Gallery. If the **current** attribute is set to true, the theme becomes the current theme and is applied to the website. Otherwise, it will just be downloaded. It is also possible to enable a theme by using the `enable="true"` attribute. Otherwise the theme is initially disabled. If you use `current="true"`, the theme is automatically enabled. +> **Important**: The **Module** and **Theme** elements must appear in the recipe immediately after the **Recipe** element. +* **layer create** command. This was added in order to create the **Blog** and **Maps** layer. +* **blog create** command. This was added in order to create the blog. +* **page create** command. This was added in order to create the **Maps** page. +* **menuitem create** command. This was added in order to create the **Blog** and **Maps** menu tabs. + +In addition to the attributes shown here for the **Module** and **Theme** elements, both elements support a **version** attribute. If the version is specified, that version will be downloaded from the Orchard Gallery. Both elements also have a **repository** attribute. By default, the **repository** attribute points to the Orchard Gallery. However, you can set it to any feed URL. + +To add your custom recipe to the setup page, put the recipe XML file into the _Orchard.Web/Modules/Orchard.Setup/Recipes_ folder. When you set up a new Orchard website, the recipe list will contain your recipe. + +![](../Upload/screenshots/recipes_new_custom.png) + +# Importing and Exporting a Recipe +Orchard enables you to import and export recipes from and to the web server. It uses the **Import Export** module, which is disabled by default. Therefore you must enable the module to use this feature. + +To enable the **Import Export** module, open the dashboard and click **Modules**. On the **Modules** page, select the **Features** tab. Under **Content**, locate the **Import Export** feature and click **Enable**. A message at the top of the page will notify you when the feature is enabled. You will also see **Import/Export** listed in the dashboard feature list. + +![](../Upload/screenshots/recipe_ImportExport_enable.png) + +To export a recipe, open the dashboard and click **Import/Export**. Click the **Export** tab and then choose the types, metadata, data, and settings to include in the export file. When you are finished, click **Export**. + +![](../Upload/screenshots/recipe_export.png) + +To import a recipe, click **Import/Export** and then click the **Import** tab. Browse to the recipe file and click **Import**. + +![](../Upload/screenshots/recipe_import.png) + +# Creating a Specialized Distribution of Orchard + +Recipes simplify the process of creating a specialized distribution of Orchard. Using recipes (and optionally custom modules), you can configure a version of the Orchard platform that is optimized for nearly any type of website you can envision. + +**To create a specialized distribution of Orchard** + +1. Enlist in the Orchard source code. For information about how to enlist in Orchard, see [Setting Up a Source Enlistment](Setting-up-a-source-enlistment). +2. Sync to the latest build. +3. Create a custom recipe and add it to the _Orchard.Web/Modules/Orchard.Setup/Recipes_ folder. If you want your recipe to be the only option, you can remove the other recipe files. +4. Add any custom modules to the _Orchard.Web/Modules_ folder. +5. Compile the project. +6. Distribute all files under the _Orchard.Web_ folder. diff --git a/Documentation/Managing-users-and-roles.markdown b/Documentation/Managing-users-and-roles.markdown new file mode 100644 index 00000000..6b11779e --- /dev/null +++ b/Documentation/Managing-users-and-roles.markdown @@ -0,0 +1,35 @@ + +Orchard provides the ability to manage users and roles for your site, with users assigned to one or more roles, and different permissions associated to each role. + +To manage the users in your site, click the **Users** link in admin panel. + +![](../Upload/screenshots/Users_select.png) + +By default, there is ony one user, which is the admin user that is configured in the Orchard setup screen on first install. To add an additional user, click **Add a new user**. You can also edit, remove, and disable user accounts from this screen. + +![](../Upload/screenshots_675/Users_manage.png) + +When adding a new user, specify a user name, email and password, along with one or more roles for the user. The roles determine what permissions a user has on your site, in other words, what operations they are allowed to perform. The effective permissions for a user are the union of permissions for all applied roles. Permissions only grant operations to a user; they never deny them. + +![](../Upload/screenshots_85/add_user.png) + +You can also configure the roles in your site by clicking the **Roles** link in the admin panel. + +![](../Upload/screenshots/Users_roles.png) + +By default, Orchard includes a number of roles with default permissions: + +* **Administrator** - Can perform any operation (has all permissions) +* **Editor** - Can author, publish and edit his own and others' content items. +* **Moderator** - Can moderate comments and tags only. No authoring permissions. +* **Author** - Can author, publish and edit his own content items +* **Contributor** - Can author and edit his own content items, but not publish them (save draft only) +* **Anonymous** - Can view the front-end of the site only. +* **Authenticated** - Can view the site front-end, and perform other operations depending on the site and other role permission settings. + +![](../Upload/screenshots_675/Users_manageroles.png) + +To edit the permission for a given role, click **Edit** next to the role name. + +![](../Upload/screenshots_675/edit_role_admin.png) + diff --git a/Documentation/Managing-widgets.markdown b/Documentation/Managing-widgets.markdown new file mode 100644 index 00000000..16050f24 --- /dev/null +++ b/Documentation/Managing-widgets.markdown @@ -0,0 +1,104 @@ + +In Orchard, a widget is a fragment of UI (such as HTML) and code (such as a content part) that can be easily mapped to any location or zone in the active theme, such as a sidebar or footer zone. Examples of widgets include navigation menus, image galleries, ads, videos, and tag clouds. + +This article explains the basics of widgets and shows you how to manage them. + +# Layers, Zones, and Widgets +In Orchard, you manage widgets by clicking **Widgets** in the dashboard. The **Widgets** screen lists the available widgets and lets you assign the widget to a _layer_ and a _zone_. + +You can think of a _layer_ as a set of rules for displaying a widget (or group of widgets). For example, a layer might display a widget on a specific page only if the user is logged in. A _zone_ helps to position a widget on a page. + +The following image shows the **Widgets** screen. + +![](../Upload/screenshots_675/widgets_manage_1_675.png) + +## Available Widgets +Whenever a widget becomes available (usually by enabling another feature in the **Features** tab on the **Modules** screen of the dashboard), Orchard adds it to the list of available widgets that can be added to zones in the current theme. To see the list of widgets available in a zone, in the **Widgets** screen, click the **Add** button on one of the listed zones. + +For example, in the **Widgets** screen click **Add** for the **Header** zone. A screen is displayed that allows you to choose one of the available widgets. + +![](../Upload/screenshots_675/widgets_choosewidget_675.png) + +The following table describes the widgets that are available by default in Orchard: + +Widget | Description +--------------------- | ------------------------------------------------------------------ +**Blog Archives** | Displays a list of archived entries for the specified blog. +**Container Widget** | Displays a "contained" content item, such as a list. +**Html Widget** | Displays HTML content, which is entered using the widget's editor. +**Recent Blog Posts** | Displays a list of recent posts for the specified blog. + +## List of Layers +Orchard comes with a number of layers already defined. You can define additional layers as needed, as discussed later in [Adding a Layer](#AddingALayer). In the **Widgets** screen, you can edit the existing layers by selecting a layer in the **Current Layer** drop-down list, or you can add new layers by clicking **Add a new layer**. + +The following table lists the default layers, shows the rule that defines the layer, and describes the effect of the layer. + +Layer | Rule | Description +-------------- | ----------------- | --------------------------------------- +Default | true | Always displayed on every page. +Authenticated | authenticated | Displayed if the user is authenticated. +Anonymous | not authenticated | Displayed if the user is anonymous. +Disabled | false | Not displayed. This layer is provided as way to save the configuration of widgets that are not currently displayed. +TheHomepage | url("~/") | Displayed on the home page. + +## List of Zones +In Orchard, a web page is divided into zones (regions). The available zones are defined by the website's theme. In the **Widgets** screen, you can see the list of all zones available for the currently selected layer. The list also shows the widgets assigned to each zone for the selected layer. + +For information about the zones that are available in the default theme (TheThemeMachine), see [Customizing the Default Theme](Customizing-the-default-theme). + + +# Adding a Layer +To add a layer, in the dashboard, click **Widgets**. On the **Widgets** screen, click **Add a new layer**. The **Add Layer** screen is displayed: + +![](../Upload/screenshots_675/widgets_AddLayer_1_675.png) + +To define the new layer, enter the name of the layer, a description, and the rule that defines the layer. When you're finished, click **Save**. + +The **Layer Rule** value is an expression that resolves to either **true** or **false**. If it resolves to **true**, the widget is displayed; otherwise the widget is not displayed. + +The following table summarizes the syntax for building layer rules. + +Rule Syntax | Description +---------------------------- | ------------------------------ +url("<url path>") | True if the current URL matches the specified path. If you add an asterisk (*) to the end of the path, all pages found in subfolders under that path will evaluate to true (for example, `url("~/home*")`). +authenticated | True if the user is logged in. +not | Logical NOT. +and | Logical AND. +or | Logical OR. + +Your expression can use parentheses. + +For example, the following expression defines a rule that displays a widget on the **About** page if the user is not authenticated, or on any page if the user is authenticated. + + + (not authenticated and url("~/about")) or authenticated + + +# Assigning a Widget to a Zone +To assign a widget to a zone, click the **Add** button on a zone that you want to add the widget to, and then select the widget to add. + +For example, click **Add** on the Header zone, and then in the **Choose A Widget** screen click the **Html Widget**. + +The **Add A Widget** screen is displayed. + +![](../Upload/screenshots_675/widgets_AddZone_1_675.png) + +The fields you need to fill in depend on the widget you're configuring. However, all widgets have **Zone**, **Layer**, **Title**, and **Position** fields. The **Position** field determines the relative position of all widgets within the zone (in effect, z-order). Keep in mind that the widgets within the zone can come from multiple layers. For example, two different layers might have widgets assigned to the same zone. + +The value of the **Position** field can be an integer or a sequence of integers separated by dots. For example, the following values are all valid: 5, 10.1, 7.5.3.1. Widgets with lower position values will be rendered before those with higher values. + +After setting the values of all fields, click **Save**. + +# Editing or Deleting a Widget +To edit or delete a widget, in the **Widgets** screen, use the **Current Layer** drop-down list to select the layer that the widget is assigned to. In the list of zones displayed for the layer, click the widget you want to edit. The **Edit Widget** screen is displayed: + +![](../Upload/screenshots_675/widgets_Delete_1_675.png) + +Edit the field you want to change, then click **Save**. To remove the widget from the zone, click **Delete**. + + + + +### Change History +* Updates for Orchard 1.1 + * 3-16-11: Updated screen shots for 1.1 version. diff --git a/Documentation/Manifest-files.markdown b/Documentation/Manifest-files.markdown new file mode 100644 index 00000000..3e8d918b --- /dev/null +++ b/Documentation/Manifest-files.markdown @@ -0,0 +1,93 @@ + +In the Orchard CMS, modules and themes are important tools for extending and customizing an application. Every module and theme is required to have a manifest, which is a text file named _module.txt_ or _theme.txt_ that resides in the root folder of the associated module or theme. A manifest stores metadata that Orchard uses to describe modules and themes to the system, such as name, version, description, author, and tags. + +This topic is a reference for manifest files. If you create a custom module or theme, or if you write code that accesses modules or themes, you must understand the metadata fields in a manifest. The data in a manifest is structured into name-value pairs in the form _Field Name_:_Value_. + +The following sections describe the available fields in a manifest for themes and for modules. Because a theme is a type of module, many of the same metadata fields occur in both theme manifests and module manifests. + + +## Module Manifest Fields + +The manifest for a module can feature the following fields: + +Field Name | Description +------------------ | --------------------------------------------------- +Name | Provides a human-readable name for a module that is an alternative to using the module's ID. The ID of a module is the name of the module's folder in the virtual base path (the default virtual base path is _~/Modules_), and is used for programmatic references to the module. For example, for a module whose ID is `Bing.Maps`, you might provide a name in the manifest such as `Bing Mapping Component` or even `Bing Maps` (notice that the "." is removed). If you do not provide a name in the manifest, the ID is used instead. If you do provide a name, it will be used as the module's display name in the gallery and in the Orchard UI. +Path | Provides a name that is used to build more readable URLs for routing purposes compared to URLs that are based on module names or ID values. This is an optional field. If you do not provide a path, Orchard builds URLs based on the module's name (if one is provided) or on the ID. However, module names often have spaces, and ID values often have "." characters, neither of which result in very readable URLs. For example, for the Orchard **ArchiveLater** module, its name is `Archive Later`, and its ID is `Archive.Later`. In the manifest, a path is provided and the value is `ArchiveLater`, which enables Orchard to build a more readable URL than the module name or the ID would. +Description | A brief summary of what a module does. The description is used in the gallery and in the Orchard UI. +Version | The version number of a module. The version information is displayed in the gallery and in the Orchard UI. It is also used to determine whether an update is needed. +OrchardVersion | The Orchard version number for the current module version. +AntiForgery | A value that indicates whether request validation is enabled for a module. Possible values are `enabled` or `disabled`. +Author | The developer of a module. This can be an organization, individual, or a list of individuals. +Website | The URL for the website of the module developer. +Tags | A comma-separated lists of tags for the module. The tags can be used to filter or group modules in a list. For example, a custom online gallery of modules can provide the ability to filter and display modules by tag. +FeatureDescription | A description of the default feature in a module. If a module has only a single feature, use the `FeatureDescription` field to describe it. If a module has multiple features and one of the features is the default, use the `FeatureDescription` field to describe the default feature, and describe the remaining features using the `Features` field. When you add this field to a manifest, you should also add a `Category` field to indicate the display category for the feature. If the feature is dependent on other features, also add a `Dependencies` field and provide a comma-separated list of the `Id` values of the other features that the feature depends on. +Category | The display heading for a feature in the Orchard UI. For each individual feature that you describe in a manifest, you should also enter a category for the feature (if you don't, the feature will be displayed in an "uncategorized" section on the **Features** screen in the dashboard). The value appears as a section heading in the **Features** screen of the Orchard dashboard. If multiple features have the same category, they are displayed under a single shared heading in the **Features** screen. For examples of how to provide a category for a default single feature or for multiple features listed under the `Features` field, see the manifest files that follow. +Dependencies | A comma-separated list of the application `Id` values of all features that the specified feature depends on. +Features | A description of the features provided by a module. If a module has only one feature, use the `FeatureDescription` field instead. If a module has two or more features, use the `FeatureDescription` field to describe the default feature, and use the `Features` field to describe details of each additional feature. To complete the `Features` field, supply the following details for each feature: `Feature Id`, `Name`, `Description`, `Category`, and `Dependencies` (if any). You may also optionally specify a `Priority` for a feature that can be used by Orchard to determine how to resolve dependencies implementing a specific interface. The default is 0 and higher priorities will take precedence. + +The following example shows an example of a manifest for the **Email Messaging** module. This module has a single feature, so it uses the `FeatureDescription` field. It also includes `Category` and `Dependencies` fields for the feature. + + Name: Email Messaging + AntiForgery: enabled + Author: The Orchard Team + Website: http://orchardproject.net + Version: 1.0.20 + OrchardVersion: 1.0.20 + Description: The Email Messaging module adds Email sending functionalities. + FeatureDescription: Email Messaging services. + Category: Messaging + Dependencies: Orchard.Messaging + + +The following example shows a manifest for the **Blogs** module. This module has a default feature, which is described in the `FeatureDescription` field, and it specifies a category and dependencies for the default feature. The module has an additional feature that is described in the `Features` field. + + Name: Blogs + AntiForgery: enabled + Author: The Orchard Team + Website: http://orchardproject.net + Version: 1.0.20 + OrchardVersion: 1.0.20 + Description: The Orchard Blogs module is implementing basic blogging features. + FeatureDescription: A simple web log. + Dependencies: Shapes, Common, Routable, Feeds, Navigation, Orchard.Widgets, Orchard.jQuery, Orchard.PublishLater + Category: Content + Features: + Orchard.Blogs.RemotePublishing: + Name: Remote Blog Publishing + Description: Blog easier using a dedicated MetaWeblogAPI-compatible publishing tool. + Dependencies: XmlRpc, Orchard.Blogs + Category: Content Publishing + + +Notice the structure that is used for each feature described in the `Features` field. The ID of the feature is listed followed by ":". Then on a new line for each field, you can specify the name, description, category, and dependencies (if any). + +For more information about how to create a module, including how to generate a manifest file and how to modify the manifest, see [Building a Hello World Module](Building-a-hello-world-module). + +## Theme Manifest Fields + +A theme manifest can have the following fields: + +Field Name | Description +----------- | ---------------------------------------------------- +Name | Provides a human-readable name for a theme that is an alternative to using the theme's ID. The ID of a theme is the name of the theme's folder in the virtual base path (the default virtual base path is _~/Themes_), and is used for programmatic references. For example, for a theme whose ID is `Orchard.Theme.Contoso`, you might provide a name in the manifest such as `Contoso Theme`. If you do not provide a name in the manifest, the ID is used instead. If you do provide a name, it will be used as the theme's display name in the gallery and in the Orchard UI. +Description | A brief summary of a theme's appearance and layout details. The description is used in the gallery and in the Orchard UI. +Version | The version number of a theme. The version information is displayed in the gallery and the Orchard UI, and is also used to determine whether an update is needed. +Author | The developer of a theme. This can be an organization, individual, or a list of individuals. +Website | The URL for the website of the theme developer. +Tags | A comma-separated lists of tags for the theme. The tags can be used to filter or group themes in a list. For example, a custom online gallery of themes can provide the ability to filter and display themes by tag. +Zones | A comma-separated list of the Orchard zones that are used by a theme. These zones are displayed in the Orchard dashboard and can be used to customize the layout of a site by adding, removing, or arranging widgets. +BaseTheme | The ID of another theme that this theme inherits from. This is an optional field. It is useful in cases where you want to customize an existing theme by copying it and then making some changes in style and appearance. When you use this approach, add the `BaseTheme` field to the manifest for the customized theme, and specify the `Id` of the base theme. For example, if you customized the Contoso theme, you could add the line `BaseTheme: Orchard.Theme.Contoso` to the manifest of your theme. + +The following example shows the manifest for **The Theme Machine** theme, which is the default Orchard theme. + + Name: The Theme Machine + Author: jowall, mibach, loudej, heskew + Description: Orchard Theme Machine is a flexible multi-zone theme that provides a solid foundation to build your site. It features 20 collapsible widget zones and is flexible enough to cover a wide range of layouts. + Version: 1.0.20 + Tags: Customize, Default + Website: http://orchardproject.net + Zones: Header, Navigation, Featured, BeforeMain, AsideFirst, Messages, BeforeContent, Content, AfterContent, AsideSecond, AfterMain, TripelFirst, TripelSecond, TripelThird, FooterQuadFirst, FooterQuadSecond, FooterQuadThird, FooterQuadFourth, Footer + + +For more information about how to write a theme, including how to generate and modify a manifest, see [Writing a New Theme](Writing-a-new-theme). For information about how to customize an existing theme and then generate a manifest for it, see [Customizing Themes](Customizing-the-default-theme). diff --git a/Documentation/Manually-installing-Orchard-zip-file.markdown b/Documentation/Manually-installing-Orchard-zip-file.markdown new file mode 100644 index 00000000..989102e7 --- /dev/null +++ b/Documentation/Manually-installing-Orchard-zip-file.markdown @@ -0,0 +1,83 @@ + +If you do not want to use the Microsoft Web Platform Installer to install Orchard, you can download a .zip file that contains everything you need to in order use Orchard. This topic shows the steps you need to perform to install Orchard using the .zip file. For information about using the Web Platform Installer, see [Installing Orchard](Installing-Orchard). + +> **Note**: If you plan to use Visual Studio 2010 to develop your Orchard site, we recommend that you install Visual Studio, and the ASP.NET MVC 3 Tool Update, before installing Orchard. If you plan to use WebMatrix to develop your site, you may want to see the topic [Installing Orchard](Installing-Orchard), which installs Orchard from the Web Platform Installer and includes WebMatrix in the installation. Also, if you previously installed pre-release versions of WebMatrix, ASP.NET Web Pages, or ASP.NET MVC 3, you must uninstall those or upgrade those products to the final release of each before Orchard will run correctly on your computer. + + + +# Downloading the .zip File + +Download the Orchard [.zip file](http://orchard.codeplex.com/releases/view/59918) from CodePlex. Select the **Orchard.Web.1.x.xx.zip** file for the latest build of Orchard, as shown in the following illustration: + +![](../Upload/screenshots/Install_downloadzip.png) + +The website is in the "Orchard" folder that's included in the .zip file. + +You can run your downloaded Orchard site using IIS, WebMatrix and IIS Express, or Visual Studio and the Visual Studio Development Server. The site has already been built and can be run without additional compilation. + +# Running the Site Using IIS + +To use IIS, extract the contents of the _Orchard_ folder from the .zip file to an IIS virtual directory (or site root), and then view the site using a browser. If you are using IIS 7, configure it to run in integrated mode, and configure the application pool to run the .NET Framework version 4. + +You might have to set read/write permissions for the account that is configured as the identity for the IIS application pool on the following folders: + +* _Modules_. This is required if you want to install modules from the gallery. (We recommend that you remove the read/write permissions for production sites.) +* _Themes_. This is required if you want to install themes from the gallery. (We recommend that you remove the read/write permissions for production sites.) +* _App_Data_. This folder is where Orchard stores site settings. +* _Media_. This folder is where Orchard stores media files (images, etc.). + +If you want to completely reset an Orchard site configuration to its default settings, you can delete the _App_Data_ directory. This removes all your custom settings, users, and configuration, as well as any custom data you have added to the site. If you delete the _App_Data_ folder, and if you want to remove custom images that you have added to the site, you can delete the _Media_ folder as well. + +# Running the Site Using WebMatrix and IIS Express + +To use WebMatrix and IIS Express, extract the Orchard .zip file to a local folder. Launch WebMatrix, and in the **Quick Start** screen, click **Site from Folder**. Navigate to the folder where you extracted the .zip file, select the folder named **Orchard**, and then click **Select Folder** to open the site. + +![](../Upload/screenshots_675/webmatrix_selectfolder_675.png) + +To run the site, in the WebMatrix **Files** workspace, select the root **Orchard** folder. Click the drop-down list in the **Run** button and then select a browser. + +![](../Upload/screenshots_675/webmatrix_run_orchard_675.png) + +# Running the Site Using Visual Studio and the Visual Studio Development Server + +To run the site in Visual Studio, extract the full source code .zip file to a local folder. Launch Visual Studio and select **File** > **Open** > **Project/Solution**. Navigate to the folder where you extracted the .zip and open the folder named **src**. Select the **Orchard.sln** solution file. + +![](../Attachments/Manually-installing-Orchard-zip-file/OpenSolution.PNG) + +To run the site, press Ctrl+F5. + +# Setting Up a Site + +When you first launch the Orchard site, you are presented with the Orchard setup screen: + +![](../Upload/screenshots/get_started_dialog_1.png) + +By default, Orchard includes a built-in database that you can use without installing a separate database server. However, if you are running SQL Server or SQL Server Express, you can configure Orchard to use either of those products instead by specifying a connection string. Optionally, you can enter a table prefix so that multiple Orchard installations can share the same database but keep their data separate. + +![](../Upload/screenshots_85/setup_sqlserver.png) + +The Orchard setup screen includes a section where you can choose an Orchard recipe. You can choose from the following Orchard recipes: + +* **Default**. Sets up a site with frequently used Orchard features. +* **Blog**. Sets up a site as a personal blog. +* **Core**. Sets up a site that has only the Orchard framework for development use. + +![](../Upload/screenshots/get_started_recipe.png) + +For information about recipes and how to make a custom recipe, see [Making a Web Site Recipe](http://orchardproject.net/docs/Making-a-Web-Site-Recipe.ashx). + +After you've entered the required information on the setup screen, click **Finish Setup**. When the setup process is complete, your new site's home page is displayed. + +![](../Upload/screenshots_675/Install_finished.png) + +You are now on the Orchard home page and can begin configuring your site. + + + +# Change History +* Updates for Orchard 1.1 + * 4-12-11: Updated screens for 1.1 installation. + * 3-14-11: Added section on using WebMatrix and IIS Express. + * 3-14-11: Added information about recipes in the setup screen. + * 3-15-11: Fixed the IIS section to use the Orchard subfolder from the zip. + diff --git a/Documentation/Media-management.markdown b/Documentation/Media-management.markdown new file mode 100644 index 00000000..9104c709 --- /dev/null +++ b/Documentation/Media-management.markdown @@ -0,0 +1,86 @@ + + +## Media storage +When storing media such as images, there are basically two choices: the file system or the database. + +### Database storage +The database storage has the advantage that it's relatively easier to set-up and to not require additional writing privileges. When media are attached to other database-bound objects such as a contents page, it also makes the management a little easier as the association between the object and the media it uses is explicit. On the other hand, such a structure also makes it more difficult to reuse media across objects. + +Database storage also provides great freedom to add arbitrary metadata and also handle multiple revisions, drafts, etc. + +To properly scale, a database storage for media will probably have to implement many features of a file system, which may be expensive to implement. + +From the end-user management perspective, the database is a black box. The web interface being the only way to explore the contents can be seen as a disadvantage. + +Uploading tools are also more constrained with a database storage: with the file system, any FTP tool can upload, in addition to web-based uploads. With database storage, only web uploads are possible. XML-RPC APIs such as the [Atom Publishing Protocol](http://tools.ietf.org/html/rfc5023) are appearing though, enabling media publishing from non-web-based tools. + +Another problem with the database storage is performance: IIS serves static files a lot faster than dynamic resources. + +### File system storage +Storing media in the file system looks like a natural choice. It makes it very easy to manage the files, even without using the application: open an FTP client, navigate to the contents/media folder and explore at will. + +File system storage also enables the application to associate content entities with the media they use by automatically creating folders with the entities' slugs but the association is less robust than with database storage: there is no reference integrity checks and it is possible to delete the media and end up with the dreaded red crosses in web pages. Similarly, if the content goes away and the media are not deleted, this might lead the media folder to slowly rot. + +Metadata can be managed in the database even if the media is in the file system, but that also leads to integrity problems. Metadata can also be managed with files next to the media files. Finally, most media formats support meta-data right in the media file. For example, photographic formats support EXIF data. Meta-data is best handled using the storage that the media format already provides, as the workflow that produces those media files already uses tools that understand native embedded meta-data formats. + +### File system or database? +That decision could actually be abstracted away by virtual path providers but those don't run in medium trust on .NET 3.5. Effectively, they will be abstracted away from the outside as they will be available through XML-RPC APIs. Without using virtual path providers, it is still possible to go with an abstraction, enabling for database storage even if our default implementation is the file system. + +As the default, we are implementing the file system storage, with a thin abstraction layer to still allow for alternative implementations and easier testing. + +## Scenarios + +### From the page editor, I can upload an image and insert it into a content zone +Users must be able to upload and use media in their contents without leaving the page editor. The goal of this scenario is that the online content editing experience is on par with the LiveWriter experience. + +In the case where JavaScript is enabled, a rich text editor is displayed in admin UI to edit contents. This rich-text editor will be extended to add an "Upload picture" button to the editor's toolbar. Pressing this button will bring an overlay dialog that contains a file upload field and an "Upload" button. The user would click "browse" on the upload field, would navigate to a file on his local hard drive, select it and then click OK to close the choose file dialog. He would then click "Upload". The image would then be uploaded, and on completion, would be automatically inserted into the contents being edited at the position of the caret. + +The location on the site where the media get uploaded would be similar to the case of LiveWriter post creation. That means in particular that a folder gets auto-created from the slug to contain the uploaded files. For a blog post, the uploading location could be: /media/\[slugOfMyBlog\]/\[SlugOfMyPost\]/\[ImageFileName\]\.\[extension \(jpg, png, etc\.\)\]. + +If an image with the same name already exists in the uploading folder, a number gets automatically appended to the file name to make it unique. + +> **Note:** Flow 1 below represents a non-JavaScript scenario for the same thing, which we won't implement at this time. + +### From the page editor, I can browse to an existing image and insert it into a content zone +See flow 2 below. Media can be reused across different pieces of contents. + +### I can manage the files on the site +See flow 2 below. Media management has its own specialized management UI. + +### When JavaScript is off, I can still upload an image and get its URL as a result, which I can use in an img tag +See flow 1 below. Embedding media in contents is easy with or without JavaScript. + +# Permissions + +In this context, owner means the media asset owner when acting on a specific asset, or the folder owner otherwise. + +> **Note:** Front-end viewing permissions for media are out of the scope of Orchard permissions because media are being served directly by IIS without intervention of the ASP.NET pipeline. Thus, the view permissions for media really are file-level permissions and should be managed at that level if the need arises. + +Default permissions are: + +Permission | Anon. | Authentic. | Owner | Admin. | Author | Editor +------------------------------------------------ | ----- | ---------- | ----- | ------ | ------ | ------ +Upload & manage media (modify/rename/delete) | No | No | Yes | Yes | Yes | Yes +Create and manage media folders | No | No | Yes | Yes | Yes | No + +## Flows + +### Flow 1: media uploading and embedding with JavaScript disabled from the page editor +![](../Attachments/media-management/2.1_s.png) +![](../Attachments/media-management/2.2_s.png) +![](../Attachments/media-management/2.3_s.png) +![](../Attachments/media-management/2.4_s.png) + +### Flow 2: media management +![](../Attachments/media-management/1_s.png) +![](../Attachments/media-management/2_s.png) +![](../Attachments/media-management/3_s.png) +![](../Attachments/media-management/4_s.png) +![](../Attachments/media-management/5_s.png) +![](../Attachments/media-management/6_s.png) +![](../Attachments/media-management/7_s.png) +![](../Attachments/media-management/8_s.png) +![](../Attachments/media-management/9_s.png) +![](../Attachments/media-management/10_s.png) +![](../Attachments/media-management/11_s.png) +![](../Attachments/media-management/12_s.png) diff --git a/Documentation/Moderating-comments.markdown b/Documentation/Moderating-comments.markdown new file mode 100644 index 00000000..8c27d495 --- /dev/null +++ b/Documentation/Moderating-comments.markdown @@ -0,0 +1,68 @@ + +The **Comments** feature of Orchard provides the ability to monitor and manage the comments for content items on your site. This topic describes two sets of tools that Orchard provides for working with site comments: tools for managing existing comments, and site-level settings for comments. + + +# Managing Comments + +To access the comment management screen, click **Comments** on the Orchard dashboard. + +![](../Upload/screenshots_675/comments_dashboard_manage_675.png) + +The **Comments** screen lists the comments across all content items in your site. It can also display a filtered list that shows all comments by administrative category ("pending", "approved", or "spam"). If you want to carry out a bulk administrative task that applies to many comments, select the comments you want, and then use the **Actions** drop-down list to apply an action such as **Approve** or **Unapprove**. + +> **Note** If you want to manage just the comments for a specific content item, such as a page or a blog post, edit the content item. In edit mode, there is an option to display and manage comments for that item. The screen for editing comments that are linked to a content item is identical to the **Comments** screen, except that it only shows comments from the specific content item. + +In the **Comments** screen, click **Edit** next to an approved comment. A screen for editing the comment is displayed. + +![](../Upload/screenshots_675/comments_editing_675.png) + +Click **Pending** to change the comment status, and then save the comment. Browse to your site and view the content item for which you changed the comment category to "pending". The pending comment is no longer visible. + +You can assign comments to the following categories: + +* **Pending**. The comment is pending administrator approval. The comment will not be visible to users unless an administrator marks it as "Approved". +* **Approved**. The comment is approved and will appear on the site. This is the default category for new comments unless you enable the site-level setting to require approval of all comments. (See the next section.) +* **Mark as spam**. The comment is spam and will not displayed. For more information, see the next section. + +# Setting Site-Level Comment Options + +Orchard provides two site-level features for comments: administrative approval of comments and spam protection. You can access both features by clicking **Settings > Comments** on the dashboard to open the screen for setting comment options. + +## Requiring Approval for Comments + +You might want to require moderator approval of comments before they become visible on the site. As the previous illustration for editing comments shows, by default, comments are approved and visible. However, if you enable the site-level setting to require approval of comments, new comments will default to the "pending" category and will not be displayed until they are approved. + +To require approval of comments, click **Settings > Comments** in the dashboard. A screen appears for managing site-level comment settings. + +![](../Upload/screenshots_675/comments_sitewide_settings_675.png) + +Select **Comments must be approved before they appear** and then save the settings. After you have enabled this setting, you will need to review all new user comments in the **Comments** screen, and for the comments that you want to allow on the site, change their status from "pending" to "approved". + +## Enabling Spam Protection + +The spam-protection feature helps to automatically categorize certain comments as spam so that you can prevent them from being displayed in your site. + +To implement spam protection, Orchard uses [Akismet spam protection](http://akismet.com/), which reviews comments as they are posted. When Akismet detects a comment that fits the criteria for spam, it automatically assigns it to the **Mark as spam** category. + +To enable the Akismet spam protection feature on a site, do the following: + +* Obtain an Akismet key from [Akismet.com](http://akismet.com/). +* Click **Settings > Comments** on the dashboard and then select **Enable spam protection**. +* Enter your Akismet key in the field. +* Add the URL of your Orchard site (the text box calls it your **Blog URL** but you can use your site URL). +* Save the updated setting. + +![](../Upload/screenshots_675/comments_sitewide_settings_2_675.png) + +After you enable spam protection in your site, you can use the **Comments** screen described earlier to select the comments that are marked as spam, review them, and delete the comments that really are spam. + + + + + +# Change History +* Updates for Orchard 1.1 + * 3-28-11: Updated existing screens, added new step showing how to require pre-approval of comments. + + + diff --git a/Documentation/Modifying-site-settings.markdown b/Documentation/Modifying-site-settings.markdown new file mode 100644 index 00000000..ed26f517 --- /dev/null +++ b/Documentation/Modifying-site-settings.markdown @@ -0,0 +1,80 @@ + +You can configure the general, global, and feature-specific settings for your site in the **Settings** panel (the menu items contained in the **Settings** section) of the Orchard dashboard. This topic describes these site-level settings. + +In the **Settings** panel in the dashboard, the settings are arranged into categories, including **General**, **Gallery**, **Comments**, **Media**, and **Users**. + +![](../Upload/screenshots/dashboard_sitewide_settings.png) + + +## General Settings +To access general settings, click **General** in the **Settings** panel. This opens the following screen: + +> **Note** The general settings screen also displays options that are specific to the features that are enabled for your site. + +![](../Upload/screenshots_675/manage_general_settings_675.png) + +In the general settings category, you can modify the following global and site-wide settings: + +* **Site Name**. The name of your site, which is usually displayed by the applied theme. +* **Default Site Culture**. The default culture for the site. You can also add culture codes here. For more information, see [Creating Global-Ready Applications](Creating-global-ready-applications). +* **Page title separator**. The character that is used to separate sections of a page title. For example, the default separator character for the `en-US` locale is a hyphen (-). +* **Super user**. A user who has administrative capability on the site, regardless of configured roles. This is usually the user who ran the Orchard installation and setup. The default user is the admin account. +* **Resource Debug Mode**. The mode that determines whether scripts and style sheets are loaded in a "debuggable" form or in their minimal form. +* **Default number of items per page**. On pages that can show multiple items (like a blog page with blog posts), the default number of items that are shown per page. +* **Base URL**. The base URL for your site. + +## Gallery Settings +To access settings for the gallery, click **Gallery** in the **Settings** panel. This opens the following screen: + +![](../Upload/screenshots_675/manage_gallery_feed_settings_675.png) + +In the gallery feed settings, you can add or delete a feed using the following settings: + +* **Add Feed**. Lets you specify the URL to a gallery feed. +* **Delete**. Lets you remove an existing gallery feed. + +For more information about how to add feeds to the gallery, see [Registering Additional Gallery Feeds](Module gallery feeds). + +## Comments Settings +To access settings for comments, click **Comments** in the **Settings** panel. This opens the following screen: + +![](../Upload/screenshots_675/manage_site_comments_settings_675.png) + +In the comments settings, you can enable or disable the following features: + +* **Comments must be approved before they appear**. Requires user comments to be approved by an administrator or moderator before they become visible on the site. +* **Enable spam protection**. Automatically identifies spam comments and marks them for your review. + +For more information about how to work with comments, see [Moderating Comments](Moderating-comments). + +## Media Settings +To access settings for what types of files can be uploaded on a site, click **Media** in the **Settings** panel. This opens the following screen: + +![](../Upload/screenshots_675/manage_site_media_extensions_675.png) + +In the media settings, you can specify the following options: + +* **Media**. A space-delimited list of file extensions that can be uploaded (for example, `jpeg gif png txt doc docx xls xlsx`). Do not include a dot (.) as part of the extension. + +## User Settings +To access user settings, click **Users** in the **Settings** panel. This opens the following screen: + +![](../Upload/screenshots_675/manage_site_user_settings_675.png) + +In the user settings, you can enable or disable the following settings in order to customize user registration: + +* **Users can create new accounts on the site**. Configures the site to let users create a new account. +* **Display a link to enable users to reset their password**. Provides users with a way to reset their password. +* **Users must verify their email address**. Requires users to confirm their email address during registration. +* **Users must be approved before they can log in**. Requires administrative approval of new accounts before users can log in. + + + + + +# Change History + +* Updates for Orchard 1.1 + * 3-29-11: Added sections for new screens in the dashboard. Updated existing screen shots. + + diff --git a/Documentation/Module-from-vs.markdown b/Documentation/Module-from-vs.markdown new file mode 100644 index 00000000..e69de29b diff --git a/Documentation/Module-gallery-feeds.markdown b/Documentation/Module-gallery-feeds.markdown new file mode 100644 index 00000000..a8ca23d6 --- /dev/null +++ b/Documentation/Module-gallery-feeds.markdown @@ -0,0 +1,32 @@ + +To facilitate sharing of modules and themes, Orchard lets you register gallery feeds. When gallery feeds are registered in an Orchard site, you can browse, install, or download the available modules and themes from the feeds by using the Orchard dashboard. This topic shows you how to register new gallery feeds and remove existing feeds from an Orchard site. + +To see the gallery feed registration screen, expand the dashboard **Settings** section and then click **Gallery**. + +![](../Upload/screenshots/dashboard_gallery_feeds.png) + +The **Gallery Feeds** screen displays currently registered feeds. + +![](../Upload/screenshots_675/gallery_registered_feeds_675.png) + +As the illustration shows, by default an Orchard site provides a single registered gallery feed from [http://orchardproject.net/gallery/server/FeedService.svc](http://orchardproject.net/gallery/server/FeedService.svc/Packages). You can add feeds or delete existing feeds. + +To register an additional feed, click the **Add Feed** button. + +In the **Add a Feed** screen, enter a URL and then click **Add Feed**. + +![](../Upload/screenshots_675/gallery_RegisterNewFeed_screen_675.png) + +> **Note** For information about publishing a module or theme to the default Orchard gallery feed, visit the [gallery website](http://orchardproject.net/gallery). To learn how to create and expose a custom gallery of themes or modules, see the reference implementation of a gallery website at [OrchardGallery.CodePlex.com](http://orchardgallery.codeplex.com) and [GalleryServer.CodePlex.com](http://galleryserver.codeplex.com). + +To view the contents of a feed in your browser, click the feed link in the **Gallery Feeds** screen. (If you are using Internet Explorer and it renders the gallery instead of displaying the feed contents, go to **Internet Options** and turn off the feed-reading feature.) + +![](../Upload/screenshots_675/feed_detailsfiles_675.png) + + + + + +# Change History +* Updates for Orchard 1.1 + * 3-23-11: Updated screens and UI options for registering feeds. diff --git a/Documentation/Navigation-and-menus.markdown b/Documentation/Navigation-and-menus.markdown new file mode 100644 index 00000000..04358271 --- /dev/null +++ b/Documentation/Navigation-and-menus.markdown @@ -0,0 +1,15 @@ + +Orchard currently has a very simple main menu feature that is a list of menu item text and links to display, accessible from the **Navigation** link in the Orchard admin panel. When you add an item to the main menu using the page or blog post editor screens, a new entry is added here. You can use this screen to rename, reorder, and remove menu items. (This will not delete the content item; it will only remove the menu item). + +![](../Upload/screenshots_675/manage_menu_675.png) + +You can also add arbitrary URLs in your menu, whether external or pointing to a page in your Orchard site, by adding a new menu item. Note that only items added in this way have an editable URL on this screen. Content item URLs must be edited from the editor screen for that content item instead. + +To reorder menu items, type a numeric index in the "Position" textbox. Position indexes can be any of the following format: + +* **Integer**: 1, 2, 3, etc. +* **Decimal**: 1.1, 1.2, 1.3, etc +* **Multi-part number**: 1.1.1, 1.2.1, 1.2.2, etc + +When you are satisfied with your changes, click **Update All** to update the main menu of your site (effective immediately). + diff --git a/Documentation/Navigation.markdown b/Documentation/Navigation.markdown new file mode 100644 index 00000000..1da18435 --- /dev/null +++ b/Documentation/Navigation.markdown @@ -0,0 +1,80 @@ + +Navigation and search are an essential part of CMS applications. This specification aims at defining the default navigation menu generation experience. + + +# Scenarios + +#### The application contains one main menu by default +The application comes preconfigured with one static menu that is present in the header include of the default templates. + +> The current implementation only allows one global flat menu for the whole site. + +#### A menu item consists of a name, description, and target route/url +The name and description can have their default values extracted from the object being pointed to if available, and can be overridden on the menu item. + +The choice of the target route or URL is made through a URL editor that should eventually become standard and shared for other components to use (for the moment it's just a textbox with validation). + +Menu items can either point to a statically determined URL, or they can be attached to a routable content item, in which case the URL is not editable but is instead provided by the item's routable aspect. + +#### An administrator can manage the set of menus and menu items from the application's admin panel + +> The application currently supports only one menu, without support for nested menus. + +The administrator can create new named menus and modify or delete existing ones. + +An administrator can add, enable/disable, reorder, nest and delete menu items within a menu. + +#### The main menu display is determined by a menu template included in the header template, so the markup is customizable by a theme author + +Displaying the menu is done by including a partial view and giving it a specific named menu as the model. That partial view can be modified and overridden by themes. + +> In the current implementation, there is only one menu, and the partial view is simply named menu.ascx. + +#### The application may optionally contain one or more sub-menus to be displayed within application sidebar zones + +Those "sub-menus" actually are other named menus. Until we build widgets, these other menus will have to be manually added to templates. + +> Not implemented. + +#### A navigation menu displays contextual links for every content item + +Such a dynamic menu may be implemented as a helper API that asks all content providers to give parents, children (optionally hierarchical to a specified depth) and siblings from a given content item. The results of this call could then get rendered by a partial view using it as the model. + +> Not implemented. + +#### A user can choose to add a page or post to a menu as part of the page/post editing interface + +This should be on by default for pages, off by default for posts. + +The UI to add an item to a menu consists of a checkbox ("Included in navigation menu") and a name textbox that is pre-filled by default with the title of the item. + +#### A menu widget can be configured to display the contents of a menu + +See Widgets section for more detail. This is essentially the same scenario as above, except that the partial view is encapsulated into a widget. Will be implemented when the widget infrastructure exists. + +> Not implemented. + +#### The menu widget may be configured to show a static or dynamic set of items + +The dynamic behavior is to display only the parent/children of the currently displayed item. + +> Not implemented. Only one static menu at the moment. + +#### The main menu and menu widget have progressive expand/collapse behavior + +The menu widget has a setting for the depth at which it represents the site hierarchy. When JavaScript is not enabled, the sub-menus have a statically defined CSS class that hides them (the downlevel experience could actually be CSS dynamic menus). When JavaScript is enabled, better expansion logic can be added, using a jQuery plug-in preferably (developing a complete JavaScript menu is not a trivial task and could become a project in itself. We should concentrate first on the core scenario). + +> Not implemented. + +#### The application exposes an API for accessing menus and menu items that can be called from user code in a template/view + +The API that asks content providers to contribute menu hierarchies knowing the current item could also take a menu name. This way, the "static" named menus could just be a special, default case of dynamic menus. + +> Not implemented. + +# Permissions +The owner in this context is the site owner. + +Permission | Anon. | Authentic. | Owner | Admin. | Author | Editor +---------------------- | ----- | ---------- | ----- | ------ | ------ | ------ +Manage navigation menu | No | No | Yes | Yes | No | No diff --git a/Documentation/Optimizing-Performance-of-Orchard-with-Shared-Hosting.markdown b/Documentation/Optimizing-Performance-of-Orchard-with-Shared-Hosting.markdown new file mode 100644 index 00000000..a3f9f96b --- /dev/null +++ b/Documentation/Optimizing-Performance-of-Orchard-with-Shared-Hosting.markdown @@ -0,0 +1,96 @@ + +This topic discusses various techniques for tuning a server environment to run Orchard efficiently. The optimal configuration depends on the type of site you're running and on usage patterns, so site administrators should pick from this list what applies best to their particular scenario. As always, improving performance should involve measuring and analyzing performance data so that changes you propose are demonstrably beneficial. + + +# Trust Level + +Orchard is configured out of the box to run in Medium trust. This was accomplished using techniques that sometimes affect performance. In particular, there are cases that result in exceptions being thrown under normal application operation. + +For those reasons, if you can run Orchard under Full trust, you are almost certain to get a performance boost out of it. You can switch to full trust by editing the _Orchard.Web/web.config_ file and making the following change: + + + + + +# Debug/Release + +On your production server, there is no reason to run in debug mode. Make sure that the application you deployed was compiled in release mode and that the _web.config_ file in _Orchard.Web_ specifies release mode: + + + + + +# Shared Versus Dedicated Versus Cloud Hosting + +## Shared Hosting + +Shared hosting environments usually consist of web farms with load-balancing. The way this is implemented varies greatly between hosting companies and it is usually difficult for customers to get information on the specific configuration being used. How well these configurations perform depends on the load on hosted applications and on the architecture of the application itself. + +Shared hosting is a nice solution for Orchard users on a budget, but there can be tradeoffs. There is a natural contention between the customer who wants his or her site to be immediately available and to run as fast as possible, and the hosting company that wants to support as many sites as possible on a single computer. In order improve site density, hosting companies can be very aggressive about app domain recycling, causing sites to shut down often if they are not accessed frequently or if they consume too much memory. + +There are mitigations for these situations, such as using a pinging service or a module that accesses the site on a fixed interval to prevent the app domain from shutting down due to a timeout. A mitigation like this might seem like a good idea, but ultimately it ruins the site density objective and penalizes everyone. + +Another mitigation is to improve the perceived startup time of the application so that a shutdown ceases to be a significant problem. The `Orchard.Warmup` module (new in Orchard 1.1) is a good way to make the most commonly accessed pages of your site immediately accessible even while the app domain is restarting. + +Hosting companies can optimize for Orchard by setting up machine affinity so that a given instance always runs on the same server. This can in turn enable the local file system to be used rather than a network appliance. This can make a real difference, because Orchard can make a heavy use of the file system, such as when performing dynamic compilation or when using SQL Server Compact databases. + +## Dedicated Hosting + +A dedicated hosting environment is typically more expensive than a shared hosting account, but it might be worth the investment if your business depends on your application responding immediately to any request. A dedicated computer or a dedicated virtual machine offers the advantage of being configurable in exactly the way you want. You get guaranteed processing and bandwidth instead of sharing it with a varying load on other applications running on the same computer, and you get the opportunity to fine-tune all the parameters for the application. + +## Cloud Hosting + +Cloud hosting such as Microsoft Azure offers most of the advantages of dedicated hosting plus the ability to scale to increased loads with the flip of a switch. If you are building a business that is expected to grow considerably, this might be the most secure way of ensuring the scalability that you need. + +# SQL Server Compact Versus SQL Server + +An Orchard instance can either run on SQL Server Compact or on full versions of SQL Server or SQL Server Express. SQL Server Compact is an embedded version of SQL Server that has the advantage of being deployable by simply copying its DLLs and database files. + +While SQL Server Compact is extremely lightweight and easy to use and deploy, full versions of SQL Server offer the guaranteed performance that you might need on your site. It might therefore be worth the cost of investing in a hosting solution that gives you access to a full edition of SQL Server. + +# File System + +The file system itself can be a drag on application performance. Possible bottlenecks can include a fragmented file system or a congested network connection to a NAS. Checking the speed of the file system and then optimizing it can be a way to get better performance. + +# Memory + +The more memory is available on a server, the better it will perform. If you can afford it, increasing memory might be among the most efficient ways of improving performance (assuming it's properly configured). Increasing processing power is more expensive and often has a lower return on investment. + +# App Pool Recycling + +If you have access to IIS settings and if your site has few hits over extended periods of time, consider increasing the default value for app pool recycling. This can be done by going into IIS Manager, going to **Application Pools**, selecting the app pool for your application, and clicking **Recycling**: + +![](../Attachments/Optimizing-Performance-of-Orchard-with-Shared-Hosting/AppPoolRecycle.PNG) + +Removing the timeout is generally a good idea if it is replaced by a limit on memory usage; recycling at an arbitrary interval has little benefit, whereas recycling if the application uses all available memory is a good practice. + +# Multi-Tenancy + +Orchard has an optional module called **Multi Tenancy** that enables more than one site to exist on the same Orchard instance. The data for the sites is separated, and for all practical purposes they are distinct sites. There are a few limitations on what each tenant can do, such as installing new modules and themes. + +The advantage of a multi-tenant installation over multiple instances of Orchard is that there is only one app domain, which hosting companies favor because it improves site density considerably. It also has advantages for each of the multi-tenant sites, because a hit on any of the tenants keeps the app domain alive. Therefore, even sites that receive very few hits will remain responsive if they share the app domain with enough other sites. + +This results in the seemingly paradoxical notion that more sites on a single app domain might perform better in some cases than a single site per app domain. In shared hosting scenarios in particular, this configuration is optimal if it is an option. + +# Installed Modules + +For both security and performance reasons, it's a good idea to keep the number of modules installed on your production server as low as compatible with your application. There's a cost to anything you add to the system, in particular in terms of dynamic compilation and loading additional assemblies. + +If you are not using a module, it should be removed. Some modules, such as the gallery, will be useful on your development server but probably not on your production server and should be removed. + +Going even further, some modules are a convenience that you might want to do without. For example, many modules do nothing more than render a pre-formatted bit of HTML to include some external script or embedded object. If so, it's a good to determine whether you couldn't achieve the same thing with an HTML widget or the body of content items by going into the HTML source and directly injecting HTML there. + +# Depth of the Views Folders + +The contents of _Views_ folders are dynamically compiled and there is some overhead associated with each subfolder. This, combined with the multiplication of modules in a typical Orchard instance, means that it can have an impact on startup performance to flatten _Views_ directories. Orchard gives a choice to module and theme authors to use subfolders or equivalent dotted names for templates (see [Accessing and Rendering Shapes](Accessing-and-rendering-shapes)). It is generally preferable to use the dotted notation. + +# IPv6, Development Servers, and Modern Browsers + +If you are in an IPv6 environment and using a local development server such as the Visual Studio Development Server or IIS Express in WebMatrix, some browsers may have trouble handling more than one request at once. This results in slower performance because resources are fetched one after the other. If you are testing locally and see images appearing one by one, you are probably hitting this bug. + +An easy workaround is to use `127.0.0.1` instead of `localhost` as the domain for the development server. Another is to disable IPv6 in the browser, although this change can have side effects. A third workaround is to make sure there's an explicit entry for `localhost` in your HOSTS file. + +# Future Perspectives + +The Orchard team is planning more work for performance in the future. This might include versions of the core assemblies and main dependencies that can be put into the GAC as well as NGen optimizations. diff --git a/Documentation/Orchard-Markup-Guidelines.markdown b/Documentation/Orchard-Markup-Guidelines.markdown new file mode 100644 index 00000000..82638a16 --- /dev/null +++ b/Documentation/Orchard-Markup-Guidelines.markdown @@ -0,0 +1,97 @@ + +## Supported Browsers + +All templates will be tested against and support the following browsers. For Internet Explorer 6 and below, we will strive to ensure the site and templates remain functional, but will not put effort into resolving any rendering issues that does not affect the ability for the user to consume the content. + +* IE7+ +* Chrome 5+ +* Firefox 3.5+ +* Safari 4+ +* Opera 10+ + +## File Names + +The following rules should be observed when naming files: + +* **Include files** will use "_" at the beginnings +* All **cshtml, vbhtml, HTML and CSS** files should be named using camel case. + +**Examples:** BlogPage.vbhtml, APageWithAReallyLongName.cshtml, About.html, Style.css + +## HTML Doctype + +We will standardize on the HTML5 doctype as it allows the use of HTML5 markup while being compatible with existing content that applies to HTML 4.01 and XHTML. + + + +## Tags + +In addition to all non- deprecated HTML4 tags, you may optionally use all the "New Elements" tags listed in section 3.1 as specified at which allow progressive enhancement in all browsers. + +The following are common new elements have been introduced for better structure: + +* `
` Section represents a generic document or application section. It can be used together with the h1, h2, h3, h4, h5, and h6 elements to indicate the document structure. +* `
` Article represents an independent piece of content of a document, such as a blog entry or newspaper article. +* `