首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

HTML5 复合组件,第 2 部分 实现拖放-5

HTML5 复合组件,第 2 部分 实现拖放-5

添加 Ajax 并发送一个负载到服务器在  小节,我完全在客户端处理放置链接,通过呈现一个显示链接标题和 URL 的示警框(见 )。对于 Feeds 应用程序以及大多数提供拖放的重要 JSF 应用程序而言,一个放置通常伴随着一次服务器访问,其中负载合并到服务器端数据。由于这一原因,在这一小节,我将 Ajax 添加到 <h5:drop> 组件,以便在放置发生时,该组件可以自动发起 Ajax 调用,并随 Ajax 调用发送负载。
每次当用户在右边菜单上放置一个链接时,<h5:drop> 组件发起一次 Ajax 调用,将链接添加到在服务器端保存的应用程序链接列表。当 Ajax 调用返回时,JSF 更新放置目标来反映最新添加的链接。
清单 7 显示更新的放置目标:
清单 7. 放置目标,Take II
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
   xmlns:ui="http://java.sun.com/jsf/facelets"
   xmlns:h="http://java.sun.com/jsf/html"
   xmlns:fn="http://java.sun.com/jsp/jstl/functions"
   xmlns:h5="http://java.sun.com/jsf/composite/html5">

   <script>
        function dragenter(event) { /* Implement as desired */ }
        function dragleave(event) { /* Implement as desired */ }
        function dragover(event)  { /* Implement as desired */ }
        function drop(event)      { /* Implement as desired */ }
    </script>

   <h5:drop id="dropzone" payload="#{dragDrop.payload}"
                           render="@this"
      ondragover="dragover(event)"
      ondragenter="dragenter(event)"
      ondragleave="dragleave(event)"
      ondrop="drop(event)">

      <div class="welcomeImage">
          <h:graphicImage id="welcomeImage"
             library="images" name="cloudy.gif"/>
      </div>
         
      <br />

      <div class="savedItems">
           <ui:repeat value="#{rssFeed.savedItems}" var="item">
             <div class="savedLink">
              <a href="#{item.link}">
                 #{ fn:substring(item.title, 0, 25) } ...
               </a>
               
               <br/>
           </div>
        </ui:repeat>      
      </div>

   </h5:drop>
</ui:composition>




在放置目标的这个版本中,我将拖放负载连接到一个 bean 属性:#{dragDrop.payload}。并且我通知放置目标显示 @this — 是指放置目标本身 — 当放置初始化的 Ajax 调用返回时。
清单 8 显示更新的 <h5:drop> 组件实现:
清单 8. <h5:drop> 组件,Take II
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml"
   xmlns:f="http://java.sun.com/jsf/core"
   xmlns:h="http://java.sun.com/jsf/html"
   xmlns:composite="http://java.sun.com/jsf/composite">

   <composite:interface>
      <composite:attribute name="ondragenter"/>
      <composite:attribute name="ondragover"/>
      <composite:attribute name="ondragleave"/>
      <composite:attribute name="ondrop"/>
      <composite:attribute name="render"/>
      <composite:attribute name="payload"/>
      <composite:attribute name="payloadType"/>
   </composite:interface>
   
   <composite:implementation>
      <hutputScript library="javax.faces" name="jsf.js" target="head" />
      <hutputScript library="html5" name="drop.js" target="head" />
         
      <div id="#{cc.id}" ondragenter="#{cc.attrs.ondragenter}"
                         ondrop="#{cc.attrs.ondrop}"
                         ondragover="#{cc.attrs.ondragover}"
                         ondragleave="#{cc.attrs.ondragleave}">
                          

        <composite:insertChildren />
           
        <h:form id="form">
          <h:inputText id="payload"
                     value="#{cc.attrs.payload}"
                     style="display: none"/>   
        </h:form>
           
        </div>
      
        <script> html5.jsf.init("#{cc.id}",
                                "#{cc.attrs.payloadType}",
                                "#{cc.attrs.render}"); </script>
   </composite:implementation>
</html>




更新的放置目标需要:
  • 当放置发生时,发起一个 Ajax 调用
  • 在 Ajax 调用过程中在服务器端提供负载
在 <h5:drop> 组件 JavaScript 中进行 Ajax 调用,如清单 9 所示,使用 JSF 的 jsf.ajax.request() JavaScript 函数:
清单 9.  <h5:drop> 组件的 JavaScript,Take II
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
if (!html5)
   var html5 = {}
if (!html5.jsf) {
   html5.jsf = {
      init : function(ccid, payloadType, renderIds) {
         var dropzone = $(ccid);

         dropzone.payloadInput = $(ccid + ":form:payload");

         dropzone.addEventListener("drop", function(event) {
            if (payloadType == "")
               payloadType = "text";

            if (renderIds == "" || renderIds == "@this")
               renderIds = ccid;

            dropzone.payloadInput.value = event.dataTransfer
                  .getData(payloadType);jsf.ajax.request(dropzone.payloadInput, event, {
               render : renderIds,
               onevent : function(data) {
                   if (data.status == "success")
                      html5.jsf.init(ccid, payloadType, renderIds);
                }
            });
         }, false);

         dropzone.addEventListener("dragenter", function(event) {
            event.preventDefault();
         }, false);

         dropzone.addEventListener("dragover", function(event) {
            event.preventDefault();
         }, false);
      }
   };
}




重新调用  中的负载名称:
1
<h5:drop...payload="#{dragDrop.payload}">




在  中,我通过 <h5:drop> 组件的不可见输入文本 使负载可供使用。为了将负载传送到客户端,我需要一个在客户端和服务端来回传送数值的方法,而 JSF 已经在 <h:inputText> 中提供了。因此,我将一个不可见输入文本添加到放置目标,正如您在  中所看到的那样,当生成一个放置时,在 Ajax 请求之前设置不可见输入的值。
因为我在发起 Ajax 调用之前设置了输入值,现在存储在输入值中的拖放负载在 Ajax 调用期间将在服务器端可用。因为输入值是连接到一个 bean 属性的,在 Ajax 调用期间 JSF 将传递负载到那个属性的 setter 方法中。
在  中,该值被 <h5:drop> 组件使用,作为不可见文本输入的值:
1
<h:inputText id="payload" value="#{cc.attrs.payload}" style="display: none"/>




在  中,不可见文本输入被指定为 Ajax 请求的源:
1
jsf.ajax.request(dropzone.payloadInput, event, {...});




由于不可见文本输入被指定为 Ajax 请求的源,JSF 在服务器端处理输入,这意味着它将调用与属性 setter 方法相关的文本输入 — 在本例中是 DragDrop.setPayload(),如清单 10 所示:
清单 10.  payload 属性的实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
package com.clarity;

import java.util.Iterator;
import java.util.LinkedList;
import java.util.StringTokenizer;

import javax.enterprise.context.SessionScoped;
import javax.inject.Inject;
import javax.inject.Named;

import org.gnu.stealthp.rsslib.RSSItem;

@Named
@SessionScoped
public class DragDrop implements Serializable {
   @Inject private RSSFeed rssFeed;

   public DragDrop() {
   }
   
   public String getPayload() {
      // JSF requires both getters and setters for input properties
      return "";
   }
   
   public void setPayload(String payload) {
      // creates a new saved item, based on the payload. Payload
      // was set in the drop event listener for the h5:drop component
      // in /sections/feeds/menuLeft.xhtml
      StringTokenizer st = new StringTokenizer(payload);
      RSSItem item = new RSSItem();
      
      item.setTitle(st.nextToken("|"));
      st.nextToken(" ");
      item.setLink(st.nextToken(" "));
      
      rssFeed.getSavedItems().add(item);
   }
}




JSF 传递拖放负载到 DragDrop.setPayload()。基于该负载,DragDrop.setPayload() 方法创建一个新的 RSS 项,并将其添加到保存的 rssFeed 项清单中。注意,我还为负载属性包含一个 getter 方法,因为 JSF 需要 setter 和 getter 两个来处理输入值。
使用复合组件重用现有组件功能很简单 — 在本例中是 <h:inputText> 在服务器端与客户端传送数据的功能。我在 <h5:drop> 组件中使用不可见文本输入将数据从客户端传送到服务器端,只需要将文本输入添加到复合组件,然后在 Ajax 调用之前设置输入值。
现在我已经有了一个相对成熟的放置目标了(注意拖拉源从引入到现在没有改变),进行 Ajax 调用来响应放置,然后将转换的数据从客户端传递到服务器端。这也允许页面创建者在 Ajax 调用返回时指定他们想要显示的组件。但是我的拖放组件仍然缺乏一个特性:有条件拖拉。
返回列表