Drupal7表单定制和Drupal6大致相同,但是也有一些区别。这次我就来说说Drupal7是如何定制表单的。新建一个“form_theme”模块,然后创建一个表单,显示如下:
! P3 ?7 }9 w& F% d/ \2 }My name is [FORM INPUT] [FORM INPUT] and I am [FORM INPUT] years old.6 g$ H# F- ?% s( E& y8 h
这三个表单元素的默认值依次显示“First name”,“Last name”和“Age”,当用户点击某个INPUT时,该表单元素的值为空,然后你就能随意书写了。
- x% [" s/ W0 m Q! b这个简易的功能涉及到:
# l: c, q6 {6 p: @- 主题化表单
- 给表单添加JQuery(JavaScript)
- 给表单添加CSS, I" q7 h+ c1 Q3 S7 l0 U9 I. d
这个教程的主要目的是学习如何主题化表单,我不会对一些与主题化不相关的代码做过多地介绍。同样地,如果你想看懂这篇教程,你必须先知道:5 b N0 a) m T5 r( R' o
- 怎样在Drupal7中创建一个模块
- 怎样在Drupal中使用drupal_get_form()创建一个表单! U! D; M& W8 ~3 u8 Z$ L- s
我也不会对教程中的CSS和JQuery代码做过多的讲解,你可以直接复制并粘贴到本地去试验。呵呵,我的目的是如何将CSS和JQuery添加进Drupal中。& y0 z/ s$ u1 k; E( X9 P1 l% G: W9 L
开始吧!
6 X' Q0 s' n: R' B, E6 H1 A9 K$ S第一步:使用hook_menu()为表单注册一个路径
: |4 c7 v0 `7 L# f0 v我需要先注册一个页面路径好展现表单,下面是hook_menu()的实现:: J' Q8 G6 b/ s5 n8 g
2 Z; \8 F, G$ s, Q( O* ?<?php
8 N5 \+ h6 F; ]function form_theme_menu()
$ v. ~ U( h O* q! K/ U# O{
7 e: o+ V W7 k+ W# l3 Q) v9 X $menu['form_theme'] = array
8 h; d+ M/ H: r6 q/ h (' R! [! V M. t- w T
'title' => 'Theming Forms',; N: i4 q9 T" J5 i( l# t
'description' => 'Practicing theming forms in Drupal 7',
+ W; Z9 t9 Q O 'page callback' => 'drupal_get_form',
- l* o3 b u+ D; v4 L: ^ 'page arguments' => array('form_theme_form'),' ?4 p9 E/ r3 k6 d3 \! \& P* G% _
'access callback' => TRUE,
: \' H" h6 ?$ I% O );
! @7 i0 N8 k. `" G# s, s return $menu;
- r- p& P/ `/ y0 C$ l# Q b}3 S# f! w5 \ `5 K6 g# N
?>
8 R/ I4 W& k+ s; n" i/ v! h& }; v1 w. E6 I8 B: c4 c
第二步:定义表单9 Q' S8 \5 W; i( O5 s" o4 ~
在我的表单里,我需要三个textfield,表单定义如下:; \' ?0 C$ M. @6 W: R
6 }) A- Q/ |6 @, F* ]" |<?php5 w4 e5 K) g; I1 {
$form['first_name'] = array
: n8 g7 K9 J( r1 B, L(
; V# O3 V0 Z# g) E( ? '#type' => 'textfield',
! {: f& k' P- } E* {);
: I& N- j% e$ [: f1 n1 p$form['last_name'] = array% b& I$ x1 |3 B; E% h0 A# @
(* `) D8 T: S1 B
'#type' => 'textfield',
0 n9 ^" t+ k. w, X# S. y7 G);& O: S4 s% B& v G1 Z
$form['age'] = array' H# J3 d. s; r p, ]
(/ ?# K; o, H8 B5 V3 B, ~
'#type' => 'textfield',
/ d0 \0 }! x' Q '#maxlength' => 3,
: W8 a! ^3 |3 L7 A' U);
6 r9 ?8 k! @2 z( Y7 m?>0 B6 i( ]6 B" Z: |: a6 b
* Q' p& @) G; y+ a7 k
嘿嘿,代码十分简洁吧。我已经创建了这些表单元素,它们没什么修饰或其它配置。1 M `. z) E) C! e
然后,我需要添加CSS和Javascript到该表单。Drupal7有个新属性,#attached,我能通过它添加,代码如下:% ? t# l g. ]4 `) E m
3 G4 ], h3 M. Q4 U
<?php: S7 ^$ S7 S( |! L( \/ E
// Get the path to the module# W" V! Z F: C- }
$path = drupal_get_path('module', 'form_theme');7 }" E$ K- ]! p' y+ T. F& Y; F
// Attach the CSS and JS to the form# ~8 ]) e* k5 f& `
$form['#attached'] = array: ~. R$ y- c) P' a
(
7 l; U, ~; w- w+ ^# u& ?0 D* w. S2 M/ h0 ~ 'css' => array- v7 k* K2 Y! b1 v% d- _
(8 m% H& L# D9 k0 z& N! m' u2 m
'type' => 'file',: T1 B5 Q! Q6 c8 Z7 Q
'data' => $path . '/form_theme.css',) r4 x- | J. Y4 G& f6 {, O8 O5 M
),8 p: k. N' Z2 Q7 D T/ z
'js' => array& V3 x9 t* y- ]* o3 V+ S; ^) ]# I
(
6 `( F- t b- A4 \! r 'type' => 'file',- b9 I0 @& X3 w3 F# ^" ]
'data' => $path . '/form_theme.js'," }. H* A- A4 H. z
),+ b o, ~: T2 U. M# n
);
U& e8 d( C1 q7 U2 Q5 J* T* n?>: x' T% n4 ] C% P
* O. e( s z% B" m
这种方法相比drupal_add_js()和drupal_add_css()有个很大的好处,就是其它模块可以在该模块的样式和脚本的基础上做修改。
) [0 }& A) b) x4 b最后,返回我的$form表单,代码如下:1 q. u0 N$ n7 r
$ s$ c& Y- i6 `
<?php
9 U# `9 b& b( y, @7 }function form_theme_form($form, &$form_state)
* y9 m! o! `# }2 K/ L1 U{/ V, N4 z3 u! y p; x7 m
$form['first_name'] = array+ q' p; G8 ^7 g3 ~1 ^
(/ ^! Y2 ~* l) S7 Y& P
'#type' => 'textfield',
) K( J/ s5 j) Y );
( o1 U p0 E5 P5 ]. H9 ~6 t $form['last_name'] = array6 o4 M, Q* y* ~+ H
(2 K: d) M9 Z3 [% w+ d7 {6 d# q4 g
'#type' => 'textfield',
. R! F9 g: I9 \* Z: U' V );
) S6 ~* k9 b, \ $form['age'] = array( r- q3 [0 c+ |5 D& F
( \- ^" ]7 y" F5 q+ {9 g8 w
'#type' => 'textfield',
3 V0 q+ w0 H( F* `9 { '#maxlength' => 3,
* F4 C4 i1 W0 s" S );
. R" w) Q: g8 t! V, p // Get the path to the module
8 v% k7 q% s4 }# W* v7 l c" F/ q/ N $path = drupal_get_path('module', 'form_theme');; H( B* D$ n9 ]8 m* j4 s$ k
// Attach the CSS and JS to the form
0 I# D/ w ]" t2 [3 z$ X $form['#attached'] = array( t5 j' O4 `" H
(
; U: P8 r5 X p- s$ q* L8 e 'css' => array
# S M" D# } C* L0 r (
- T' x* J: g: M# g' p 'type' => 'file',; P8 @5 p/ M- }1 ]$ D$ W
'data' => $path . '/form_theme.css',7 H s4 Q, ], s" v7 G7 B% N" w
),. G( Y" J" Z; r% t" R
'js' => array
; J3 f; }) Z# a$ G8 ]% T! I (
X4 C: N, T: }1 @8 \& Z+ f" S 'type' => 'file',
$ d! n% l, L/ | 'data' => $path . '/form_theme.js',$ i6 ] J1 G( Z) y
),
/ l) e5 b; V5 ^% D% L );1 o4 ^( e$ f' e8 U
return $form;7 t! }* B9 p6 q8 A* B
}
& O5 P) q4 s- L9 `?>
5 _; `1 T" ~1 h: M) _$ ~2 R% a
7 x w1 F3 ]4 T& D' b3 s' f6 t$ X第三步:用hook_theme()注册一个主题函数1 N$ @& y% x1 {
从Drupal6开始,主题函数就需要通过hook_theme()注册,但是在Drupal6和Drupal7中还是有些细微的区别。在Drupal7中,表单的主题函数不是使用“arguments”,而是使用仅仅只有“form”一个值的“render element”。在注册主题函数时,你必须让索引和你已经定义的表单函数保持一致。代码如下:( K3 y4 b _6 ~/ T) A/ C% R. M% M
6 ~/ t+ R# n8 Z/ n
<?php
: {, N/ u* Y- W) M. g% F6 ufunction form_theme_theme()' H# v" f v+ |, e5 u
{- s7 l! b& I" y' ? ^3 d
return array
3 T ]% ]3 ]* D g0 ?* C$ G) U (
r4 p- [; d+ ]4 O* B" w 'form_theme_form' => array
& S2 X3 M5 m: P1 F* l& R, w' q! p) ` (/ h: D, `# `6 k$ \/ u4 E8 A
'render element' => 'form'
, [% j9 g) M( b" j ),' Y) s8 [- \& C& i5 \
);
$ G6 T+ `- j- F; M0 g3 }2 ^}3 u( l, R& } G6 |! p& H" M
?>
+ ?; S/ |8 W. z, @; u- t( x
* Q6 Q% o% v4 B A. Y4 w d正如你所见,我已经注册了一个主题函数。主题函数的命名十分重要,因为这个主题函数跟表单有相同的名称,Drupal在实现这个表单时会自动调用该主题函数。我也不需要添加#theme到我定义的表单$form中,这是多余的。# y" d; M- c# q% f2 Q
第四步:写主题函数8 L! v; e! w1 I8 g0 Z
在Drupal7中,写主题函数,有几个注意点。它们是:
3 Y9 u( S) F9 [8 ^# E6 M- 函数只有一个参数,命名为$variables的数组。$variables有一个form索引,该索引的值就包括所有你已定义的表单元素。
- 所有的表单元素必须要作为参数传给drupal_render()函数。这个函数能将一个PHP数组转换成HTML,并且将Javascript和css添加进去。这些Drupal会自动帮你完成,你仅仅需要传递这些参数就行了。
- 在写主题函数的最后,你必须将剩余的表单元素传给drupal_render_children()函数,这样才能将剩下的或隐藏的表单元素转换成HTML。这是跟Drupal6一个很大的不同。在Drupal6中,我们直接传递$form给drupal_render(),但是在Drupal7中,这样做就会导致死循环,而且不会出现任何错误提示。, q1 r' H$ ~, O6 T
主题函数是以“theme_”加上我们上面注册过“form_theme_form”命名的。代码如下:/ d" v5 r ?$ d2 l
) Y9 `/ M3 K6 O<?php! J# m$ D3 r M# s3 x( G* M& _1 N
function theme_form_theme_form($variables)
! U; E! F; q! |. B{& e& f9 U2 L! ]8 e6 d8 K
// Isolate the form definition form the $variables array- F& D$ z- o2 B7 ~- k7 q
$form = $variables['form'];
) O* E3 b n4 [2 T4 V$ M4 ~, r* o $output = '<h2>' . t('Please enter your information below') . '</h2>';9 ^3 _+ L6 F$ ~8 o* \! N
// Put the entire structure into a div that can be used for1 N6 ~5 N8 Q7 r. B
// CSS purposes. e& U) P; U# J! r6 Z6 s( k
$output .= '<div id="personal_details">'; r+ s p5 v/ t; R$ Q) ~; S
// Each of the pieces of text is wrapped in a <span>" g* `9 U8 C5 B
// tag to allow it to be floated left
, Q4 P, v/ i6 Z$ X% { $output .= '<span>' . t('My name is') . '</span>';
% M( i# K7 J! {/ p0 e. o8 \ // Form elements are rendered with drupal_render()
~" O: ?: P4 q $output .= drupal_render($form['first_name']);; C% k D% k. i8 V5 u$ }
$output .= drupal_render($form['last_name']);* B* U3 G( ^' _$ m& F
$output .= '<span>' . t('and I am') . '</span>';
3 |5 c0 Z8 R$ \3 Z9 _ $output .= drupal_render($form['age']);9 O( H# Y/ K1 h+ l
$output .= '<span>' . t('years old.') . '</span>';7 B. J! u. d0 W2 ~, m
$output .= '</div>';7 ]! _% ]: X) V, a7 a
// Pass the remaining form elements through drupal_render_children()
" F6 i" C7 S& S' X! t $output .= drupal_render_children($form);, R( ~( s( J- v* i6 f1 M+ G$ v
// return the output
1 W/ i. v W3 }, q; Z# P return $output;7 u* |5 c2 x8 Q
}
; P+ \3 t3 r+ R- x6 i0 h# k& l" U) r?>* c% `6 c/ k% B: U3 r* i5 L
$ [* W5 W6 k" B) P4 y+ ^( e/ L9 t
到这里,我已经完成大部分的内容,定义表单,注册主题函数,实现主题函数。但是我还没添加CSS和Javascript。3 {! D- A- s9 U' r' H. o
第五步:创建CSS和Javascript文件' k6 R+ _) P: T1 }
在第二步中我添加了CSS和JS路径,这两个文件都在form_theme模块的根目录。CSS代码如下:
4 r. K$ R4 K$ }
w8 K3 R8 r; @6 N#personal_details span, #personal_details div
% x1 @+ o* n/ T{
% Q) d0 Z+ a5 ]. P$ \& ufloat:left;+ p) y) K6 H4 [
}
. ]. }) s) x4 O; ~
2 z7 K" x- P6 S#personal_details .form-item-first-name, #personal_details .form-item-last-name
8 e/ W* ]: m: v- |2 }8 M' G{
3 ]0 q: G; Q" j. p: A) e8 Zwidth:115px;$ G2 w4 ~$ t' a7 i
}7 y: y; L8 x( ]7 s6 s4 O& M8 [ o# j" @
+ @8 { _9 T9 Z( J" Y4 I#edit-first-name, #edit-last-name% h; }" w: K4 J8 b
{
& }5 |* X7 K, ?) awidth:100px;
/ d) n2 K# b& F}
6 W7 O" y$ D7 }/ l; j2 Y, p. R; R, u1 r$ e( k
#personal_details .form-item-age
2 w0 }* G/ F) B, W1 _. I4 U{( [! _0 n1 g% D! ]
width:50px;3 J! M. H7 f! Y/ c. [, {
}
& M: H& u# ]9 [* j0 a2 w
8 w5 M4 i8 `" X5 [#edit-age$ Q" M5 a3 h+ ^
{
' n6 B; p% u4 owidth:35px;
$ h+ F/ r. S% y}
5 h' g+ U8 ^# j1 v- E2 e3 m) I- ~" J0 T' |. \
#personal_details span$ z$ a! l9 p. O( R f
{
8 z! }1 ?' @1 K1 wmargin-right:5px;
. t9 B8 k, k# k+ l6 o% f* upadding-top:5px;
. j& z1 o. m1 Z3 m}* I1 m/ O# k8 n, a) O
1 W0 P( w, V' k, V0 t. ]+ ^% VJavascript代码如下:6 U5 K% p# t& G q1 c' D( @4 @2 t
6 r+ J7 X* u* \8 \; C0 \7 g
// We wrap the entire code in an anonymous function1 d" A5 D) ~4 t
// in order to prevent namespace collisions, and to0 ~! T, Y. \, f4 G
// allow for jQuery to be set in a safe mode where% @: O- e2 ?3 ~( ]6 Y3 V. L; \
// it will not collide with other javascript libraries.& Q# l7 O) u: @3 i
// While this is the proper way to do it in Drupal 7,! T) v# [, c9 E2 S# ] ]; s
// this method is actually good to use in Drupal 6 as
3 ~6 ?$ \& c0 y0 P! v9 V/ ?3 o4 Q// well, for the same reasons.
+ r6 ~! n) C0 t$ l* W(function($); F9 [* H6 h0 K% w; m
{3 Y% w; E/ f2 s3 w, w8 O! i9 S
// In Drupal 6, each element of Drupal.behaviors" i' F! r) D1 C$ O5 @' ~
// was a function that was executed when the0 O" E, m+ R9 t
// document was ready. In Drupal 7, each element9 {& h4 @1 c5 K9 n2 i/ b
// of Drupal.behaviors is an object with an5 I$ K+ M8 u* ` ]2 `3 M U
// element 'attach' (and optionally an element8 `7 h" ^8 j. H4 C5 L
// 'detach'), which is executed when the document2 j, j2 \ k) s* M* p1 a0 Z* T0 \: \
// is ready5 t0 [- G7 E8 i& @" |* t, `
Drupal.behaviors.formTheme = {9 h# F E1 @# j1 X) _3 P
attach:function() {
+ w1 t3 B4 a: ^+ E3 H1 l// First, define an empty array& E l. X; ?, k' o
var defaults = [];% E$ A, H' S& B$ I
// Next, add three elements to the array, B. w$ ~/ F. H2 B7 G* \
// one for each of the form elements. The value0 Z6 W- A) W+ c: U& z
// is of the array element is set as the default2 U5 ]7 K5 d1 U
// text. This text is run through Drupal.t(),
( S4 X+ q1 v q+ s* v0 {" {// which is the Drupal JavaScript equivalent
" M$ ^( U" M: d! D) A) _// of the Drupal PHP t() function, and allows s/ J: v& j9 S% m; D5 x
// for translating of text in a JavaScript document
J6 D& R' {/ L* o/ Mdefaults["#edit-first-name"] = Drupal.t("First Name");3 F2 w* a5 O7 g4 ^7 B+ f
defaults["#edit-last-name"] = Drupal.t("Last Name");
& M1 t( v' R* B0 [- y9 xdefaults["#edit-age"] = Drupal.t("Age");7 l' G# t8 H, \6 C
// Next we loop through each of the elements of the array
' x$ A. [% q! j3 v! i8 y2 M! wvar element;
+ G6 v I; }8 Y# Ufor(element in defaults)
: e. y7 T% _# [- M" i$ z$ `$ r{
2 i3 N; q8 z7 x) r// We wrap the body in the following if() statement! A* c# ~& U) J |
// as each element in an array will also have a4 a4 _% l& Z6 B0 D. k
// prototype element. If you don't understand this,
3 w( C" E$ c6 P; o/ S3 S: G8 k// don't worry. Just copy it. It will make your: V' h* c" f' T+ o1 O7 u( O
// for(A in B) loops run better.& o& E% p5 k: p4 h
if(defaults.hasOwnProperty(element)) {1 L0 B+ K: O2 w, U
// 1) Set a placeholder in the form element( e- B8 ~+ H3 F1 ~* `3 K8 \
// 2) Set the CSS text color to grey for the placeholder3 _8 H9 D. U0 P6 W8 _8 |) j
// 3) Attach an onfocus and onblur listener to each element
: i3 s1 w* f4 n8 m4 k1 v# J- U; C$(element).val(defaults[element]).css("color", "grey").focus(function()
: X/ M, @. L8 Z7 z5 o5 F{0 E8 C* S7 F* b! e% ]8 t) M6 [) x
// This is entered on focus. It checks6 F1 y' d- r* O" Z5 E8 m8 R0 R
// if the value of the form element is" p v6 ^' H8 H8 _4 p
// the default value of the placeholder,& [9 G6 Y( ]" F+ p
// and if it is, it clears the value and5 e9 d9 J) e% ]; |& @
// sets the text color to black,as the
# }* ?9 r P4 w" E, W; S2 |// entered text will be the actual text
- A( {% Y' l; f// and not the greyed out placeholder text.9 M. |2 l4 Q' H4 Z0 Z n
var key = "#" + $(this).attr("id");
. C# D) I' e: I; ]1 [ y6 m8 kif($(this).val() === defaults[key]) {
0 \& p2 e9 i+ B$(this).css("color", "black").val("");
& F$ R6 n0 P! V5 h L0 k}% }: x0 a/ A) t+ Q/ q4 N
}).blur(function()
9 K% e6 K& _& Z, w: k8 s% D/ f+ x: ~{1 B1 u/ ]) m' R O9 N0 R
// This is entered on blur, when the element4 i7 O7 `5 r! J% Y1 i
// is exited out of. It checks if the element
) u& r. ?! ?7 w3 R0 A. W$ \6 l* s// is empty, and if it is, it sets the default6 ?( ]( N; K+ Q% z
// placeholder text back into the element, and' r' C' ~1 Q' F0 V; V$ l
// changes the text color to the grey placeholder
/ s* {3 L8 I3 ~ s// text color.$ q; Y/ @1 ^' l1 @: n7 c
if($(this).val() == "") {
, `( s* h5 }& i2 K: k' j# }var key = "#" + $(this).attr("id");
4 n6 d6 e5 K# L( T8 @; I! ^$(this).css("color", "grey").val(defaults[key]);
) b! `& o$ M. R( }}
3 ~! m# Q2 l5 s});
8 K# G0 L: G x* |5 T}
% k7 i( R/ A9 c2 p1 \$ z}/ T6 i, y9 A0 n( }0 ~8 g. |& G
}
$ T5 W9 W! e# r' ~0 o x3 F};
- Y+ H% t6 u" T! M: ]}(jQuery));
! I$ p& j) s# ?8 z. V* I, M' ^/ q. U. M6 ?
好了,你可以试试看。
. B! D& c! N$ P1 L) j1 r原文出自:http://junepeng.info/zh/node/28
. K7 I; w% f. Y4 R* H- t* {$ V: x5 o: K
- s8 ~* U( V2 z5 b
$ V. `2 p5 ?- F7 t+ d7 O2 X: Q9 f+ D4 c+ M
" r$ @# U# R5 s* b- R& h( h" p8 w# s( E% E' F
|
|