{-# LANGUAGE QuasiQuotes, OverloadedStrings, FlexibleContexts, ViewPatterns, RecordWildCards, TupleSections, NoImplicitPrelude #-} module View ( -- * Pages renderRoot, renderAdmin, renderEdits, renderHaskellRoot, renderDonate, renderCategoryPage, renderUnwrittenRules, -- * Tracking renderTracking, -- * Methods renderHelp, -- ** Categories renderCategoryList, renderCategory, renderCategoryTitle, renderCategoryNotes, -- ** Items renderItem, renderItemInfo, renderItemDescription, renderItemEcosystem, renderItemTraits, renderItemNotes, -- ** Traits renderTrait, -- * Rendering for feeds renderItemForFeed, -- * Miscellaneous getItemHue, newGroupValue, ) where -- General import BasePrelude hiding (Category) -- Default import Data.Default -- Lenses import Lens.Micro.Platform hiding ((&)) -- Monads and monad transformers import Control.Monad.IO.Class import Control.Monad.Reader -- Containers import qualified Data.Map as M import Data.Tree -- Text import qualified Data.Text as T import qualified Data.Text.IO as T import Data.Text (Text) import NeatInterpolation -- Web import Lucid hiding (for_) -- Time import Data.Time.Format.Human -- Markdown import Cheapskate.Lucid import Cheapskate.Types -- Local import Config import Types import Utils import JS (JS(..), JQuerySelector) import qualified JS import Markdown {- Note [autosize] ~~~~~~~~~~~~~~~~~~ All textareas on the site are autosized – i.e. they grow when the user is typing. This is done by the autosize.js plugin, which is called on page load: autosize($('textarea')); A slight problem is that it doesn't compute the height of hidden elements correctly – thus, when something is shown and it happens to be a textarea or contain a textarea, we have to call autosize again. This is done in 'JS.switchSection'. So far there are no textboxes that are shown *without* switchSection being involved, and so there's no need to watch for elements being added to the DOM. It would be nicer if we could watch for elements becoming visible without having to modify switchSection, but there doesn't seem to be an easy way to do this – MutationObserver doesn't let us find out when something becomes visible (i.e. when its clientHeight stops being 0). In switchSection we use autosize($('textarea')); autosize.update($('textarea')); instead of simple autosize.update($('textarea')); – this is done because the textarea could have appeared after the original `autosize($('textarea'));` was called on page load (which could happen if an item was added, for instance). -} {- Note [show-hide] ~~~~~~~~~~~~~~~~~~~ A lot of things (help, notes, etc) can be expanded/collapsed by pressing a button. Similarly, pressing “edit” replaces rendered text with a textbox, or adds buttons to pros/cons. All this is done with sections and show/hide. A section is something that can be shown or hidden. You define a section by using 'section' (which creates a
) or 'sectionSpan' (which creates a ). section "normal" [shown, noScriptShown] $ do renderText ... section "editing" [] $ do renderEditbox ... You can even give 2 names to a section – e.g. "normal editing" if you want the section be visible both in “normal” mode and in “editing” mode. The list parameter is used to add attributes to the section. 'shown' is an attribute that means that the section is normally visible; 'noScriptShown' means that the section will be visible when Javascipt is disabled. Sections without either attribute will be hidden. (Usually 'shown' and 'noScriptShown' go together, but not always.) When several sections are in the same container (e.g. a
), you can toggle between them with 'JS.switchSection', which shows the section (or several sections) with given name, and hides all sections with other names. The elements that aren't sections are not affected. Also, there's another function available – 'JS.switchSectionEverywhere' – that switches sections everywhere inside the container, not only among container's direct children. It's useful when you have something like a list of pros/cons and you want to switch them all into the “editable” state. //////////////////////////////////// And now, here's how it's all implemented. In 'wrapPage' there's a piece of CSS wrapped in