Embed inline script in Drupal

話說最近跟某客戶在玩 Highcharts 這套動態圖表函式庫;而我們為了讓資料能動態更新,data 都存放在外部的 Google Spreadsheet 裡,因此無法使用如 EasychartCharts 等 Drupal 圖表模組。因此,如果要餵 Highcharts 吃存在 Google Spreadsheet 的資料,就必須手動寫 JS script 來進行設定。但在 Drupal 8 裡,這是有點麻煩的事情。

正統之艱難

在 Drupal 8,如果我們要在 Theme 或 Module 加入 CSS 或 JS,正統的方法定義 "asset libraries",再用不同方法 attach 到目標裡。那如果直接寫在 twig template、甚至直接寫在 CKEditor 裡呢?官方文件對此作法「高度不建議」(Inline JavaScript is highly discouraged ),因為會造成安全性隱憂。

但很多時候,例如我們需要對內容進行高度客製化,或是跟第三方工具整合時,還是不可能每次都把細瑣的 style 或 script 都寫到 Library 裡(那會多雜亂啊?)即使有 Asset injector 這樣的好用工具,在某些情形下也是無法發揮作用:例如使用 Entity Embed 把文章嵌入到其他 node 裡的時候,Asset injector 是沒辦法帶著跑的。

因此,我們還是會需要使用 inline script 或 style 的時候。不過同樣是在使用 Entity Embed 的情境下,如果我們把 script 或 style 寫在 CKEditor 裡,會在嵌入頁面造成原因不明的版面大爆炸 XD

作法

困擾了非常久之後,決定放棄正道。然後在內容類型裡增設一個純文字欄位,再把 field value 直接 print 在 twig template 裡。作法如下:

我們現在有一段 JS 要載入:

console.log("Hello Drupal!"); 

假設我們的純文字欄位叫做 field_script ,因此可以寫成:

{% set scriptvalue = node.field_script.value %}
{% if scriptvalue %} 
    {% block javascript %}
        <script type="text/javascript">
            {{ scriptvalue|raw }}
        </script>
    {% endblock %}
{% endif %}

快速說明:

  1. node.field_script.value print 出欄位值,設成變數 scriptvalue
  2. 要加上 raw filter,不然會輸出成 HTML 特殊字元 → console.log(&quot;Hello Drupal!&quot;);
  3. 我平常習慣修改 page.html.twig,但這段 code 則是放在 node.html.twig 裡,主要是因為在其他地方會用到 core modal dialog 功能(用來取代 Colorbox link dialog),而在這種 modal 對話框裡出現的 entity,並不會呼叫 page.html.twig,因此必須放在 node.html.twig

標籤 (Tags)