handlebars.js - Shiny Server 自定义 Handlebars.js 模板

标签 handlebars.js shiny-server

我对 handlebars.js 一点也不熟悉,但我想自定义 Shiny Server 附带的目录索引模板。具体来说,我要做的是呈现不同应用程序的缩略图页面。

文件/opt/shiny-server/templates/directorIndex.html 带有下面的代码,其中引用了许多表达式,包括 {{title}}、对应用程序、目录和文件的引用。

<!DOCTYPE html>
<html lang="en-US" xmlns="http://www.w3.org/1999/xhtml">
<head>
  <title>{{title}}</title>
  <link href='https://fonts.googleapis.com/css?family=Source+Sans+Pro:400,700,400italic,700italic' rel='stylesheet' type='text/css'>
  <link href='https://fonts.googleapis.com/css?family=Source+Code+Pro' rel='stylesheet' type='text/css'>
  <style type="text/css">
    body {
      font-family: Helvetica, Arial, sans-serif;
      background-color: #F5F5F5;
    }
    pre, tt, code, .code, #detail {
      font-family: 'Consolas', 'Courier New', 'Courier', monospace;
    }
    h1 {
      font-size: 40px;
    }
    a {
      text-decoration: none;
    }
  </style>
</head>
<body>

<h1>{{title}}</h1>

<ul>
  {{#each apps}}
    <li><a class="code" href="{{this.url}}">{{this.name}}</a> (application)</li>
  {{/each}}
  {{#each dirs}}
    <li><a class="code" href="{{this.url}}/">{{this.name}}</a></li>
  {{/each}}
  {{#each files}}
    <li><a class="code" href="{{this.url}}">{{this.name}}</a></li>
  {{/each}}
</ul>

</body>
</html>

所以我有两个问题。

首先 - 我怎么知道可以调用哪些表达式?

其次 - 假设我只有这个 html 页面(据我所知)我如何注册一个助手,例如
Handlebars.registerHelper('splitURL', function(url) {
  var t = url.split("/");
  return t[1];
});

最佳答案

我同样希望自定义 directoryIndex.html 模板,并且同样缺乏关于可以使用哪些 Handlebars 表达式的文档。我不是网络开发人员,所以这里的代码可能是垃圾,但它运行良好。听起来您已经解决了您的问题,但其他人可能会在这种方法中找到一些用处。每个应用程序的图像都保存在 site_dir/images 中。

screenshot of end result

目录索引.html:

<!DOCTYPE html>
<html lang="en-US" xmlns="http://www.w3.org/1999/xhtml">
<head>
  <title>{{title}}</title>
  <link href='https://fonts.googleapis.com/css?family=Source+Sans+Pro:400,700,400italic,700italic' rel='stylesheet' type='text/css'>
  <link href='https://fonts.googleapis.com/css?family=Source+Code+Pro' rel='stylesheet' type='text/css'>
  <link href="main.css" rel="stylesheet">
  <script type='text/javascript'>
    function include(arr,obj) {
      return(arr.indexOf(obj) != -1);
    }

    function updateView(data) {
      //update title and heading
      if ("title" in data) {
        var host = document.location.hostname;
        if (host in data.title) {
          document.title = data.title[host];
          document.getElementById("title").innerHTML = data.title[host];
        } else if ("default" in data.title) {
          document.title = data.title.default;
          document.getElementById("title").innerHTML = data.title.default;
        }
      }

      //hide cards (for directories like /images)
      if ("ignore" in data) {
        var element;
        for (var i in data.ignore) {
          if (element = document.getElementById("card_"+data.ignore[i])) {
            element.parentNode.removeChild(element);
          }
        }
      }

      //update each shiny app if it has JSON data
      if ("apps" in data) {
        for (var item in data.apps) {
          if (document.getElementById("card_"+item)) {
            if ("img" in data.apps[item])
              document.getElementById("img_"+item).src = "/images/" + data.apps[item].img;
            if ("name" in data.apps[item])
              document.getElementById("name_"+item).innerHTML = data.apps[item].name;
            if ("desc" in data.apps[item])
              document.getElementById("desc_"+item).innerHTML = data.apps[item].desc;
          }
        }
      }
    }


    function loadJSON(url) {
      var xmlhttp = new XMLHttpRequest();
      xmlhttp.onreadystatechange = function() {
        if (this.readyState == 4 && this.status == 200) {
          var data = JSON.parse(this.responseText);
          updateView(data)
        }
      }
      xmlhttp.open("GET", url, true);
      xmlhttp.send();
    }

    document.addEventListener("DOMContentLoaded", function() {
      loadJSON("data.json");
    });
  </script>
</head>

<body>
<div id="title_bar">
  <h1 id="title"></h1>
</div>

<div id="apps">
  {{#each dirs}}
    <div id="card_{{name}}" class="card" onclick="location.href='{{url}}';" style="cursor: pointer;">
      <img id="img_{{name}}" src="" alt="{{name}}" onerror="if (this.src != '/images/missing.png') this.src = '/images/missing.png';">
      <div class="container">
        <h4 id="name_{{name}}">{{name}}</h4>
        <p id="desc_{{name}}"></p>
      </div>
    </div>
  {{/each}}
</div>

</body>
</html>

data.json(位于 site_dir 根位置):
{
  "title": {
    "default": "Shiny Server",
    "dev_host": "Shiny Server (Development)",
    "accp_host": "Shiny Server (Acceptance)",
    "prod_host": "Shiny Server",
    "dev_host.fully.qualified.name": "Shiny Server (Development)",
    "accp_host.fully.qualified.name": "Shiny Server (Acceptance)",
    "prod_host.fully.qualified.name": "Shiny Server"
  },
  "ignore": [ "app_4", "app_5", "images" ],
  "apps": {
    "app_1": {
      "name": "app 1 name goes here",
      "desc": "app 1 description goes here",
      "img": "app1.png"
    },
    "app_2": {
      "name": "app 2 name",
      "desc": "app 2 desc",
      "img": "app2.png"
    },
    "app_3": {
      "name": "app 3 name",
      "desc": "",
      "img": "app3.png"
    }
  }
}

main.css(位于 site_dir 根位置):
body, html {
  font-family: Helvetica, Arial, sans-serif;
  background-color: #F5F5F5;
  color: #114;
  margin: 0;
  padding: 0;
}

#title_bar {
  height: 80px;
  background-color: #3475b4;
  overflow: hidden;
  border-bottom: 1px solid #3475b3;
  -moz-box-shadow:    0px 0px 10px 3px #BBC;
  -webkit-box-shadow: 0px 0px 10px 3px #BBC;
  box-shadow:         0px 0px 10px 3px #BBC;
}

#title_bar h1 {
  margin: 14px auto .5em auto;
  padding: .2em;
  color: #EEE;
  text-align: center;
}

#apps {
  margin-top: 14px;
}

.card {
  box-shadow: 0 4px 8px 0 rgba(0,0,0,0.2);
  transition: 0.3s;
  border-radius: 5px;
  width: 300px;
  margin: 10px;
  display: inline-block;
  vertical-align: top;
}

.card:hover {
  box-shadow: 0 12px 24px 0 rgba(0,0,0,0.2);
}

.card img {
  display: block;
  margin: 0 auto;
  max-width: 300px;
  max-height: 250px;
}

.container {
  padding: 2px 16px;
}

关于handlebars.js - Shiny Server 自定义 Handlebars.js 模板,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32207842/

相关文章:

javascript - 如何使用 Handlebars 排除数组/对象元素?

r - 在Shiny中获取用户IP

python - 用 Handlebars 制作美味的汤

jquery - 更新 Ember 嵌套模型和模板

java - 从 Spring JAR 读取文件

javascript - 如何解析 Handlebars 中已更改的 json 数据?

python - 如何在Shiny中通过R运行Python文件中的特定函数?

r - Shiny 编码

r - 以固定的时间间隔更新图形/绘图

R Shiny : Automatic wellpanel wrapping UI