[change Menu to NavBar Jeremy Shaw **20130212204345 Ignore-this: 7c3a1223c451ab34f4f0365171957741 ] move ./clckwrks-plugin-page/Clckwrks/Page/MenuCallback.hs ./clckwrks-plugin-page/Clckwrks/Page/NavBarCallback.hs move ./clckwrks/Clckwrks/Menu ./clckwrks/Clckwrks/NavBar move ./clckwrks/Clckwrks/NavBar/EditMenu.hs ./clckwrks/Clckwrks/NavBar/EditNavBar.hs hunk ./README.html 1 - -happstack-lite tutorial -

Clckwrks

- -

Installing and Testing clckwrks

- -

There are three cabal project directories:

- -

clckwrks - contains the core clckwrks server code -clckwrks-theme-basic - an example clckwrks theme -clckwrks-dot-com - source for the (future) clckwrks.com website

- -

To run this demo you will also need the follow javascript libraries:

- -

jquery - jquery-ui - json2 - jstree

- -

The first two can be installed via apt-get:

- -
$ apt-get install libjs-jquery libjs-jquery-ui
-
- -

The last two can be installed by running 'make' it the top-level directory.

- -

You will also need to install the binaries:

- -

HsColour - markdown

- -

These can be installed via:

- -
$ apt-get install markdown HsColour
-
- -

The demo clckwrks server can be built statically or with dynamic plugins enabled.

- -

Static clckwrks-dot-com

- -

To build the server statically run 'cabal install' in clckwrks, clckwrks-theme-basic, and finally clckwrk-dot-com.

- -

The clckwrks-dot-com is currently configured to be run from the clckwrks-dot-com directory. So to run the server do:

- -
cd clckwrks-dot-com
-./dist/build/clckwrks-server/clckwrks-server
-
- -

It should print out:

- -
Static Server Started.
-
- -

You can then point your browser at: http://localhost:8000/

- -

Dynamic clckwrks-dot-com

- -

To use plugins to load the theme file you need only install clckwrks. Then do the following:

- -
cd clckwrks-dot-com    
-ln -sf ../clckwrks-theme-basic/Theme .
-runhaskell Setup clean
-runhaskell Setup configure --user -fplugins
-runhaskell Setup build
-./dist/build/clckwrks-server/clckwrks-server
-
- -

It should print out:

- -
Dynamic Server Started.
-
- -

Now if you edit Theme.Home and reload the homepage, you should see your changes reflected. It may take a second or two for the changes to appear.

- -

Note that symbolic link is needed due to the plugins-auto not handling include directories very well. So, we create a symlink as a work-around.

- -

A tour of the web-site

- -

When you first open the site, there should be a big blue box and under it there are three columns which say, "Invalid PageId x".

- -

Those columns are supposed to show previews of the 2nd, 3rd, and 4th pages. But those pages have not been created yet.

- -

So, click on 'admin' to get to the admin console. (in theory, you need to login first, but that is currently not hooked up).

- -

Next click on 'Create New Page'.

- -

The body of the page is processed usThe code is ing markdown. The syntax for markdown is here:

- -

http://daringfireball.net/projects/markdown/syntax

- -

markdown allows you to insert arbitrary HTML as well. So you can either just write some simple text, or you can go nuts with HTML.

- -

If you check the 'Highlight Haskell code with HsColour' option, then you can use bird-notation (aka, >) and include literate Haskell which will be colored using HsColour.

- -

After you click 'update' you should be taken to a view of the page you just created. Notice that the menu on the left has been updated to include the newly created page.

- -

If you now click 'This title rocks!' you should be taken back to the homepage. You will see that the first column now contains a preview of page 2.

- -

If you click on 'admin' again. And then 'this title rocks'. You can edit the title of the page and change it to 'Home'.

- -

In the admin console there is also an 'Edit Menu' feature. This feature is currently incomplete and does not work. It allows you to interactively create and organize the menu.

- -

A tour of the code

- -

Looking at the code, we see it is divided into three packages: clckwrks, clckwrks-theme-basic, and clckwrks-dot-com.

- -

clckwrks

- -

A majority of the code lives in clckwrks. As an end-user, you would install this library, but never need to modify the code in it. It contains all the codefor the core features.

- -

clckwrks-theme-basic

- -

clckwrks-theme-basic is a theme package. Themes conform to a simple theme API so that you can easily swap out one for another. Themes are designed so that they could be distributed as .tar.gz bundles. Switching to a different theme should not require any code changes.

- -

For the static server, you would just edit the clckwrks-dot-com.cabal and change clckwrks-theme-basic to clckwrks-theme-awesome.

- -

For the dynamic server you currently need to edit clckwrksConfig and change the path to the theme. But ultimately, that is a value that you would change via the admin console. I envision that you would be able to go to the theme store, and one-click install and activate new themes.

- -

A typical clckwrks user may never look inside, create, or edit a theme bundle. They could just use the prepackaged themes from the site.

- -

Theme designers, on the other hand would need to know how to modify the theme files. So, let's look briefly at the structure.

- -

Right now the theme API is simple. The theme should provide the follow modules: -page :: XMLGenT (Clck ClckURL) XML -Theme.Home -Theme.Page

- -

which export a function:

- -

page :: XMLGenT (Clck ClckURL) XML

- -

any assets such as .css, .jpgs, etc should go in the 'data' directory.

- -

Looking at Theme/Page.hs we see that it tries hard to look like a normal HTML template. There is a bit of noise at the top of the file that would be nice to reduce/simplify.

- -

The Clckwrks module exports a ton of stuff so that you do not need a bunch of imports.

- -

Looking at the template we see that it is primarily html, with some simple calls to fill in content such as: getPageTitle and getPageContent. Those functions come from the clckwrks modules such as Page.API. The .API modules are supposed to provide a friendly interface for template designers to use.

- -

The internal URLs use web-routes.

- -

Looking at this template, it seems like it should be easy for template designers to do there thing with out having to have much understanding of Haskell.

- -

Obviously, the big hang-up is the error messages that you can encounter while using HSP. As Niklas mentioned in this thread:

- -

https://groups.google.com/group/haskell-server-pages/browse_thread/thread/1b136c7acb448136

- -

There is a long-term plan for addressing that.

- -

Looking at the Theme.Home file, we see a slightly more advanced template that uses a helper function summaryBox.

- -

Hopefully the themes are simple enough that end users can modify an existing theme with out really having to learn any Haskell.

- -

clckwrks-plugin-media

- -

One of the most valuable aspects of Clckwrks is the ability to extend it through the use of plugins. The clckwrks-plugin-media adds a media gallery. You can upload images, including them in post, and (eventually) create galleries and slideshows.

- -

plugins can also hook into the markup engine and add new markup commands. For example, in a post you could write:

- -
Check out this great photo I took: {media|id=1}
-
- -

And when the page is rendered, the image with id 1 will automatically be included in the message.

- -

clckwrks-dot-com

- -

This is where we tie it all together. There are only two files so far.

- -
Main.hs
-PageMapper.hs
-
- -

Main.hs is a bit scary looking due to the CPP code to select between static and dynamic mode. But there is really not much code there. Basically we create a ClckwrksConfig and then call simpleClckwrks to start the server.

- -

The static code path just imports the PageMapper.hs directly and calls pageMapper. The dynamic code path imports that symbol via withMonadIOFile.

- -

It would be nice to hide some of that ugliness away because it is pretty much boiler-plate. The tricky part is that we don't want to link against plugins-auto at all when building the static server. The current solution is the obvious way to do that. But, hopefully, not the best.

- -

PageMapper.hs just contains a simple function pageMapper. The purpose of this function is to allow you to specify different page templates for specific pages. For example, we see that PageId 1 will use Home.page and all the other pages will use Page.page.

- -

If you comment out the (PageId 1) you will see that the bluebox disappears from the home page. If you are using the dynamic server, you can comment that line out and refresh the page and it should be automatically recompiled/reloaded. If you are using the static server, then you will need to rebuild to see the changes.

- -

If you are using the dynamic server and have created the symlink, you could also edit the Theme.Home or Theme.Page templates and see the changes reflected after a short delay.

- -

Beyond simpleClckwrks

- -

The simpleClckwrks entry point is good if you just want a simple wordpress-like site. But, clckwrks is also designed to be integrated into a more sophisticated site such as patch-tag.com.

- -

An example is forth-coming. The essence is that you would create a new URL type for your site which embeds ClckURL:

- -
data MySite = C ClckURL
-            | Home
-            | Foo
-
- -

And then in your routing function you would call routeClck for the ClckURL case.

- -

clckwrks-cli

- -

The clckwrks-cli app provides a command-line interface which communications with a running clckwrks app to perform various administrative features. Right now the only feature it has is the ability to make UserId 1 an Administrator.

- -

TODO

- -

There is clearly a bunch of stuff left to do including:

- - - -

And then there are a bunch of add-on modules that would be great to have such as:

- - - rmfile ./README.html hunk ./README.md 3 -## Installing and Testing clckwrks +Clckwrks is a modular platform for building web sites and web +applications. It provides a simple core which can be extended using a +variety of plugins and themes. Ultimately, it will be possible to +install plugins and themes via the web interface with zero programming +knowledge. hunk ./README.md 9 -There are three cabal project directories: +The set of currently available plugins make clckwrks suitable for +creating a blogging or CMS system. New functionality can be added by +creating additional plugins. hunk ./README.md 13 -clckwrks - contains the core clckwrks server code -clckwrks-theme-basic - an example clckwrks theme -clckwrks-dot-com - source for the (future) clckwrks.com website +Clckwrks has the hooks in place to support dynamic loading of plugins +and themes. But, the higher-level functionality for interfacing with +cabal is not yet implemented. hunk ./README.md 17 -To run this demo you will also need the follow javascript libraries: +At present, Clckwrks still requires some degree of Haskell knowledge. hunk ./README.md 19 - jquery - jquery-ui - json2 - jstree +More information can be found at: hunk ./README.md 21 -The first two can be installed via apt-get: +[http://www.clckwrks.com/](http://www.clckwrks.com) hunk ./README.md 23 - $ apt-get install libjs-jquery libjs-jquery-ui +## Recent Changes ## hunk ./README.md 25 -The last two can be installed by running 'make' it the top-level directory. +### 0.15.0 ### hunk ./README.md 27 -You will also need to install the binaries: +We have made several large changes in this release: hunk ./README.md 29 - HsColour - markdown + 1. We have split the blogging/CMS functionality into a new package, `clckwrks-plugin-page`. hunk ./README.md 31 -These can be installed via: + 2. We have also revamped the menu (navbar) editor system. hunk ./README.md 33 - $ apt-get install markdown HsColour + 3. We now use bootstrap for the theming of internal admin menus hunk ./README.md 35 -The demo clckwrks server can be built statically or with dynamic plugins enabled. + 4. settings menu entries are now marked with Role-based visiblity settings hunk ./README.md 37 -### Static clckwrks-dot-com +These changes greatly improve the code base. But, there are some caveats. hunk ./README.md 39 -To build the server statically run 'cabal install' in clckwrks, clckwrks-theme-basic, and finally clckwrk-dot-com. + 1. the new navbar system is incompatible with the old system. hunk ./README.md 41 -The clckwrks-dot-com is currently configured to be run from the clckwrks-dot-com directory. So to run the server do: - - cd clckwrks-dot-com - ./dist/build/clckwrks-server/clckwrks-server - -It should print out: - - Static Server Started. - -You can then point your browser at: http://localhost:8000/ - -### Dynamic clckwrks-dot-com - -To use plugins to load the theme file you need only install clckwrks. Then do the following: - - cd clckwrks-dot-com - ln -sf ../clckwrks-theme-basic/Theme . - runhaskell Setup clean - runhaskell Setup configure --user -fplugins - runhaskell Setup build - ./dist/build/clckwrks-server/clckwrks-server - -It should print out: - - Dynamic Server Started. - -Now if you edit Theme.Home and reload the homepage, you should see your changes reflected. It may take a second or two for the changes to appear. - -Note that symbolic link is needed due to the plugins-auto not handling include directories very well. So, we create a symlink as a work-around. - -## A tour of the web-site - -When you first open the site, there should be a big blue box and under it there are three columns which say, "Invalid PageId x". - -Those columns are supposed to show previews of the 2nd, 3rd, and 4th pages. But those pages have not been created yet. - -So, click on 'admin' to get to the admin console. (in theory, you need to login first, but that is currently not hooked up). - -Next click on 'Create New Page'. - -The body of the page is processed usThe code is ing markdown. The syntax for markdown is here: - -http://daringfireball.net/projects/markdown/syntax - -markdown allows you to insert arbitrary HTML as well. So you can either just write some simple text, or you can go nuts with HTML. - -If you check the 'Highlight Haskell code with HsColour' option, then you can use bird-notation (aka, >) and include literate Haskell which will be colored using HsColour. - -After you click 'update' you should be taken to a view of the page you just created. Notice that the menu on the left has been updated to include the newly created page. - -If you now click 'This title rocks!' you should be taken back to the homepage. You will see that the first column now contains a preview of page 2. - -If you click on 'admin' again. And then 'this title rocks'. You can edit the title of the page and change it to 'Home'. - -In the admin console there is also an 'Edit Menu' feature. This feature is currently incomplete and does not work. It allows you to interactively create and organize the menu. - -## A tour of the code - -Looking at the code, we see it is divided into three packages: clckwrks, clckwrks-theme-basic, and clckwrks-dot-com. - -### clckwrks - -A majority of the code lives in clckwrks. As an end-user, you would install this library, but never need to modify the code in it. It contains all the code for the core features. - -### clckwrks-theme-basic - -clckwrks-theme-basic is a theme package. Themes conform to a simple theme API so that you can easily swap out one for another. Themes are designed so that they could be distributed as .tar.gz bundles. Switching to a different theme should not require any code changes. - -For the static server, you would just edit the clckwrks-dot-com.cabal and change clckwrks-theme-basic to clckwrks-theme-awesome. - -For the dynamic server you currently need to edit `clckwrksConfig` and change the path to the theme. But ultimately, that is a value that you would change via the admin console. I envision that you would be able to go to the theme store, and one-click install and activate new themes. - -A typical clckwrks user may never look inside, create, or edit a theme bundle. They could just use the prepackaged themes from the site. - -Theme designers, on the other hand would need to know how to modify the theme files. So, let's look briefly at the structure. - -Right now the theme API is simple. The theme should provide the follow modules: -page :: XMLGenT (Clck ClckURL) XML -Theme.Home -Theme.Page - -which export a function: - -page :: XMLGenT (Clck ClckURL) XML - -any assets such as .css, .jpgs, etc should go in the 'data' directory. - -Looking at Theme/Page.hs we see that it tries hard to look like a normal HTML template. There is a bit of noise at the top of the file that would be nice to reduce/simplify. - -The `Clckwrks` module exports a ton of stuff so that you do not need a bunch of imports. - -Looking at the template we see that it is primarily html, with some simple calls to fill in content such as: `getPageTitle` and `getPageContent`. Those functions come from the clckwrks modules such as `Page.API`. The `.API` modules are supposed to provide a friendly interface for template designers to use. - -The internal URLs use web-routes. - -Looking at this template, it seems like it should be easy for template designers to do there thing with out having to have much understanding of Haskell. - -Obviously, the big hang-up is the error messages that you can encounter while using HSP. As Niklas mentioned in this thread: - -https://groups.google.com/group/haskell-server-pages/browse_thread/thread/1b136c7acb448136 - -There is a long-term plan for addressing that. - -Looking at the Theme.Home file, we see a slightly more advanced template that uses a helper function `summaryBox`. - -Hopefully the themes are simple enough that end users can modify an existing theme with out really having to learn any Haskell. - -### clckwrks-plugin-media - -One of the most valuable aspects of Clckwrks is the ability to extend it through the use of plugins. The `clckwrks-plugin-media` adds a media gallery. You can upload images, including them in post, and (eventually) create galleries and slideshows. - -plugins can also hook into the markup engine and add new markup commands. For example, in a post you could write: - - Check out this great photo I took: {media|id=1} - -And when the page is rendered, the image with id 1 will automatically be included in the message. - -### clckwrks-dot-com - -This is where we tie it all together. There are only two files so far. - - Main.hs - PageMapper.hs - -`Main.hs` is a bit scary looking due to the `CPP` code to select between static and dynamic mode. But there is really not much code there. Basically we create a `ClckwrksConfig` and then call `simpleClckwrks` to start the server. - -The static code path just imports the `PageMapper.hs` directly and calls `pageMapper`. The dynamic code path imports that symbol via `withMonadIOFile`. - -It would be nice to hide some of that ugliness away because it is pretty much boiler-plate. The tricky part is that we don't want to link against plugins-auto at all when building the static server. The current solution is the obvious way to do that. But, hopefully, not the best. - -`PageMapper.hs` just contains a simple function `pageMapper`. The purpose of this function is to allow you to specify different page templates for specific pages. For example, we see that PageId 1 will use `Home.page` and all the other pages will use `Page.page`. - -If you comment out the `(PageId 1)` you will see that the bluebox disappears from the home page. If you are using the dynamic server, you can comment that line out and refresh the page and it should be automatically recompiled/reloaded. If you are using the static server, then you will need to rebuild to see the changes. - -If you are using the dynamic server and have created the symlink, you could also edit the `Theme.Home` or `Theme.Page` templates and see the changes reflected after a short delay. - -### Beyond `simpleClckwrks` - -The `simpleClckwrks` entry point is good if you just want a simple wordpress-like site. But, `clckwrks` is also designed to be integrated into a more sophisticated site such as `patch-tag.com`. - -An example is forth-coming. The essence is that you would create a new URL type for your site which embeds `ClckURL`: - - data MySite = C ClckURL - | Home - | Foo - -And then in your routing function you would call `routeClck` for the `ClckURL` case. - -### clckwrks-cli - -The `clckwrks-cli` app provides a command-line interface which communications with a running clckwrks app to perform various administrative features. Right now the only feature it has is the ability to make UserId 1 an Administrator. - -## TODO - -There is clearly a bunch of stuff left to do including: - - * requiring authentication for the admin console - * adding an image gallery (code partial exists but needs to be integrated) - * adding JSON import/export for database - * integrate comment module - * add RSS feed / bloggy-stuff - * tags, searching, etc / CRM - * menu editor - -And then there are a bunch of add-on modules that would be great to have such as: - - * mailing list - * web-store - * paypal - * social media integration - * members-only content - * post scheduling (aka, write a bunch of posts now, but have them published automatically on a schedule) - * and more! - - - hunk ./clckwrks-cli/clckwrks-cli.cabal 2 -Version: 0.2.1 +Version: 0.2.2 hunk ./clckwrks-cli/clckwrks-cli.cabal 27 - clckwrks >= 0.12 && < 0.15, + clckwrks >= 0.12 && < 0.16, hunk ./clckwrks-plugin-page/Clckwrks/Page/NavBarCallback.hs 2 -module Clckwrks.Page.MenuCallback where +module Clckwrks.Page.NavBarCallback where hunk ./clckwrks-plugin-page/Clckwrks/Page/NavBarCallback.hs 4 -import Clckwrks (ClckT, ClckURL, query) -import Clckwrks.Menu.Types (MenuLink(..)) -import Clckwrks.Page.Acid (AllPublishedPages(..), PageState) +import Clckwrks (ClckT, ClckURL, NamedLink(..), query) +import Clckwrks.Page.Acid (AllPublishedPages(..), PageState) hunk ./clckwrks-plugin-page/Clckwrks/Page/NavBarCallback.hs 7 -import Clckwrks.Page.URL (PageURL(..)) -import Data.Acid (AcidState) -import Data.Acid.Advanced (query') -import Data.Function (on) -import Data.List (sortBy) -import Data.Text (Text) +import Clckwrks.Page.URL (PageURL(..)) +import Data.Acid (AcidState) +import Data.Acid.Advanced (query') +import Data.Function (on) +import Data.List (sortBy) +import Data.Text (Text) hunk ./clckwrks-plugin-page/Clckwrks/Page/NavBarCallback.hs 14 -menuCallback :: AcidState PageState +navBarCallback :: AcidState PageState hunk ./clckwrks-plugin-page/Clckwrks/Page/NavBarCallback.hs 16 - -> ClckT ClckURL IO (String, [MenuLink]) -menuCallback acidMenuState showPageURL = - do pages <- query' acidMenuState AllPublishedPages - let blogLink = MenuLink { menuItemName = "Blog", menuItemLink = showPageURL Blog [] } - pageLinks = map (\p -> MenuLink (pageTitle p) (showPageURL (ViewPage (pageId p)) [])) pages - return ("Page", blogLink : (sortBy (compare `on` menuItemName) pageLinks)) + -> ClckT ClckURL IO (String, [NamedLink]) +navBarCallback acidPageState showPageURL = + do pages <- query' acidPageState AllPublishedPages + let blogLink = NamedLink { namedLinkTitle = "Blog", namedLinkURL = showPageURL Blog [] } + pageLinks = map (\p -> NamedLink (pageTitle p) (showPageURL (ViewPage (pageId p)) [])) pages + return ("Page", blogLink : (sortBy (compare `on` namedLinkTitle) pageLinks)) hunk ./clckwrks-plugin-page/Clckwrks/Page/Plugin.hs 4 -import Clckwrks ( ClckwrksConfig(clckTopDir), ClckState(plugins), ClckT(..), ClckURL, ClckPlugins, Theme - , Role(..), ClckPluginsSt, addAdminMenu, addMenuCallback, addPreProc, query, update - ) -import Clckwrks.Acid (GetUACCT(..), SetUACCT(..)) -import Clckwrks.Plugin (clckPlugin) -import Clckwrks.Page.Acid (PageState, GetOldUACCT(..), ClearOldUACCT(..), initialPageState) -import Clckwrks.Page.MenuCallback (menuCallback) -import Clckwrks.Page.Monad (PageConfig(..), runPageT) -import Clckwrks.Page.PreProcess (pageCmd) -import Clckwrks.Page.Route (routePage) -import Clckwrks.Page.URL (PageURL(..), PageAdminURL(..)) -import Clckwrks.Page.Types (PageId(..)) -import Control.Applicative ((<$>)) -import Control.Monad.State (get) -import Data.Acid (AcidState) -import Data.Acid.Advanced (update', query') -import Data.Acid.Local (createCheckpointAndClose, openLocalStateFrom,) -import Data.Text (Text) -import qualified Data.Text.Lazy as TL -import Data.Maybe (fromMaybe) -import Data.Set (Set) -import qualified Data.Set as Set -import Happstack.Server (ServerPartT, Response, notFound, toResponse) -import System.Directory (createDirectoryIfMissing) -import System.FilePath (()) -import Web.Routes (toPathInfo, parseSegments, withRouteT, fromPathSegments) -import Web.Plugins.Core (Plugin(..), Plugins(..), When(..), addCleanup, addHandler, addPostHook, initPlugin, getConfig, getPluginRouteFn) +import Clckwrks ( ClckwrksConfig(clckTopDir), ClckState(plugins), ClckT(..), ClckURL, ClckPlugins, Theme + , Role(..), ClckPluginsSt, addAdminMenu, addMenuCallback, addPreProc, query, update + ) +import Clckwrks.Acid (GetUACCT(..), SetUACCT(..)) +import Clckwrks.Plugin (clckPlugin) +import Clckwrks.Page.Acid (PageState, GetOldUACCT(..), ClearOldUACCT(..), initialPageState) +import Clckwrks.Page.NavBarCallback (navBarCallback) +import Clckwrks.Page.Monad (PageConfig(..), runPageT) +import Clckwrks.Page.PreProcess (pageCmd) +import Clckwrks.Page.Route (routePage) +import Clckwrks.Page.URL (PageURL(..), PageAdminURL(..)) +import Clckwrks.Page.Types (PageId(..)) +import Control.Applicative ((<$>)) +import Control.Monad.State (get) +import Data.Acid (AcidState) +import Data.Acid.Advanced (update', query') +import Data.Acid.Local (createCheckpointAndClose, openLocalStateFrom,) +import Data.Text (Text) +import qualified Data.Text.Lazy as TL +import Data.Maybe (fromMaybe) +import Data.Set (Set) +import qualified Data.Set as Set +import Happstack.Server (ServerPartT, Response, notFound, toResponse) +import System.Directory (createDirectoryIfMissing) +import System.FilePath (()) +import Web.Routes (toPathInfo, parseSegments, withRouteT, fromPathSegments) +import Web.Plugins.Core (Plugin(..), Plugins(..), When(..), addCleanup, addHandler, addPostHook, initPlugin, getConfig, getPluginRouteFn) hunk ./clckwrks-plugin-page/Clckwrks/Page/Plugin.hs 66 - addMenuCallback plugins (menuCallback acid pageShowFn) + addMenuCallback plugins (navBarCallback acid pageShowFn) hunk ./clckwrks-plugin-page/clckwrks-plugin-page.cabal 26 - Clckwrks.Page.MenuCallback + Clckwrks.Page.NavBarCallback hunk ./clckwrks-plugin-page/clckwrks-plugin-page.cabal 44 - happstack-server ==7.0.*, + happstack-server >= 7.0 && < 7.2, hunk ./clckwrks-theme-bootstrap/Theme.hs 6 -import Clckwrks.Menu.API +import Clckwrks.NavBar.API hunk ./clckwrks-theme-bootstrap/Theme.hs 41 - <% getMenu %> + <% getNavBar %> hunk ./clckwrks-theme-clckwrks/Theme.hs 6 -import Clckwrks.Menu.API +import Clckwrks.Types (NamedLink(..)) +import Clckwrks.NavBar.API (getNavBarData) +import Clckwrks.NavBar.Types (NavBar(..), NavBarItem(..)) hunk ./clckwrks-theme-clckwrks/Theme.hs 20 --- , themeBlog = blog hunk ./clckwrks-theme-clckwrks/Theme.hs 40 + + +genNavBar :: GenXML (Clck ClckURL) +genNavBar = + do menu <- lift getNavBarData + navBarHTML menu + +navBarHTML :: NavBar -> GenXML (Clck ClckURL) +navBarHTML (NavBar menuItems) = + + +mkNavBarItem :: NavBarItem -> GenXML (Clck ClckURL) +mkNavBarItem (NBLink (NamedLink ttl lnk)) = +
  • <% ttl %>
  • + hunk ./clckwrks-theme-clckwrks/Theme.hs 76 --- - - +-- + + + +-- +-- hunk ./clckwrks-theme-clckwrks/Theme.hs 88 + <% genNavBar %> +
    +
    +
    +

    <% ttl %>

    +
    +
    + <% bdy %> +
    +{- hunk ./clckwrks-theme-clckwrks/Theme.hs 101 - <% getMenu %> + <% getNavBar %> hunk ./clckwrks-theme-clckwrks/Theme.hs 118 --- +-- - +-} hunk ./clckwrks/Clckwrks/Acid.hs 4 -import Clckwrks.Menu.Acid (MenuState , initialMenuState) +import Clckwrks.NavBar.Acid (NavBarState , initialNavBarState) hunk ./clckwrks/Clckwrks/Acid.hs 73 - , acidMenu :: AcidState MenuState + , acidNavBar :: AcidState NavBarState hunk ./clckwrks/Clckwrks/Acid.hs 86 - bracket (openLocalStateFrom (basePath "menu") initialMenuState) (createArchiveCheckpointAndClose) $ \menu -> + bracket (openLocalStateFrom (basePath "navBar") initialNavBarState) (createArchiveCheckpointAndClose) $ \navBar -> hunk ./clckwrks/Clckwrks/Acid.hs 89 - (const $ f (Acid auth profile profileData core menu)) + (const $ f (Acid auth profile profileData core navBar)) hunk ./clckwrks/Clckwrks/Admin/Route.hs 6 -import Clckwrks.Menu.EditMenu (editMenu, menuPost) +import Clckwrks.NavBar.EditNavBar (editNavBar, navBarPost) hunk ./clckwrks/Clckwrks/Admin/Route.hs 14 - EditMenu -> editMenu - MenuPost -> menuPost + EditNavBar -> editNavBar + NavBarPost -> navBarPost hunk ./clckwrks/Clckwrks/Admin/URL.hs 11 - | EditMenu - | MenuPost + | EditNavBar + | NavBarPost hunk ./clckwrks/Clckwrks/Monad.hs 31 + , getNavBarLinks hunk ./clckwrks/Clckwrks/Monad.hs 34 - , getMenuLinks hunk ./clckwrks/Clckwrks/Monad.hs 55 --- import Clckwrks.Page.Types (Markup(..), runPreProcessors) -import Clckwrks.Menu.Acid (MenuState) --- import Clckwrks.Page.Acid (PageState, PageId) hunk ./clckwrks/Clckwrks/Monad.hs 57 -import Clckwrks.Menu.Types (MenuLink(..), MenuLinks(..)) -import Clckwrks.Types (Prefix, Trust(Trusted)) +import Clckwrks.NavBar.Acid (NavBarState) +import Clckwrks.NavBar.Types (NavBarLinks(..)) +import Clckwrks.Types (NamedLink(..), Prefix, Trust(Trusted)) hunk ./clckwrks/Clckwrks/Monad.hs 117 - , cpsMenuLinks :: [ClckT ClckURL IO (String, [MenuLink])] + , cpsMenuLinks :: [ClckT ClckURL IO (String, [NamedLink])] hunk ./clckwrks/Clckwrks/Monad.hs 348 -instance (Functor m, Monad m) => GetAcidState (ClckT url m) MenuState where - getAcidState = (acidMenu . acidState) <$> get +instance (Functor m, Monad m) => GetAcidState (ClckT url m) NavBarState where + getAcidState = (acidNavBar . acidState) <$> get hunk ./clckwrks/Clckwrks/Monad.hs 607 - -> ClckT ClckURL IO (String, [MenuLink]) + -> ClckT ClckURL IO (String, [NamedLink]) hunk ./clckwrks/Clckwrks/Monad.hs 612 -getMenuLinks :: (MonadIO m) => +getNavBarLinks :: (MonadIO m) => hunk ./clckwrks/Clckwrks/Monad.hs 614 - -> ClckT ClckURL m MenuLinks -getMenuLinks plugins = + -> ClckT ClckURL m NavBarLinks +getNavBarLinks plugins = hunk ./clckwrks/Clckwrks/Monad.hs 618 - MenuLinks <$> sequenceA genMenus + NavBarLinks <$> sequenceA genMenus hunk ./clckwrks/Clckwrks/NavBar/API.hs 2 -module Clckwrks.Menu.API where +module Clckwrks.NavBar.API where hunk ./clckwrks/Clckwrks/NavBar/API.hs 5 -import Clckwrks.Menu.Acid -import Clckwrks.Menu.Types +import Clckwrks.NavBar.Acid +import Clckwrks.NavBar.Types hunk ./clckwrks/Clckwrks/NavBar/API.hs 8 -getMenuData :: (Functor m, MonadIO m) => ClckT url m Menu -getMenuData = query GetMenu +getNavBarData :: (Functor m, MonadIO m) => ClckT url m NavBar +getNavBarData = query GetNavBar hunk ./clckwrks/Clckwrks/NavBar/API.hs 11 -getMenu :: GenXML (Clck ClckURL) -getMenu = - do menu <- query GetMenu - navBarHTML menu +getNavBar :: GenXML (Clck ClckURL) +getNavBar = + do navBar <- query GetNavBar + navBarHTML navBar hunk ./clckwrks/Clckwrks/NavBar/API.hs 16 -navBarHTML :: Menu -> GenXML (Clck ClckURL) -navBarHTML (Menu menuItems) = +navBarHTML :: NavBar -> GenXML (Clck ClckURL) +navBarHTML (NavBar navBarItems) = hunk ./clckwrks/Clckwrks/NavBar/API.hs 21 - <% mapM mkMenuItem menuItems %> + <% mapM mkNavBarItem navBarItems %> hunk ./clckwrks/Clckwrks/NavBar/API.hs 26 -mkMenuItem :: MenuItem -> GenXML (Clck ClckURL) -mkMenuItem (MILink (MenuLink ttl lnk)) = +mkNavBarItem :: NavBarItem -> GenXML (Clck ClckURL) +mkNavBarItem (NBLink (NamedLink ttl lnk)) = hunk ./clckwrks/Clckwrks/NavBar/Acid.hs 2 -module Clckwrks.Menu.Acid where +module Clckwrks.NavBar.Acid where hunk ./clckwrks/Clckwrks/NavBar/Acid.hs 4 -import Clckwrks.Menu.Types (Menu(..), MenuItem(..)) +import Clckwrks.NavBar.Types (NavBar(..), NavBarItem(..)) hunk ./clckwrks/Clckwrks/NavBar/Acid.hs 12 -data MenuState = MenuState - { menu :: Menu +data NavBarState = NavBarState + { navBar :: NavBar hunk ./clckwrks/Clckwrks/NavBar/Acid.hs 16 -$(deriveSafeCopy 2 'base ''MenuState) +$(deriveSafeCopy 2 'base ''NavBarState) hunk ./clckwrks/Clckwrks/NavBar/Acid.hs 18 -initialMenuState :: MenuState -initialMenuState = - MenuState { menu = Menu [] } +initialNavBarState :: NavBarState +initialNavBarState = + NavBarState { navBar = NavBar [] } hunk ./clckwrks/Clckwrks/NavBar/Acid.hs 22 -setMenu :: Menu - -> Update MenuState () -setMenu m = modify $ \ms -> ms { menu = m } +setNavBar :: NavBar + -> Update NavBarState () +setNavBar m = modify $ \ms -> ms { navBar = m } hunk ./clckwrks/Clckwrks/NavBar/Acid.hs 26 -getMenu :: Query MenuState Menu -getMenu = menu <$> ask +getNavBar :: Query NavBarState NavBar +getNavBar = navBar <$> ask hunk ./clckwrks/Clckwrks/NavBar/Acid.hs 29 -$(makeAcidic ''MenuState ['getMenu, 'setMenu]) +$(makeAcidic ''NavBarState ['getNavBar, 'setNavBar]) hunk ./clckwrks/Clckwrks/NavBar/EditNavBar.hs 3 -module Clckwrks.Menu.EditMenu where +module Clckwrks.NavBar.EditNavBar where hunk ./clckwrks/Clckwrks/NavBar/EditNavBar.hs 8 -import Clckwrks.Menu.Acid (GetMenu(..), SetMenu(..)) -import Clckwrks.Menu.Types (Menu(..), MenuLink(..), MenuLinks(..), MenuItem(..)) -import Clckwrks.Monad (Clck(..), ClckState(..), getMenuLinks, mapClckT) +import Clckwrks.NavBar.Acid (GetNavBar(..), SetNavBar(..)) +import Clckwrks.NavBar.Types (NavBar(..), NavBarLinks(..), NavBarItem(..)) +import Clckwrks.Monad (Clck(..), ClckState(..), getNavBarLinks, mapClckT) +import Clckwrks.Types (NamedLink(..)) hunk ./clckwrks/Clckwrks/NavBar/EditNavBar.hs 24 -editMenu :: Clck ClckURL Response -editMenu = +editNavBar :: Clck ClckURL Response +editNavBar = hunk ./clckwrks/Clckwrks/NavBar/EditNavBar.hs 27 - links <- getMenuLinks p + links <- getNavBarLinks p hunk ./clckwrks/Clckwrks/NavBar/EditNavBar.hs 29 - currentMenu <- query GetMenu - template "Edit Menu" (headers currentMenu links) $ + currentNavBar <- query GetNavBar + template "Edit NavBar" (headers currentNavBar links) $ hunk ./clckwrks/Clckwrks/NavBar/EditNavBar.hs 32 -

    Menu Editor

    +

    NavBar Editor

    hunk ./clckwrks/Clckwrks/NavBar/EditNavBar.hs 45 - + hunk ./clckwrks/Clckwrks/NavBar/EditNavBar.hs 48 - + hunk ./clckwrks/Clckwrks/NavBar/EditNavBar.hs 54 - --
    + --
    hunk ./clckwrks/Clckwrks/NavBar/EditNavBar.hs 72 - Menu + NavBar hunk ./clckwrks/Clckwrks/NavBar/EditNavBar.hs 74 - + hunk ./clckwrks/Clckwrks/NavBar/EditNavBar.hs 79 - headers currentMenu menuLinks - = do menuUpdate <- showURL (Admin MenuPost) + headers currentNavBar navBarLinks + = do navBarUpdate <- showURL (Admin NavBarPost) hunk ./clckwrks/Clckwrks/NavBar/EditNavBar.hs 86 -// menu.rename(d.rslt); +// navBar.rename(d.rslt); hunk ./clckwrks/Clckwrks/NavBar/EditNavBar.hs 90 - { $("#menu").jstree(`(jstree currentMenu)`); - var !menu = $.jstree._reference("#menu"); - $("#menu").bind("select_node.jstree", function(e, d) { $("#menu").jstree("rename", d.inst.o); } ); + { $("#navBar").jstree(`(jstree currentNavBar)`); + var !navBar = $.jstree._reference("#navBar"); + $("#navBar").bind("select_node.jstree", function(e, d) { $("#navBar").jstree("rename", d.inst.o); } ); hunk ./clckwrks/Clckwrks/NavBar/EditNavBar.hs 101 - `(initializeDropDowns menuLinks)`; + `(initializeDropDowns navBarLinks)`; hunk ./clckwrks/Clckwrks/NavBar/EditNavBar.hs 103 - `(saveChanges menuUpdate)`; + `(saveChanges navBarUpdate)`; hunk ./clckwrks/Clckwrks/NavBar/EditNavBar.hs 110 -initializeDropDowns :: MenuLinks -> JStat -initializeDropDowns menuLinks' = +initializeDropDowns :: NavBarLinks -> JStat +initializeDropDowns navBarLinks' = hunk ./clckwrks/Clckwrks/NavBar/EditNavBar.hs 113 - var !menuLinks = `(toJSON menuLinks')`; + var !navBarLinks = `(toJSON navBarLinks')`; hunk ./clckwrks/Clckwrks/NavBar/EditNavBar.hs 115 - var menuItemList = $('#menu-item-list'); + var navBarItemList = $('#navBar-item-list'); hunk ./clckwrks/Clckwrks/NavBar/EditNavBar.hs 118 - menuItemList.empty(); - for (var i = 0; i < menuLinks[pluginIndex].pluginLinks.length; i++) { - var option = $('', { value : [pluginIndex,i] }).text(menuLinks[pluginIndex].pluginLinks[i].menuItemName); - option.data("menuItem", menuLinks[pluginIndex].pluginLinks[i].menuItemName); - menuItemList.append(option); + navBarItemList.empty(); + for (var i = 0; i < navBarLinks[pluginIndex].pluginLinks.length; i++) { + var option = $('', { value : [pluginIndex,i] }).text(navBarLinks[pluginIndex].pluginLinks[i].navBarItemName); + option.data("navBarItem", navBarLinks[pluginIndex].pluginLinks[i].navBarItemName); + navBarItemList.append(option); hunk ./clckwrks/Clckwrks/NavBar/EditNavBar.hs 126 - for (var p = 0; p < menuLinks.length; p++) { - var option = $('', { 'value' : p }).text(menuLinks[p].pluginName); - option.text(menuLinks[p].pluginName); + for (var p = 0; p < navBarLinks.length; p++) { + var option = $('', { 'value' : p }).text(navBarLinks[p].pluginName); + option.text(navBarLinks[p].pluginName); hunk ./clckwrks/Clckwrks/NavBar/EditNavBar.hs 136 - var indexes = menuItemList.val().split(','); - var menuItem = menuLinks[indexes[0]].pluginLinks[indexes[1]]; + var indexes = navBarItemList.val().split(','); + var navBarItem = navBarLinks[indexes[0]].pluginLinks[indexes[1]]; hunk ./clckwrks/Clckwrks/NavBar/EditNavBar.hs 139 - , 'data' : { 'title' : menuItem.menuItemName } + , 'data' : { 'title' : navBarItem.navBarItemName } hunk ./clckwrks/Clckwrks/NavBar/EditNavBar.hs 142 - : { 'link' : { 'menuName' : menuItem.menuItemName - , 'menuLink' : menuItem.menuItemLink + : { 'link' : { 'navBarName' : navBarItem.navBarItemName + , 'navBarLink' : navBarItem.navBarItemLink hunk ./clckwrks/Clckwrks/NavBar/EditNavBar.hs 147 - menu.create(null, 0, entry , false, true); + navBar.create(null, 0, entry , false, true); hunk ./clckwrks/Clckwrks/NavBar/EditNavBar.hs 153 -saveChanges menuUpdateURL = +saveChanges navBarUpdateURL = hunk ./clckwrks/Clckwrks/NavBar/EditNavBar.hs 156 - var tree = $("#menu").jstree("get_json", -1); + var tree = $("#navBar").jstree("get_json", -1); hunk ./clckwrks/Clckwrks/NavBar/EditNavBar.hs 159 - $.post(`(menuUpdateURL)`, { tree : json }); + $.post(`(navBarUpdateURL)`, { tree : json }); hunk ./clckwrks/Clckwrks/NavBar/EditNavBar.hs 171 - menu.remove(menu.get_selected()); + navBar.remove(navBar.get_selected()); hunk ./clckwrks/Clckwrks/NavBar/EditNavBar.hs 175 -jstree :: Menu -> Value -jstree menu = +jstree :: NavBar -> Value +jstree navBar = hunk ./clckwrks/Clckwrks/NavBar/EditNavBar.hs 182 - , "menu" .= + , "navBar" .= hunk ./clckwrks/Clckwrks/NavBar/EditNavBar.hs 198 - , "json_data" .= menuToJSTree menu + , "json_data" .= navBarToJSTree navBar hunk ./clckwrks/Clckwrks/NavBar/EditNavBar.hs 202 -menuToJSTree :: Menu -> Value -menuToJSTree (Menu items) = - object [ "data" .= (toJSON $ map menuItemToJSTree items) +navBarToJSTree :: NavBar -> Value +navBarToJSTree (NavBar items) = + object [ "data" .= (toJSON $ map navBarItemToJSTree items) hunk ./clckwrks/Clckwrks/NavBar/EditNavBar.hs 207 -menuItemToJSTree :: MenuItem -> Value -menuItemToJSTree (MILink MenuLink{..}) = +navBarItemToJSTree :: NavBarItem -> Value +navBarItemToJSTree (NBLink NamedLink{..}) = hunk ./clckwrks/Clckwrks/NavBar/EditNavBar.hs 210 - object [ "title" .= menuItemName + object [ "title" .= namedLinkTitle hunk ./clckwrks/Clckwrks/NavBar/EditNavBar.hs 217 - object [ "menuLink" .= menuItemLink + object [ "navBarLink" .= namedLinkURL hunk ./clckwrks/Clckwrks/NavBar/EditNavBar.hs 222 -menuPost :: Clck ClckURL Response -menuPost = +navBarPost :: Clck ClckURL Response +navBarPost = hunk ./clckwrks/Clckwrks/NavBar/EditNavBar.hs 225 - let mu = decode t :: Maybe MenuUpdate + let mu = decode t :: Maybe NavBarUpdate hunk ./clckwrks/Clckwrks/NavBar/EditNavBar.hs 230 - do internalServerError $ toResponse ("menuPost: failed to decode JSON data" :: Text) - (Just (MenuUpdate u)) -> - do update (SetMenu u) + do internalServerError $ toResponse ("navBarPost: failed to decode JSON data" :: Text) + (Just (NavBarUpdate u)) -> + do update (SetNavBar u) hunk ./clckwrks/Clckwrks/NavBar/EditNavBar.hs 235 -newtype MenuUpdate = MenuUpdate Menu deriving (Show) +newtype NavBarUpdate = NavBarUpdate NavBar deriving (Show) hunk ./clckwrks/Clckwrks/NavBar/EditNavBar.hs 237 -instance FromJSON MenuUpdate where - parseJSON (Array a) = (MenuUpdate . Menu) <$> mapM parseJSON (Vector.toList a) +instance FromJSON NavBarUpdate where + parseJSON (Array a) = (NavBarUpdate . NavBar) <$> mapM parseJSON (Vector.toList a) hunk ./clckwrks/Clckwrks/NavBar/EditNavBar.hs 240 -instance FromJSON MenuItem where +instance FromJSON NavBarItem where hunk ./clckwrks/Clckwrks/NavBar/EditNavBar.hs 245 - menuLink <- link .: "menuLink" - let ml = MenuLink ttl menuLink - return (MILink ml) + navBarLink <- link .: "navBarLink" + let nl = NamedLink ttl navBarLink + return (NBLink nl) hunk ./clckwrks/Clckwrks/NavBar/Types.hs 2 -module Clckwrks.Menu.Types where +module Clckwrks.NavBar.Types where hunk ./clckwrks/Clckwrks/NavBar/Types.hs 4 -import Data.Aeson (ToJSON(..), (.=), object) -import Data.Data (Data, Typeable) -import Data.SafeCopy (base, deriveSafeCopy) -import Data.Text (Text) +import Clckwrks.Types (NamedLink(..)) +import Data.Aeson (ToJSON(..), (.=), object) +import Data.Data (Data, Typeable) +import Data.SafeCopy (base, deriveSafeCopy) +import Data.Text (Text) hunk ./clckwrks/Clckwrks/NavBar/Types.hs 10 -newtype Menu = Menu - { menuItems :: [MenuItem] +newtype NavBar = NavBar + { navBarItems :: [NavBarItem] hunk ./clckwrks/Clckwrks/NavBar/Types.hs 15 -data MenuLink = MenuLink - { menuItemName :: Text - , menuItemLink :: Text - } + + +data NavBarItem + = NBLink NamedLink + | NBSubNavBar Text NavBar hunk ./clckwrks/Clckwrks/NavBar/Types.hs 21 +$(deriveSafeCopy 1 'base ''NavBar) +$(deriveSafeCopy 1 'base ''NavBarItem) hunk ./clckwrks/Clckwrks/NavBar/Types.hs 24 -newtype MenuLinks = MenuLinks [(String, [MenuLink])] +newtype NavBarLinks = NavBarLinks [(String, [NamedLink])] hunk ./clckwrks/Clckwrks/NavBar/Types.hs 27 -instance ToJSON MenuLinks where - toJSON (MenuLinks menuLinks) = +instance ToJSON NavBarLinks where + toJSON (NavBarLinks navBarLinks) = hunk ./clckwrks/Clckwrks/NavBar/Types.hs 32 - ]) menuLinks - -instance ToJSON MenuLink where - toJSON (MenuLink{..}) = - object [ "menuItemName" .= menuItemName - , "menuItemLink" .= menuItemLink - ] - --- instance FromJSON MenuLink where --- fromJSON (Object obj) = - -data MenuItem - = MILink MenuLink - | MISubMenu Text Menu - deriving (Eq, Read, Show, Data, Typeable) - -$(deriveSafeCopy 1 'base ''Menu) -$(deriveSafeCopy 1 'base ''MenuLink) -$(deriveSafeCopy 1 'base ''MenuItem) - - - + ]) navBarLinks hunk ./clckwrks/Clckwrks/Plugin.hs 5 -import Clckwrks.Menu.Types (MenuLink(..)) +import Clckwrks.Types (NamedLink(..)) hunk ./clckwrks/Clckwrks/Plugin.hs 22 -clckMenuCallback :: ClckT ClckURL IO (String, [MenuLink]) +clckMenuCallback :: ClckT ClckURL IO (String, [NamedLink]) hunk ./clckwrks/Clckwrks/Plugin.hs 25 - return ("Clck", [MenuLink "Admin" adminURL]) + return ("Clck", [NamedLink "Admin" adminURL]) hunk ./clckwrks/Clckwrks/Plugin.hs 47 - , (Set.singleton Administrator, "Edit Menu" , clckShowURL (Admin EditMenu) []) + , (Set.singleton Administrator, "Edit Nav Bar" , clckShowURL (Admin EditNavBar) []) hunk ./clckwrks/Clckwrks/Types.hs 1 -{-# LANGUAGE DeriveDataTypeable, GeneralizedNewtypeDeriving, TemplateHaskell #-} +{-# LANGUAGE DeriveDataTypeable, GeneralizedNewtypeDeriving, RecordWildCards, TemplateHaskell, OverloadedStrings #-} hunk ./clckwrks/Clckwrks/Types.hs 6 + , NamedLink(..) hunk ./clckwrks/Clckwrks/Types.hs 9 +import Data.Aeson (ToJSON(..), (.=), object) hunk ./clckwrks/Clckwrks/Types.hs 12 -import Data.Text as T +import Data.Text (Text) hunk ./clckwrks/Clckwrks/Types.hs 22 -newtype Prefix = Prefix { prefixText :: T.Text } +newtype Prefix = Prefix { prefixText :: Text } hunk ./clckwrks/Clckwrks/Types.hs 31 +data NamedLink = NamedLink + { namedLinkTitle :: Text + , namedLinkURL :: Text + } + deriving (Eq, Read, Show, Data, Typeable) +$(deriveSafeCopy 1 'base ''NamedLink) + +instance ToJSON NamedLink where + toJSON (NamedLink{..}) = + object [ "navBarItemName" .= namedLinkTitle + , "navBarItemLink" .= namedLinkURL + ] + hunk ./clckwrks/clckwrks.cabal 2 -Version: 0.15.0 +Version: 0.15.1 hunk ./clckwrks/clckwrks.cabal 48 - Clckwrks.Menu.Acid - Clckwrks.Menu.API - Clckwrks.Menu.EditMenu - Clckwrks.Menu.Types + Clckwrks.NavBar.Acid + Clckwrks.NavBar.API + Clckwrks.NavBar.EditNavBar + Clckwrks.NavBar.Types