Drupal7表单定制和Drupal6大致相同,但是也有一些区别。这次我就来说说Drupal7是如何定制表单的。新建一个“form_theme”模块,然后创建一个表单,显示如下:
0 g6 t& H. D9 J4 l( `My name is [FORM INPUT] [FORM INPUT] and I am [FORM INPUT] years old.* a6 H, @4 `- v) ? l B
这三个表单元素的默认值依次显示“First name”,“Last name”和“Age”,当用户点击某个INPUT时,该表单元素的值为空,然后你就能随意书写了。
: V5 m) i/ J, u; [: K! Q; k这个简易的功能涉及到: ?/ M5 {* z0 A; W% f7 S e
- 主题化表单
- 给表单添加JQuery(JavaScript)
- 给表单添加CSS
: ]4 y6 [. o5 W) ~1 b- w: B, d 这个教程的主要目的是学习如何主题化表单,我不会对一些与主题化不相关的代码做过多地介绍。同样地,如果你想看懂这篇教程,你必须先知道:
9 V" r k5 L2 a( U$ n# k- 怎样在Drupal7中创建一个模块
- 怎样在Drupal中使用drupal_get_form()创建一个表单& j5 ^) C6 k: B+ C
我也不会对教程中的CSS和JQuery代码做过多的讲解,你可以直接复制并粘贴到本地去试验。呵呵,我的目的是如何将CSS和JQuery添加进Drupal中。
+ K* h( g0 g% `: n开始吧!
4 R( `0 m3 F6 ?5 k* M e9 A第一步:使用hook_menu()为表单注册一个路径. k+ x& I3 i9 P: ^
我需要先注册一个页面路径好展现表单,下面是hook_menu()的实现:
' m: ? `5 z5 o' S+ f8 w! R* O6 t! D! k) J: X+ k* `% q
<?php
! P! f* o& D8 o, I4 |function form_theme_menu()7 @! e. o& \. \5 g, S" p
{
$ A; ^, P8 L5 x' n $menu['form_theme'] = array
# G z* W* W) y: L4 h) k7 L () f9 F9 c3 ]5 ~9 |5 h8 S: b( r7 t
'title' => 'Theming Forms',: _8 H$ `3 `% ?8 C. N
'description' => 'Practicing theming forms in Drupal 7',% e. H3 C3 s k
'page callback' => 'drupal_get_form',% B, O& j5 S0 p. D- r2 ^- P' [! ~
'page arguments' => array('form_theme_form'),% q9 _" {$ s; x+ P
'access callback' => TRUE,
8 P& ~( y2 R( @0 ` );
. N3 N# l3 G+ p# N3 j& o! }( v return $menu;7 R+ q. ?4 X; p, r% m! Y. D
}
' Q! L1 s2 a9 e; P$ U$ B4 A; F# G?>: h8 R3 c8 h; V3 w* i) H. L
! C; Z' K2 q; \6 H0 u
第二步:定义表单% { p2 A' ?. F
在我的表单里,我需要三个textfield,表单定义如下:
1 a9 w B+ b4 d' y9 x
# f8 p' M4 [0 I# c3 M2 t1 U<?php
1 I1 D/ @3 z U f$form['first_name'] = array
3 N' \- a6 t5 E9 a C4 V1 W(1 ^( Z( O0 E* I0 W9 X% A- [' g: E' Q
'#type' => 'textfield',
8 c- T5 J1 s& ?- l0 I7 ^ \);
3 m& v5 q& {5 x1 B$form['last_name'] = array
; b9 [+ h9 @- l9 H(* \: g$ J, @5 _! S! i1 w
'#type' => 'textfield',# H, Q) P! M' ~: p/ o! F
);
+ L; }( v+ z2 }5 m- p9 e8 O$form['age'] = array5 d4 V V. I2 w
(# Y) Y- M& ?+ ]5 u
'#type' => 'textfield',
. N* {% C( X B$ x' k. G '#maxlength' => 3,: P9 I$ @0 n2 {$ ^' H% k" {
);
6 K( ^# e* V$ G& h; i( {! s8 M?>
% @/ s5 ~( T& J9 e. ^& g
! N' ?$ T$ _2 A0 g. W- b5 c( m- j嘿嘿,代码十分简洁吧。我已经创建了这些表单元素,它们没什么修饰或其它配置。
9 m) {8 y/ r' o- n4 G& U然后,我需要添加CSS和Javascript到该表单。Drupal7有个新属性,#attached,我能通过它添加,代码如下:
6 G+ x, y* Z/ w" D( }0 B. z& Y7 b( O. q- ^8 c4 ?- O
<?php2 @* [) ?; P1 t k
// Get the path to the module
, V) e$ a/ [- Q0 h$ J: {2 H- S2 n$path = drupal_get_path('module', 'form_theme');
1 ^ S2 D5 i a! _- C! D G, a) [; ^// Attach the CSS and JS to the form
2 E5 W; [) t- B( _- r0 l$form['#attached'] = array0 O" o v; i6 e N; K
(
" ~9 b+ t0 W; s3 X! c0 n/ a! u 'css' => array5 |0 c) g& n% J
(
2 p0 b: P! G4 m" G% I& g8 k9 b! X1 x 'type' => 'file',
+ K% R- c) K) w+ g3 N. n1 J 'data' => $path . '/form_theme.css',, s. t9 }+ q) E, f, e" h/ K+ F/ A
),
& X: @- ]# K- U% _8 l# c 'js' => array) Z9 E% _2 G6 i4 u7 I8 i w3 r+ L
(0 J* ?! X# Z3 p1 c+ `% N
'type' => 'file',
9 q/ B" [1 B; p2 N1 ~ 'data' => $path . '/form_theme.js',/ Q1 b3 @- ]6 H9 {$ `
),
7 o2 H9 x) `; F, I [);
3 u1 U) G6 v, @$ ^?>1 P* c$ ^ a; q' f' c8 P; r' M* D
- k6 |! o$ h0 C% W这种方法相比drupal_add_js()和drupal_add_css()有个很大的好处,就是其它模块可以在该模块的样式和脚本的基础上做修改。2 z5 x0 d1 E+ T9 K4 |1 j! r
最后,返回我的$form表单,代码如下:
: n9 K- K" S t$ P; c7 C" Q4 f
* v; o9 C, T8 |- U {<?php9 ]. U7 C. ?7 G( \
function form_theme_form($form, &$form_state)
' Z& W* V0 s8 c% u* _{3 V% d, V1 Y2 A1 v1 L6 @" Y) A3 p
$form['first_name'] = array
# }3 ^( }) Y$ B' w- H- A) `# U (& W% J7 ^; W" n6 f* g% i$ C
'#type' => 'textfield'," i7 [" `9 s$ h4 W' w- E/ {( S
);
+ ]( o7 G3 W! T; w $form['last_name'] = array- S$ S; S7 z* _, Z( ]
( Y, D. ?* j$ j/ M) ?) d
'#type' => 'textfield',! e$ f3 \4 R0 }# h$ P8 c
);
7 o3 E, _. Y" P* c; N5 l $form['age'] = array
4 X4 w) [9 p' |! S4 {) q! ]) e (5 y1 ^# |# m% a0 Q
'#type' => 'textfield',/ S0 Z) B6 x! E+ d9 c
'#maxlength' => 3,
& i% h* s) i1 l# e0 I# H );) H# t& R, J5 `" ~; J0 w% x1 ?& K
// Get the path to the module: K8 X* H' g+ _) x" k
$path = drupal_get_path('module', 'form_theme');# A9 E( X0 k/ t: u. p) ^- x/ h
// Attach the CSS and JS to the form
6 }" M7 l: |" n* m. | $form['#attached'] = array, V+ F6 W0 o4 |
(
3 |/ {. d! S& h4 t; { 'css' => array
- B' B! D$ ]" e& p (
$ H7 U0 r9 Q! K P& Z' L 'type' => 'file',. c+ @0 g# d( O& \6 `8 o C2 ~& S
'data' => $path . '/form_theme.css',, z$ _* e% k+ c4 N
),
2 p) J* `# s& M7 W- W1 g9 r 'js' => array
' P+ Z8 w2 }, A1 _% _' e" x4 H (% ^" u2 x# p8 d; g# {- o8 e3 @
'type' => 'file',( A3 K6 i5 I; l. @4 M
'data' => $path . '/form_theme.js',
/ p, ]2 q- N( v ),
6 H: T: K! [% F& _3 p$ c );$ }8 j& `" D* h/ q. H
return $form;
) [& a. b; `+ x/ w1 B! l}
2 F: L: _+ B1 F4 p* ??>7 B3 J0 M F. {+ }' N. ]+ e
% Z# h3 z% b4 w, z% e p
第三步:用hook_theme()注册一个主题函数
' V& U# _" e6 S. K! {7 S从Drupal6开始,主题函数就需要通过hook_theme()注册,但是在Drupal6和Drupal7中还是有些细微的区别。在Drupal7中,表单的主题函数不是使用“arguments”,而是使用仅仅只有“form”一个值的“render element”。在注册主题函数时,你必须让索引和你已经定义的表单函数保持一致。代码如下:& z* ^5 T! A% P3 O* b; z
4 T* I+ w: U* I, v<?php
, r) a$ Z! w# v/ E/ Q3 Q ~function form_theme_theme()7 c3 F7 R: ?# j+ T" V8 F5 Z
{( c7 F! f+ Y; X9 M7 V9 |1 p$ l
return array
! P( U- m+ b4 Z4 u/ n (
' q6 X6 [7 L {# w! A3 X3 p- e 'form_theme_form' => array
3 y. }/ v( G& ]7 ~ (5 v7 f# u# Y; B+ q* u
'render element' => 'form'7 V! Y. n! R: T) D& ?
),
5 J+ C, i+ _2 j+ B );, Y. U$ u8 c% Y
}, q( L7 ~ a( E. g( b/ }. [' T H1 X
?>
0 P) n! D1 v, C- A, [8 s9 m9 ]$ b) o: Z6 w+ @* v
正如你所见,我已经注册了一个主题函数。主题函数的命名十分重要,因为这个主题函数跟表单有相同的名称,Drupal在实现这个表单时会自动调用该主题函数。我也不需要添加#theme到我定义的表单$form中,这是多余的。
- H# N& I/ e; E f6 H第四步:写主题函数( w$ i7 Y7 ]. \- o' K% S$ K
在Drupal7中,写主题函数,有几个注意点。它们是:
3 I* ?4 j4 k- }0 n9 P- 函数只有一个参数,命名为$variables的数组。$variables有一个form索引,该索引的值就包括所有你已定义的表单元素。
- 所有的表单元素必须要作为参数传给drupal_render()函数。这个函数能将一个PHP数组转换成HTML,并且将Javascript和css添加进去。这些Drupal会自动帮你完成,你仅仅需要传递这些参数就行了。
- 在写主题函数的最后,你必须将剩余的表单元素传给drupal_render_children()函数,这样才能将剩下的或隐藏的表单元素转换成HTML。这是跟Drupal6一个很大的不同。在Drupal6中,我们直接传递$form给drupal_render(),但是在Drupal7中,这样做就会导致死循环,而且不会出现任何错误提示。
: k. W$ m- J- @. U2 F3 L" Q: J/ C 主题函数是以“theme_”加上我们上面注册过“form_theme_form”命名的。代码如下:
1 L4 M4 K& ]9 V$ L1 x" m& H/ H- o7 n
<?php% d+ N2 U) ~) P
function theme_form_theme_form($variables)& _* P% \9 `/ X) a- W' p* {
{
& W8 H, N. K0 F; R // Isolate the form definition form the $variables array
: R) {: X0 H3 S: C$ S1 t8 j3 ? $form = $variables['form'];
& R1 l0 g2 R/ {9 [4 |/ F $output = '<h2>' . t('Please enter your information below') . '</h2>';: l* M; ^$ f( W; v1 u
// Put the entire structure into a div that can be used for$ p1 e5 C! j+ s( G3 m
// CSS purposes+ I- T9 Y }" j8 r5 e0 s
$output .= '<div id="personal_details">';! |: @" a J3 j0 C4 o# u) ]( `
// Each of the pieces of text is wrapped in a <span>
f! ]% v& s8 W" ]% g5 g8 O // tag to allow it to be floated left
6 ?4 R( x* v0 m- e7 w4 `. D! E $output .= '<span>' . t('My name is') . '</span>';, o* ?, X+ u% r8 ^9 }; w
// Form elements are rendered with drupal_render()2 x% |. F, Y. x
$output .= drupal_render($form['first_name']);
8 X( \0 a4 e* E $output .= drupal_render($form['last_name']);9 z% V9 M4 ]4 F& g8 ~
$output .= '<span>' . t('and I am') . '</span>';( P: r6 I( T: Y$ M: Y8 Q0 N4 R
$output .= drupal_render($form['age']);
) y0 f M" o/ h: p8 U $output .= '<span>' . t('years old.') . '</span>';
. X* c9 f3 ?- H6 `: ?4 s $output .= '</div>';
+ x( D3 p6 _# U // Pass the remaining form elements through drupal_render_children(). o9 c, {; M: k
$output .= drupal_render_children($form);% Y6 i* ]/ }7 S7 @' ~8 M# _/ a" i
// return the output# }5 V2 ]! {8 X1 m
return $output;
+ H+ w: [1 O6 L$ z+ b}4 H9 |! C2 y9 W9 k
?>
4 K6 ~/ {9 z" o8 {4 |' n2 Y& Z- T9 u$ Z' T ?0 ?! C( D3 }
到这里,我已经完成大部分的内容,定义表单,注册主题函数,实现主题函数。但是我还没添加CSS和Javascript。
0 {7 u" w \ }0 h! l8 f! o第五步:创建CSS和Javascript文件1 }! F( k8 e! A3 z
在第二步中我添加了CSS和JS路径,这两个文件都在form_theme模块的根目录。CSS代码如下:0 N( i8 d7 m# K) t- E
- J3 y( a: ~. e$ N#personal_details span, #personal_details div( T' s) h" \$ P/ w/ v& D; m
{
' [6 H! E2 |! F( b9 Dfloat:left;
1 n ] P( g! C2 m8 X" ^}) u+ K. }. U4 |- W0 j% _) ]
* R% u9 p4 o. x8 U) ] N5 G# w
#personal_details .form-item-first-name, #personal_details .form-item-last-name- P+ q2 K6 w5 o: k
{ G: s" F8 f, @/ t$ f! t5 ]
width:115px;
+ Y* S% ^. N6 I" Z}/ o& i o% w4 e. v
5 P8 i7 j4 j( \$ a
#edit-first-name, #edit-last-name& F4 n0 U% e3 g7 K/ B/ s; V5 N
{
. ^: h) G3 m) \4 jwidth:100px;& ~# m' d/ t+ i- N: x+ J& |# K
}& W, ^( _! @8 }7 z
. l. b. T8 z# `2 F
#personal_details .form-item-age
& ]+ D% w3 c. R4 v( z) K/ W{5 `0 `3 w- r: X2 _3 |
width:50px;
! \+ `$ w) `9 R& [. J; I% v}
" G B3 y0 ?! d0 I- K' S: n6 \: g$ M6 j, `
#edit-age
* ?2 m0 b5 U3 r( `# }* z' |{
" l; D, b- h. E: H, gwidth:35px;0 |9 x% k5 c/ r. v1 R- t
}/ i E) [6 F" j
2 Q0 n, `8 Q d1 ]% P#personal_details span! c" X' w& [2 }2 I; O6 z( _
{
) S6 R: U: p0 p4 |7 ^1 l/ t% @margin-right:5px;* I# o: t, F4 F% N2 `5 y2 ?
padding-top:5px;
8 d1 e: _3 H5 P9 T6 o* B: t) `% O}
- Q, Z! t- q9 Z( h4 |: N3 X' a. C) \! s0 \$ J8 P
Javascript代码如下:
5 b2 j" I! r5 e0 j. y- e/ f, X; `& @0 k
// We wrap the entire code in an anonymous function
% ?- ~* ^" e# W+ i; ~& o// in order to prevent namespace collisions, and to
3 |6 B) l) Y" ^4 f& f0 c" B// allow for jQuery to be set in a safe mode where
0 f6 N) V& Q0 e// it will not collide with other javascript libraries.: a$ [ u( c9 [6 a" l
// While this is the proper way to do it in Drupal 7,
' v& f" r4 W" _9 a9 K// this method is actually good to use in Drupal 6 as0 N6 d2 [, f. D- Z& s
// well, for the same reasons.: K2 h, s3 i' S, C$ J
(function($)
* s, p; R7 ^: M- O( q- H/ \{' H1 w9 u; Z% \
// In Drupal 6, each element of Drupal.behaviors; @6 t8 F3 m1 W$ D( | ~
// was a function that was executed when the
, }7 M. d' s4 {// document was ready. In Drupal 7, each element1 Q9 |; Z% ~2 G( Z6 f
// of Drupal.behaviors is an object with an
2 x6 b" i8 s! b+ Y+ ~1 b// element 'attach' (and optionally an element9 X6 W% B( _& m; M+ ?7 l5 I! C
// 'detach'), which is executed when the document5 v( W7 g8 ?9 P% u+ j! A' k
// is ready6 o9 Z4 @2 V9 e5 z2 F; E
Drupal.behaviors.formTheme = {% ~# p G% G( F; H" v: B& {( b
attach:function() {0 z- D6 |' x! b
// First, define an empty array
1 \- t( m9 c- j% z( @$ Q# u$ vvar defaults = [];
6 X' U1 p7 z: D- \# U- T0 \. c& i// Next, add three elements to the array,1 z7 @6 h6 I% N. f/ S
// one for each of the form elements. The value0 n7 \5 |1 ~8 o
// is of the array element is set as the default( m. t1 D: V0 ` }7 Z% V5 z
// text. This text is run through Drupal.t(),) V0 ^( m! s) D& R4 H
// which is the Drupal JavaScript equivalent
) i" F" v. `( S! U3 ?! j+ [# X1 V6 c, x// of the Drupal PHP t() function, and allows
2 e5 u3 `2 E* W) I8 R1 C l3 G& T// for translating of text in a JavaScript document
; V( A- p! U; j0 |defaults["#edit-first-name"] = Drupal.t("First Name");/ ]9 R* n$ V2 ?! P( x: C0 H5 d# \) B- ?
defaults["#edit-last-name"] = Drupal.t("Last Name");3 R2 I5 D T# W. I/ I
defaults["#edit-age"] = Drupal.t("Age");9 B/ Q" M1 @% b# \5 c, e
// Next we loop through each of the elements of the array
. P8 A* O2 Z U& q( o. ivar element;
% v1 E w* ]+ s9 Jfor(element in defaults)( [) t1 I! H9 `: m1 C' F) f* D% t
{9 N" K7 I _" T" p, }* @' [7 E
// We wrap the body in the following if() statement
9 z& ]) z* M9 ]// as each element in an array will also have a! e: G( x: G! `7 d0 V" e. }0 [
// prototype element. If you don't understand this,
) ?& O, y( ^7 c* y/ C9 Q+ j// don't worry. Just copy it. It will make your
0 u& ^* n* V' f/ Y2 S1 F// for(A in B) loops run better.
3 s u* q& q2 ]( j/ Gif(defaults.hasOwnProperty(element)) {
- `/ g+ z1 [! H$ A- K9 K// 1) Set a placeholder in the form element
# ?. m2 q2 q1 E; k3 @// 2) Set the CSS text color to grey for the placeholder& C6 K. z: N, X/ ~
// 3) Attach an onfocus and onblur listener to each element/ p, c- _, m/ g' c
$(element).val(defaults[element]).css("color", "grey").focus(function()
2 S3 k; j- W. {, {+ D8 P4 d, j{4 H3 b; C9 y P* I, e. N
// This is entered on focus. It checks0 G* b. @( R% K
// if the value of the form element is/ O" H! ~- X/ A
// the default value of the placeholder,
. n4 t1 Y8 d# \) o// and if it is, it clears the value and. j4 Y" j! t& g9 ?2 }; u
// sets the text color to black,as the
8 R f( A# m' Q8 |/ F$ X0 T. J// entered text will be the actual text
& \) Y5 B( Z0 y& m# X// and not the greyed out placeholder text.
% f. f: }. h5 A9 w6 Cvar key = "#" + $(this).attr("id");
$ V$ ~( w% W! w, y% o6 n) G& @9 oif($(this).val() === defaults[key]) {
% T l! d { g9 C7 W- Q- O- M9 @: l$(this).css("color", "black").val("");4 _2 ^& ^! w3 y+ W* x) \% B! Q% D
}+ T: h7 N G' f/ }9 S, v
}).blur(function()) K1 j' W7 W% w) J: G6 V
{: W2 J" a2 T6 ~
// This is entered on blur, when the element
1 Y1 a+ t4 y5 `; K" M! Z" p: F// is exited out of. It checks if the element; A2 ~, T' _$ @* t \5 A$ y( A
// is empty, and if it is, it sets the default
& X! Y) f) O4 k% l& M// placeholder text back into the element, and
' I" A- x4 P+ Y// changes the text color to the grey placeholder! z1 |% f. D- s# }: P. a! l, T
// text color.
$ p4 @2 @" t5 H' e$ r3 U- ?; zif($(this).val() == "") {7 w7 i+ o" Y% B9 I( G% _
var key = "#" + $(this).attr("id");
- h. v" o( {$ Y! T) j( q$(this).css("color", "grey").val(defaults[key]);, G+ p. J+ j; L/ `' M; J$ {( b
}9 E, m8 q0 B% c" e7 d# |
});
4 h9 h6 ]5 j& J}- X- r' T; q( Q9 @# f7 j g* F
}. J* b3 y7 ^9 h) }
}) F9 _1 N5 u2 _
};! ^, a G5 b% C s
}(jQuery));
1 q: ]# H! ?+ k9 n" @( ]# ~* J+ }6 e8 E5 `3 `3 \
好了,你可以试试看。% O; L& z( I2 d2 j
原文出自:http://junepeng.info/zh/node/286 q/ l/ X& A$ c
: q7 K9 ]+ P/ [, [% Z: s4 G
) H/ s8 o4 e# f0 i$ M& I3 p! e
' |4 Z/ d5 H* d) J' d
# U3 ? \' ~6 i$ a A7 R/ t, L' K# I9 O4 R& c [
1 W1 y9 D+ K- {' J$ k0 ? C |
|