3

在我的 Hakyll 站点中,我有一个链接到页面的样式表:

<link rel="stylesheet" type="text/css" href="/css/my.css">

这个 CSS 包含一个@font-face链接到字体文件的指令:

@font-face {
 font-family: "Bla";
 src: url("/data/bla.ttf") format("truetype");
}

relativizeUrls问题是即使我将字体的 URL 移动到<script>页面本身的标签中,它也不会被相对化。如何解决这个问题呢?

4

3 回答 3

2

tl;dr – 您可以使用 Beerend Lauwers 的hakyll-extra包(似乎还没有启用hackage),它提供了一个relativizeUrl宏。或者,按如下方式实现您自己的:

如果您没有太多链接,并且不想仅仅为了做到这一点而引入 CSS 解析器,您可以创建一个函数字段 - 实际上是一个宏 - 它允许您调用,例如relativize("/some/url")从页。(我遇到了类似的问题,因为我想将指向样式表的链接相对化以供旧版本的 Internet Explorer 使用;而对于TagSoup,这些链接看起来好像它们在评论中,所以它没有处理它们。)

首先,我们需要编写一个relativizeUrls只对单个 URL 进行操作的版本:

 import Data.List as L

 -- | Relativize URL. Same logic as "relativizeUrlsWith" in
 -- Hakyll.Web.Html.RelativizeUrls, but for just one url.
 relativizeUrl :: String  -- ^ Path to the site root
                    -> String  -- ^ link to relativize
                    -> String  -- ^ Resulting link
 relativizeUrl root = rel
   where
     isRel :: String -> Bool
     isRel x = "/" `L.isPrefixOf` x && not ("//" `L.isPrefixOf` x)
     rel x   = if isRel x then root ++ x else x

然后,我们定义一个可以添加到上下文中的“函数字段”。

 import Data.Maybe (maybe)

 -- ugh. ugly name.
 relativizeFuncField :: Context a
 relativizeFuncField = functionField "relativize" relativize
   where 
     relativize :: [String] -> Item a -> Compiler String
     relativize args item = do
       siteRoot <- getRoot <$> (getRoute $ itemIdentifier item)
       arg <- case args of 
               [arg] -> return arg
               _     -> error "relativize: expected only 1 arg"
       return $ relativizeUrl siteRoot arg

     getRoot :: Maybe String -> String
     getRoot = maybe (error "relativize: couldn't get route") toSiteRoot 

然后,在任何你想使用这个宏的地方,而不是使用,比如说defaultContext,使用relativizeFuncField <> defaultContext。例如:

 import Data.Monoid( (<>) )

 main = 
   -- ... 

   match (fromList ["about.rst", "contact.markdown"]) $ do
       route   $ setExtension "html"
       compile $ pandocCompiler
           >>= loadAndApplyTemplate "templates/default.html" (relativizeFuncField <> defaultContext)
           >>= relativizeUrls

所以,最后,这意味着在一个文件中,你可以在任何没有相对化链接$relativize("/path/to/file")$的地方写。TagSoup

希望这是有用的:
)(这是使用 Hakyll 4.9.0.0,但我认为其他 4.X 版本大致相同。)

编辑:ps,非常感谢 Beerend Lauwers,他在这里的帖子中解释了 Hakyll 函数字段

再次编辑:d'oh。我没有看到Beerend实际上已经在他的包中放入了一个relativizeUrl函数。hakyll-extra

于 2017-02-12T09:25:46.733 回答
1

HakyllrelativizeURLs用于TagSoup解析和打印 HTML,因此它只能在 HTML 属性中找到的 URL 上工作。我不知道任何现有的功能可以将其扩展到 CSS 而不仅仅是 HTML 属性。

相关代码会遍历每个被解析的标签,TagSoup并将函数应用于它识别为 URL 的属性:

-- | Apply a function to each URL on a webpage
withUrls :: (String -> String) -> String -> String
withUrls f = withTags tag
  where
    tag (TS.TagOpen s a) = TS.TagOpen s $ map attr a
    tag x                = x
    attr (k, v)          = (k, if isUrlAttribute k then f v else v)

(来自Hakyll.Web.HTML

无法从提供的relativizeURLs编译器更改此遍历逻辑,因此您可能必须自己编写。幸运的是,它非常简单:它获取站点根目录(使用toSiteRoot),然后用于withURLs将一个函数应用于每个 URL,将绝对路径转换为相对路径。

relativizeUrls item = do
    route <- getRoute $ itemIdentifier item
    return $ case route of
        Nothing -> item
        Just r  -> fmap (relativizeUrlsWith $ toSiteRoot r) item

relativizeUrlsWith root = withUrls rel
  where
    isRel x = "/" `isPrefixOf` x && not ("//" `isPrefixOf` x)
    rel x   = if isRel x then root ++ x else x

(摘自Hakyll.Web.RelativizeURLs)。

您需要将这种过程与某种轻量级 CSS 解析器结合起来。它看起来像这样(在伪代码中):

relativizeCssUrls root = renderCSS . fmap relativize . parseCSS
  where relativize (URL url)
          | isRel url = URL (root <> url)
          | otherwise = URL url
        relativize other = other

我没有使用任何 CSS 解析/打印库,所以在这里我不能给你一个好的建议,但css-text似乎是一个不错的起点。

于 2016-09-09T21:28:39.627 回答
1

我走了一条更简单的路。我已经使用此代码来获取相对于当前项目的根路径:

rootPath :: Compiler String
rootPath = (toSiteRoot . fromJust) <$> (getUnderlying >>= getRoute)

然后创建了一个Context带有常量的字段:

fontCtx = do
    root <- rootPath
    return $ constField "fontRoot" root

最后,我将@font-face子句从 CSS 文件中移到 HTML 文件中,并在那里使用了我的字段:

    <style type="text/css">
        @font-face {
          ...
          src: url("$fontRoot$/data/bla.ttf") format("truetype");
        }
    </style>

事实证明,该上下文字段在其他地方非常有用,例如我也使用的 Javascript 代码中的路径字符串。

于 2016-09-12T10:04:51.117 回答