plain text hidden behind a function call (to make localization easier)
This commit is contained in:
@@ -4,15 +4,16 @@
|
||||
(defn hash
|
||||
"A simple hash-function, which computes a hash from the text field
|
||||
content and given session number. It is intended to be used as a spam
|
||||
protection / captcha alternative. (Probably doesn't work for URF-16)"
|
||||
protection / captcha alternative (let's see whether spambots evaluate heavy JS).
|
||||
(Probably doesn't work for UTF-16)"
|
||||
[f s]
|
||||
(let [short-mod #(mod % 32767)
|
||||
char-codes (map f
|
||||
(filter #(not (contains? #{"\n" "\r"} %)) (map str s)))]
|
||||
char-codes (map f (remove #(contains? #{"\n" "\r"} %) (map str s)))
|
||||
zip-with-index (map list char-codes (range))]
|
||||
(reduce
|
||||
#(short-mod (+ %
|
||||
(short-mod (* (first %2)
|
||||
((if (odd? %)
|
||||
bit-xor
|
||||
bit-and) 16381 (second %2))))))
|
||||
0 (map list char-codes (range)))))
|
||||
0 zip-with-index)))
|
||||
|
||||
@@ -1,19 +1,33 @@
|
||||
(ns NoteHub.settings
|
||||
(:require [clojure.contrib.string :as ccs])
|
||||
(:refer-clojure :exclude [replace reverse])
|
||||
(:use [clojure.string]))
|
||||
|
||||
; Load and parse te settings file returning a map
|
||||
(def settings-map
|
||||
(let [file-content (slurp "settings")
|
||||
lines (split file-content #"\n")
|
||||
pairs (map #(map trim (split % #"=")) lines)]
|
||||
; Loads and parses the settings file; returns a key-value map.
|
||||
; Assumes, that all string of the setings file are in format:
|
||||
; key = value
|
||||
(defn- get-pairs-map [file]
|
||||
(let [file-content (slurp file)
|
||||
pairs (map #(map trim (split % #"=" 2))
|
||||
(remove ccs/blank? (ccs/split-lines file-content)))]
|
||||
(apply hash-map
|
||||
(mapcat #(list (keyword (first %)) (second %)) pairs))))
|
||||
|
||||
(def settings-map
|
||||
(get-pairs-map "settings"))
|
||||
|
||||
(def messages-map
|
||||
(get-pairs-map "messages"))
|
||||
|
||||
(defn get-message [key]
|
||||
"Returns messages used in layouts. Every key should be a keyword, e.g. (get-message :title)."
|
||||
(messages-map key))
|
||||
|
||||
(defn get-setting
|
||||
"Takes a settings key, a converter function and a default value, and returns a corresponding
|
||||
setting value. The default value is returned back when no setting value was found.
|
||||
The converter function can be provided to convert the setting from string to a needed type."
|
||||
The converter function can be provided to convert the setting from string to a needed type.
|
||||
Every key should be a keyword, e.g. (get-setting :page-width)."
|
||||
[key & more]
|
||||
(let [converter (first more)
|
||||
default (second more)
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
(def note "note")
|
||||
(def views "views")
|
||||
|
||||
|
||||
; Concatenates all fields to a string
|
||||
(defn- build-key [[year month day] title]
|
||||
(print-str year month day title))
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
(ns NoteHub.views.common
|
||||
(:use
|
||||
[NoteHub.settings :only [get-message]]
|
||||
[NoteHub.views.css-generator]
|
||||
[noir.core :only [defpartial]]
|
||||
[hiccup.page :only [include-js html5]]
|
||||
@@ -10,7 +11,7 @@
|
||||
[params title & content]
|
||||
(html5
|
||||
[:head
|
||||
[:title "NoteHub — " title]
|
||||
[:title (print-str (get-message :name) "—" title)]
|
||||
[:link {:href
|
||||
(clojure.string/replace
|
||||
(str "http://fonts.googleapis.com/css?family="
|
||||
|
||||
@@ -54,12 +54,19 @@
|
||||
background-halftone (color theme :background-halftone)
|
||||
foreground-halftone (color theme :foreground-halftone)]
|
||||
(css
|
||||
(rule "a"
|
||||
:color :#097
|
||||
:text-decoration :none
|
||||
:border-bottom [:1px :dotted]
|
||||
(rule "&:hover"
|
||||
:color :#0a8)
|
||||
(rule "&:visited"
|
||||
:color :#054))
|
||||
(rule ".landing-button"
|
||||
:box-shadow [0 :2px :5px :#aaa]
|
||||
:text-decoration :none
|
||||
:font-size :1.5em
|
||||
:background :#0a2
|
||||
:color :white
|
||||
:border :none
|
||||
:border-radius :10px
|
||||
:padding :10px
|
||||
@@ -77,6 +84,7 @@
|
||||
(rule "td"
|
||||
:padding :0.5em)
|
||||
(rule ".one-third-column"
|
||||
:line-height (% 120)
|
||||
:text-align :justify
|
||||
:vertical-align :top
|
||||
; Replace this by arithmetic with css-lengths as soon as they fix the bug
|
||||
@@ -94,16 +102,19 @@
|
||||
:margin :2em))
|
||||
(rule "article"
|
||||
central-element
|
||||
:line-height (% 140)
|
||||
:font-family text-fonts
|
||||
:text-align :justify
|
||||
:font-size :1.2em
|
||||
(rule "p"
|
||||
:line-height (% 140))
|
||||
(rule "& > h1:first-child"
|
||||
:text-align :center
|
||||
:margin :2em))
|
||||
(rule ".centered"
|
||||
:text-align :center)
|
||||
(rule "pre"
|
||||
:border-radius :3px
|
||||
:padding :1em
|
||||
:padding :0.5em
|
||||
:border [:1px :dotted foreground-halftone]
|
||||
:background background-halftone)
|
||||
(rule "*:focus"
|
||||
@@ -129,7 +140,7 @@
|
||||
central-element)
|
||||
(rule "h1"
|
||||
:font-size :2em)
|
||||
(rule "#preview-start-line"
|
||||
(rule ".dashed-line"
|
||||
:border-bottom [:1px :dashed foreground-halftone]
|
||||
:margin-bottom :5em)
|
||||
(rule "h1, h2, h3, h4"
|
||||
|
||||
+33
-57
@@ -1,5 +1,6 @@
|
||||
(ns NoteHub.views.pages
|
||||
(:require [NoteHub.crossover.lib :as lib])
|
||||
(:require [NoteHub.crossover.lib :as lib]
|
||||
[clojure.contrib.string :as ccs])
|
||||
(:use
|
||||
[NoteHub.storage]
|
||||
[NoteHub.settings]
|
||||
@@ -34,23 +35,18 @@
|
||||
(layout params title [:article (md-to-html md-text)]))
|
||||
(status 404 (get-page 404))))
|
||||
|
||||
; Template for the error sites
|
||||
(defn page-setter [code message]
|
||||
; Sets a custom message for each corresponding HTTP status
|
||||
(doseq [code [400 404 500]]
|
||||
(set-page! code
|
||||
(layout message
|
||||
[:article
|
||||
[:h1 message]])))
|
||||
|
||||
; Sets a message for each corresponding HTTP status
|
||||
(page-setter 404 "Nothing Found.")
|
||||
(page-setter 400 "Bad request.")
|
||||
(page-setter 500 "OMG, Server Exploded.")
|
||||
(let [message (get-message (keyword (str "status-" code)))]
|
||||
(layout message
|
||||
[:article [:h1 message]]))))
|
||||
|
||||
; Routes
|
||||
; ======
|
||||
|
||||
; This function answers to a AJAX request: it gets a sesion key and markdown text.
|
||||
; IT return html version of the provided markdown and a new session key
|
||||
; It returns the html code of the provided markdown and a new session key.
|
||||
(defremote get-preview-md [session-key md]
|
||||
(when (flash-get session-key)
|
||||
{:session-key (get-flash-key)
|
||||
@@ -58,58 +54,38 @@
|
||||
|
||||
; Landing Page
|
||||
(defpage "/" {}
|
||||
(layout "Free Markdown Hosting"
|
||||
(layout (get-message :title)
|
||||
[:div#hero
|
||||
[:h1 "NoteHub"]
|
||||
[:h2 "Free and hassle-free hosting for markdown pages."]
|
||||
[:h1 (get-message :name)]
|
||||
[:h2 (get-message :title)]
|
||||
[:br]
|
||||
[:a.landing-button {:href "/new"} "New Page"]]
|
||||
[:div#preview-start-line]
|
||||
[:table.central-element.helvetica-neue
|
||||
[:tr
|
||||
[:td.one-third-column
|
||||
[:h2 "Why?"]
|
||||
"Not every person, who occasionally wants to express some thoughts, needs a blog.
|
||||
Blogs are <b>tedious</b> for writers and for readers. Most people are not interested in thoughts
|
||||
of other random people. Moreover, nowadays everything rotates around social networks and not
|
||||
individual blogs. It makes much more sense to publish something somewhere and to share
|
||||
the link with the audience on the community or social network of your choice, than to maintain a blog
|
||||
trying to keep your readers interested.
|
||||
<b>NoteHub</b> should be the place, where you can publish your thoughts without hassle."]
|
||||
[:td.one-third-column
|
||||
[:h2 "How to Use?"]
|
||||
"First create a new page using the markdown syntax. Now, besides just sharing the link, you can
|
||||
view some rudimentary statistics by appending <code>/stats</code> to the note url:
|
||||
<pre>notehub.org/.../title/stats</pre>
|
||||
If you want to export a note in the original Markdown format, append <code>/export</code>
|
||||
<pre>notehub.org/.../title/export</pre>
|
||||
And if you want, you also can invert the color scheme by appending <code>?theme=dark</code> to the note url.
|
||||
<pre>notehub.org/.../title?theme=dark</pre>"]
|
||||
[:td.one-third-column
|
||||
[:h2 "For Geeks!"]
|
||||
"NoteHub was an experiment and is implemented entirely in Clojure and ClojureScript. Its source code can
|
||||
be found on GitHub. Look at the code to find some undocumented NoteHub features (or bugs) and — feel free to contribute!
|
||||
(If you are interested in more detailed code overview, read the following note.) NoteHub's design
|
||||
is intentionally kept extremelly simple and minimalistic, and should stay like this.
|
||||
NoteHub's persistence layer bases on the key-value store redis.
|
||||
Currently, NoteHub is hosted for free on Heroku.
|
||||
Send your feedback and comments directly to @chmllr."]]]))
|
||||
[:a.landing-button {:href "/new" :style "color: white"} (get-message :new-page)]]
|
||||
[:div.dashed-line]
|
||||
[:table.central-element.helvetica-neue
|
||||
[:tr
|
||||
[:td.one-third-column
|
||||
[:h2 (get-message :column-why)] (md-to-html (get-message :column-why-long))]
|
||||
[:td.one-third-column
|
||||
[:h2 (get-message :column-how)] (md-to-html (get-message :column-how-long))]
|
||||
[:td.one-third-column
|
||||
[:h2 (get-message :column-geeks)] (md-to-html (get-message :column-geeks-long))]]]
|
||||
[:div.centered.helvetica-neue (md-to-html (get-message :created-by))]))
|
||||
|
||||
; New Note Page
|
||||
(defpage "/new" {}
|
||||
(layout {:js true} "New Markdown Note"
|
||||
(layout {:js true} (get-message :new-note)
|
||||
[:div.central-element
|
||||
(form-to [:post "/post-note"]
|
||||
(hidden-field :session-key (get-flash-key))
|
||||
(hidden-field {:id :session-value} :session-value)
|
||||
(text-area {:class :max-width} :draft "Loading...")
|
||||
(text-area {:class :max-width} :draft (get-message :loading))
|
||||
[:div#buttons.hidden
|
||||
(submit-button {:style "float: left"
|
||||
:class :button
|
||||
:id :publish-button} "Publish")
|
||||
:id :publish-button} (get-message :publish))
|
||||
[:button#preview-button.button {:type :button
|
||||
:style "float: right"} "Preview"]])]
|
||||
[:div#preview-start-line.hidden]
|
||||
:style "float: right"} (get-message :preview)]])]
|
||||
[:div#preview-start-line.dashed-line.hidden]
|
||||
[:article#preview]))
|
||||
|
||||
; Display the note
|
||||
@@ -127,14 +103,14 @@
|
||||
(defpage "/:year/:month/:day/:title/stat" {:keys [year month day title]}
|
||||
(let [views (get-views [year month day] title)]
|
||||
(if views
|
||||
(layout "Statistics"
|
||||
(layout (get-message :statistics)
|
||||
[:article.helvetica-neue
|
||||
[:table {:style "width: 100%"}
|
||||
[:tr
|
||||
[:td "Published"]
|
||||
[:td (get-message :published)]
|
||||
[:td (interpose "-" [year month day])]]
|
||||
[:tr
|
||||
[:td "Article views"]
|
||||
[:td (get-message :article-views)]
|
||||
[:td views]]]])
|
||||
(status 404 (get-page 404)))))
|
||||
|
||||
@@ -151,11 +127,11 @@
|
||||
(let [[year month day] (map #(+ (second %) (.get (Calendar/getInstance) (first %)))
|
||||
{Calendar/YEAR 0, Calendar/MONTH 1, Calendar/DAY_OF_MONTH 0})
|
||||
untrimmed-line (filter #(or (= \- %) (Character/isLetterOrDigit %))
|
||||
(-> draft (split #"\n") first (sreplace " " "-") lower-case))
|
||||
(-> draft ccs/split-lines first (sreplace " " "-") lower-case))
|
||||
trim (fn [s] (apply str (drop-while #(= \- %) s)))
|
||||
title-uncut (-> untrimmed-line trim reverse trim reverse)
|
||||
proposed-title (apply str (take (get-setting :max-title-length #(Integer/parseInt %) 80)
|
||||
title-uncut))
|
||||
max-length (get-setting :max-title-length #(Integer/parseInt %) 80)
|
||||
proposed-title (apply str (take max-length title-uncut))
|
||||
date [year month day]
|
||||
title (first (drop-while #(note-exists? date %)
|
||||
(cons proposed-title
|
||||
|
||||
Reference in New Issue
Block a user