corebot-bliki (empty) → 0.1
raw patch · 6 files changed
+298/−0 lines, 6 filesdep +aesondep +basedep +blaze-buildersetup-changed
Dependencies added: aeson, base, blaze-builder, bytestring, containers, directory, filepath, filestore, http-types, monads-tf, pandoc, template-haskell, text, time, yesod
Files
- LICENSE +31/−0
- Setup.hs +3/−0
- corebot-bliki.cabal +49/−0
- src/DefaultMain.hs +87/−0
- static/indirect_load.js +59/−0
- static/process_HTML_for_wiki.js +69/−0
+ LICENSE view
@@ -0,0 +1,31 @@+Copyright Corey O'Connor++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++ * Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.++ * Redistributions in binary form must reproduce the above+ copyright notice, this list of conditions and the following+ disclaimer in the documentation and/or other materials provided+ with the distribution.++ * Neither the name of Stefan O'Rear nor the names of other+ contributors may be used to endorse or promote products derived+ from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.+
+ Setup.hs view
@@ -0,0 +1,3 @@+import Distribution.Simple+main = defaultMain+
+ corebot-bliki.cabal view
@@ -0,0 +1,49 @@+name: corebot-bliki+version: 0.1+synopsis: A bliki written using yesod. Uses pandoc to process files stored in git.+description: Also provides a sample use of the library that uses $HOME/bliki for data and serves+ to port 8080.+ See http://www.corebotllc.com for public site built using this library.+cabal-version: >= 1.8+build-type: Simple+data-files: static/*.js+license: BSD3+license-file: LICENSE+homepage: http://github.com/coreyoconnor/corebot-bliki++source-repository head+ type: git+ location: git://github.com/coreyoconnor/corebot-bliki.git+ +executable corebot-bliki+ main-is: DefaultMain.hs+ hs-source-dirs: src+ extensions: TemplateHaskell+ QuasiQuotes+ TypeFamilies+ MultiParamTypeClasses+ FlexibleInstances+ NoMonomorphismRestriction+ OverloadedStrings+ RankNTypes+ ScopedTypeVariables+ UndecidableInstances+ EmptyDataDecls+ GADTs+ FlexibleContexts+ ghc-options: -threaded+ build-depends: base >= 4.4.0 && < 5,+ aeson >= 0.3.2.11,+ blaze-builder >= 0.3.0.1,+ bytestring >= 0.9.2.0,+ containers >= 0.4.1.0,+ directory >= 1.1.0.1,+ filepath >= 1.2.0.1,+ filestore >= 0.4.0.5,+ http-types >= 0.6.7,+ monads-tf >= 0.1.0.0,+ pandoc >= 1.9,+ text >= 0.11.1.5,+ template-haskell >= 2.6.0.0,+ time >= 1.2.0.5,+ yesod >= 0.9.4.1
+ src/DefaultMain.hs view
@@ -0,0 +1,87 @@+module Main where+import Yesod++import Yesod.CoreBot.Bliki +import Yesod.CoreBot.Bliki.Widgets++import Paths_corebot_bliki++import Control.Applicative+import Control.Monad.Fix++import Data.Monoid ++import System.Directory ( getHomeDirectory )++import System.FilePath++data Main = Main+ { bliki :: Bliki_ Main+ }++type Bliki = Bliki_ Main++type Data = Data_ Main+get_data = data_res . bliki++type Blog = Blog_ Main+get_blog = blog_res . bliki++type Wiki = Wiki_ Main+get_wiki = wiki_res . bliki++get_static = static_config . config . data_res . bliki++instance Yesod Main where+ approot _ = "http://localhost:8080"+ defaultLayout w = do+ let page_w = mconcat [ w, toWidget NavWidget ]+ p <- widgetToPageContent page_w+ mmsg <- getMessage+ hamletToRepHtml [hamlet|+!!!++<html>+ <head>+ <title>#{pageTitle p}+ ^{pageHead p}+ <body>+ $maybe msg <- mmsg+ <p .message>#{msg}+ ^{pageBody p}+|]++getMainR = do+ bliki <- bliki <$> getYesod+ defaultLayout $ do+ default_blog_entry bliki++mkYesod "Main" [parseRoutes|+/ MainR GET+/data DataS Data get_data+/blog BlogS Blog get_blog+/wiki WikiS Wiki get_wiki+/static StaticS Static get_static+|]++main :: IO ()+main = do+ home_dir <- getHomeDirectory+ let store_dir = home_dir </> "bliki"+ cache_dir = home_dir </> "bliki/cache"+ static_dir <- getDataFileName "static"+ putStrLn $ "using static dir: " ++ static_dir+ app <- mfix $ \app -> do+ let config = Config { store_dir = store_dir+ , cache_dir = cache_dir+ , data_routes = DataS+ , blog_routes = BlogS+ , wiki_routes = WikiS+ , static_routes = StaticS+ , static_config = UseDir static_dir+ , site = app+ }+ bliki <- mk_bliki config+ return $ Main bliki+ warpDebug 8080 app+
+ static/indirect_load.js view
@@ -0,0 +1,59 @@+var worker = new Worker('static/process_HTML_for_wiki.js');++function insertSubstr( str, index, sub_str )+{+ var str_pre = str.slice( 0, index );+ var str_post = str.slice( index );+ return str_pre + sub_str + str_post;+}++function process_HTML_for_wiki( data, target, wiki_node_URL )+{+ var edits = new Array;++ var apply_edits = function()+ {+ edits.reverse();++ for(var i = 0; i < edits.length ; ++i)+ {+ var edit = edits[i];+ var edit_region = edit.edit_region;+ // +- 2 accounts for the ]] and [[ respectively. + // XXX: hackish+ data = insertSubstr( data, edit_region.end_index + 2, '</a>' );+ data = insertSubstr( data, edit_region.start_index - 2, '<a href="' + edit.node_URL + '">' );+ }++ target.html( data );+ }++ worker.postMessage( data );+ worker.onmessage = function(event)+ {+ edit_region = event.data;++ var node_URL = wiki_node_URL + '/' + edit_region.node_path;++ var http = new XMLHttpRequest();+ http.open('HEAD', node_URL, true);+ http.onload = function( pe )+ {+ console.log( http.status );++ // Thanks the gods of HTTP for making this next line so.+ if( http.status < 400 )+ {+ edits.push( { edit_region: edit_region+ , node_URL: node_URL+ }+ );+ + if( edit_region.is_final )+ apply_edits();+ }+ };+ http.send();+ };+}+
+ static/process_HTML_for_wiki.js view
@@ -0,0 +1,69 @@+onmessage = function(event) +{+ // This method assumes that double bracket *always* indicates a wiki node path regardless of+ // it's location in the source+ // I presume there is some way to use jquery from a web worker. Once I figure that out I think+ // this algo would be better: Parse the HTML fragment data and then use jquery to only scan the+ // wiki links that are not in code tags.+ //+ // for now we avoid just the HTML generated by ``[[wiki_word]]``. Every other instance of+ // [[wiki_word]] is assumed to be replacable by the a link+ var src = new String(event.data);++ var start_match = /[^>]\[\[/gm;++ var node_path_match = /(\w+(?:\/\w+)*)\]\]/g;++ var parse_state = 'pre_start';++ var pending = null;++ var step_parser = function()+ {+ switch( parse_state )+ {+ case 'pre_start':+ var m = start_match.exec( src );++ if( null == m && null != pending )+ pending.is_final = true;++ if( null != pending )+ postMessage( pending );++ pending = null;++ if( null == m )+ return;++ node_path_match.lastIndex = start_match.lastIndex;++ parse_state = 'in_brackets';+ break;+ case 'in_brackets':+ var m = node_path_match.exec( src );++ if(null == m)+ {+ parse_state = 'pre_start';+ break;+ }++ pending = { node_path: m[1] + , start_index: start_match.lastIndex+ , end_index: node_path_match.lastIndex - 2+ , is_final: false+ };++ start_match.lastIndex = node_path_match.lastIndex;++ parse_state = 'pre_start';+ break;+ }++ setTimeout( step_parser, 50 );+ };+ + setTimeout( step_parser, 50 );+};+