form 也可以使用template (*.tpl.php)

AttachmentSize
Image icon form_template-1.png61.58 KB
Image icon form_template-2.png48.92 KB

2011-06-21 更新 6.x 版的代碼(概念一樣): http://www.joetsuihk.com/form_%E4%B9%9F%E5%8F%AF%E4%BB%A5%E4%BD%BF%E7%94...

一個成熟而功能強大的Drupal,
除了使用內建的功能之外
一般都加上很多的模組, 以符合網站的需要
但簡單的一個新增node 的form 已經複雜得令人眼花燎亂

最好還是簡單的只留下Title, body, taxonomy 好.

這次從這個實例中嘗試控制theme() 函數,
令得出的HTML 符合實際需要, 消去不必要的元素

修改難度中級左右, 要懂得一點點form API,
基本template, phptemplate engine
記得一邊看一邊實驗哦

首先, 要知道任何新增node 都會使用 函數 (node.module line 2146)
函數會用drupal_render() 函數,
將$form 陣列變成HTML form
再返回這個form.

Drupal 內所有用theme_ 開始的函數都可以被 template.php 內的 phptemplate_ 函數取代
所以, 只要新增一個 phptemplate_node_form() 函數到 template.php
複製theme_node_form() 函數內容到 phptemplate_node_form()
再修改函數內容, 就可以自己定製一個對特定theme 有效的 node form 了

theme_node_form() 的內容可能比較複雜
但因為這個例子比較有用, 普遍有實用性, 故選之
文章結尾部分會再詳細探討修改的方法

但如果有很多theme_ 函數要修改, template.php 會很大
而且很難維護, 一個檔案大於一千五百行就會令維護的工作以幾何級數上升
所以要借用Drupal 6.x 的一個概念, 使用 *.tpl.php 作 node_form 的template.

建立一個node_form.tpl.php,
然後在phptemplate_node_form() 內,
用類似呼叫node-contenttype.tpl.php 的方法, 找出 node_form.tpl.php
並使用它代替原本於 phptemplate_node_form() 內的php
實際操作很簡單,
template.php:

<?php
function phptemplate_node_form($form) {
  return
_phptemplate_callback('node_form', array('form' => $form));
}
?>

_phptemplate_callback($hook, $variables = array(), $suggestions = array())
定義於drupal/themes/engines/phptemplate/phptemplate.engine
傳入最少一個, 最多三個參數.
第一個是 *.tpl.php 的 * 號的預設字符
上面的例子傳入 'node_form', 函數就會找一下 node_form.tpl.php 使用了
第二個參數是一個array, 給 *.tpl.php 的變數, 例子用了array('form' => $form)
前面的 'form' 在 *.tpl.php 內存在, 後面的 $form 在 phptemplate_node_form() 內存在
最後一個是array, 提供一個優先於 $hook 的一個template 名字的選擇.
node_form.tpl.php 內只要使用原本於theme_node_form() 內的php 就可以了

最後的一個部分, 終於到了改theme_node_form() 的內容了
node.module line 2146 原本的內容:

<?php
function theme_node_form($form) {
 
$output = "\n<div class="node-form">\n";

 
// 將author, option 兩個選項放到$admin, 以放到form 的最後
 
$admin = '';
  if (isset(
$form['author'])) {
   
$admin .= "    <div class="authored">\n";
   
$admin .= drupal_render($form['author']);
   
$admin .= "    </div>\n";
  }
  if (isset(
$form['options'])) {
   
$admin .= "    <div class="options">\n";
   
$admin .= drupal_render($form['options']);
   
$admin .= "    </div>\n";
  }
 
// 將按鈕都組合到一起, 備用
 
$buttons = drupal_render($form['preview']);
 
$buttons .= drupal_render($form['submit']);
 
$buttons .= isset($form['delete']) ? drupal_render($form['delete']) : '';

 
// 全部餘下沒有用drupal_render() 的$form 都會在此變成HTML(即除了admin, buttons 以外的全部)
 
$output .= "  <div class="standard">\n";
 
$output .= drupal_render($form);
 
$output .= "  </div>\n";

  if (!empty(
$admin)) {
   
$output .= "  <div class="admin">\n";
   
$output .= $admin;
   
$output .= "  </div>\n";
  }
 
$output .= $buttons;
 
$output .= "</div>\n";

  return
$output;
}
?>

drupal_render() 會將傳入的參數返回, 變成HTML
最後一個的drupal_render() 傳入整個$form
會將全部還沒有render 的inputs 變成HTML
最後返回HTML
要留意的是node_form.tpl.php 內不應返回HTML
而是:
<?php
 
print $output;
?>
<?code>

上面的例子將某些選定的form 用一個<div style="display:none;"> 包起
令用戶看不見, 但form API 看得見
例如要隱藏log textarea , 先在node_form.tpl.php用 print_r($form);
看看$form 內那一個控制log textarea
得知是$form['log'], 就:

<?php
$hidden
.= drupal_render($form['log']);

//input format
$hidden .= drupal_render($form['body_filter']['format']);

//comment settings
$hidden .= drupal_render($form['comment_settings']);

//放$hidden 到output
$output .= "<div style='display:none;'>$hidden</div>";
?>

放在最後一個drupal_render($form) 之前就可以了

最後, 其實phptemplate_node_form() 還可以做很多東西
例如只令用戶id = 1 才使用 *.tpl.php,
實際操作我還先查有沒有 [contenttype]-node_form.tpl.php
如沒有, 用回 theme_node_form()等等, 非常強大而靈活

CSS 的規則繼承和權重

路過 CSS specificity for poker players
這篇關於CSS 承繼規則的確不錯
CSS 是一種承繼的語言, 一個<a> 可以同時承繼兩個style
比如

a{color:#000;}
p a{color:#f00;}

那究竟瀏覽器要如何決定一個<a> 的顏色?
就是這一篇所述的內容了

這一篇用了撲克牌的比喻解釋, 簡單易明, 所以翻了一下,
但記得先要有基本的CSS 知識才可.

翻譯:
CSS 是由元素(element), class 和id 組成CSS 規則的
元素例如 div
class 例如 .sidenote 代表元素有一個屬性 class="sidenote"
id 例如 #navigation 代表元素有一個屬性 id="navigation"

單Aces 為最大:

最弱的規則是只有元素的規則

h1 p { font-size: 1em; }

Pseudo-elements, 例如 :first-line 也是元素級,
所以以下的規則是相同的權力

p:first-line a
div p a

在只有元素的規則內, 多元素代表高權力
會取代低權力的規則
因為我們都知道5 勝3
5個元素:

body div div h1 p

勝3個:
div h1 p

.

相同權力時:

如果有兩個相同權力的規則,
後出現的會勝出
這裡沒有一個好的撲克規則作比喻,
但在21點內, 莊在後, 也勝平手的

一對勝單Aces

就算一對的2 也會勝Aces.
同道理, 包含一個class 規則會勝任何多的元素規則

p.introduction
<code>
...或只是...
<code>
.introduction

...勝...
html body div div h2 p

還有, 一個class 規則不一定要是使用到最後一個的元素
這個規則一樣會勝過任何元素規則:

div.introduction p

也即是說只要有一個class 規則都會令你勝過所有只有元素的規則

當然, 多class 規則也勝少class:

div.content div.summary p.intro

...勝...
div.content div p.intro

Pseudo-classes 例如:link, :visited, :hover 是class 級
所以以下的規則是同權力:

div a:link
div a.friend

.

三條勝一對

三隻牌相同勝一對
有id 規則的 CSS 會勝任何class

#content img

...勝...
body div.wrapper div.summary p.intro img

更多id 規則也勝少id 的

Full house (AAA22, JJJ55, 66622)勝三條
你也可以估計Full house 勝三條的
同時使用id, class 規則勝只用它們其中之一

div#content.summary li

...勝...
div#content ul li
div.content div.secondary li
div ul li

.

小丑是無敵的

! important 關鍵詞就是撲克內的小丑牌.
"! important" 規則會令你跳過所有其他規則

但這規則是不建議使用的
你很容易會令全個css 檔都是"!important"

建議用法

寫CSS 都有一套策略
令整個檔案更直觀, 修改容易

  1. 先放一般性的規則, 例如body, a, 以定義一個基本的頁面風格
  2. 再用不同的class, id 定義一些地方(.description, .error)
  3. 最後是特別的區域, 例如#primary-links a

避免一開始便定義高級的規則, 例如

div#pagewrapper div#contentwrapper a

否則你便要用很多特定的規則了
所以要用點策略, 慢慢的建立
從一般的頁面開始, 直伸廷到特別的元素, 地區

譯注:
譯完以後發覺很多撲克的用語是很難譯的
中間有不少的內容都太重覆
所以刪減了一些例子, 比喻等等
希望文章不要太長

其實使用firebug 就會顯示出由最高至低的css 權力
已經十分方便, 但因為IE 在CSS 權力上好像有一點偏差
多認識一點還是好的

Pages

Google