::-- ZoomQuiet [2005-12-11 04:50:15]

1. K3日:发现!

Cheetah 只能组织有模板的页面输出,但是……

  • 对于动态变化的表单,有什么更好的方式来组织?

1.1. Karrigell_QuickForm

Karrigell_QuickForm 真的是想要什么就来什么!

  • 刚刚从订阅的karrigell-main 列表中看到有人完成了一个 Pear 中 quickform的Karrigell 实现

  • 即有之,则用之!
  • 示例:

   1 from Karrigell_QuickForm import Karrigell_QuickForm
   2 
   3 p = Karrigell_QuickForm('teste','POST','foo.py','Authentication')
   4 p.addElement('text','login')
   5 p.addElement('text','password')
   6 p.addRule('login','required',"Login is required!")
   7 p.addGroup(["submit","botao_enviar","submit","Send"]
   8            ,["reset","botao_limpar","reset","Clear"])
   9 """根据习惯hack! 原先的自动生成 value 的为指定按钮文字。
  10 p.addGroup(["submit","botao_enviar","Send"]
  11            ,["reset","botao_limpar","Clear"])
  12 """
  13 p.display()

  • 6行完成一个标准的登录表单!!!哈哈哈!赞!

    1.1.1. 改造

    毕竟是 alpha 版本,居然还是全面的table 结构!

    • 代码也很ugly 哪!使用Leo整理后

    • 立即改造!

       1 def addRadioGroup(self,name,value):
       2         """add a radio element - addRadioGroup('genre',{'male':'Male','female':'Female'})"""
       3         self.form_list.append("<tr><td align='right' valign='top'><b>"+name.title().replace('_',' ')+":</b></td> <td valign='top' align='left'>")
       4         radio = ""
       5         t = value.items()
       6         for a,b in t:
       7             radio = radio + "<input type='radio' name='"+name+"' value='"+a+"'>"+"<label><font face=verdana size=2>"+b+"</font></label><br>"
       8         self.form_list.append(radio+"</td>")
       9         self.form_list.append("</tr>")
    

  • 増补为:
       1 def addRadioList(self,name,desc,value,id=""):
       2     """add a radio element export as UL LI group
       3     """
       4     htm = """
       5         <li id='%s'><b>%s:</b>
       6             <ul>"""
       7     self.form_list.append(htm%(id,desc))
       8     radio = ""
       9     t = value.items()
      10     tmpl = """<li>
      11         <input type='radio' 
      12         name='%s' 
      13         value='%s'>  
      14         <label>%s</label>      
      15         """
      16     for a,b in t:
      17         radio = radio + tmpl%(name,a,b)
      18     self.form_list.append(radio+"</ul></li>")
    

    1.1.2. 利用

    直接将昨天的展示函式修改一下子就应该好用的!

    • def expage(dict): 对应的修改为:

       1 def qpubish(dict):
       2     exp = ""
       3     p = Karrigell_QuickForm('fm_kq','POST','#',dict.desc.desc)
       4 
       5     p.addElement('node','<ul>','')
       6     # 深入数据 基本和昨天的一样,仅仅是输出时使用 Karrigell_QuickForm 对象而已
       7     qli = {}
       8     k = [int(i) for i in dict.ask.keys()]
       9     k.sort()
      10     for i in k:
      11         ask = dict.ask[str(i)]
      12         qk = [j for j in ask.keys()]
      13         qk.sort()
      14         for q in qk:
      15             if 1==len(q):
      16                 qli[q] = ask[q]
      17             else:
      18                 pass
      19         p.addRadioList("cr_ask%s"%i
      20                    ,ask["question"]
      21                    ,qli)
      22     p.addElement('node','</ul>','')
      23     p.addGroup(["submit","btn_submit","提交"]
      24                ,["reset","btn_reset","重写"])
    
    • 注意到原先的 Karrigell_QuickForm 只有display(),要求直接输出,但是你需要进一步的HTML 处理

    • 所以有了

         1 def export(self):
         2     """ export the html form code so people can do something for them self
         3     """
         4     exp = ""
         5     ...
         6     for c in self.css_list:
         7         exp += c+"\n"
         8     for i in self.form_list:
         9         exp += i+"\n"
        10     return exp
      

      基本上就是将原先的 print 替换为 exp+= 记录为字串对象然后返回

    • 还有def addElement(self,element,name,options=None): 中追加更自由的任何HTML 节点输出:

              elif element == 'node':
                  self.form_list.append(name)
      

    1.2. JS 问题

    一切顺心,表单正确生成了,但是,Karrigell_QuickForm 提供的JS检验不支持Radio列表的!

    • 呜乎哀哉!!这是个问题哪!如果不是所有问题回答完就提交的话
      • 交给服务端检验,浪费带宽!你还要记录上次的问题情况,返回/提示/重答
      • 不检验,则没有办法进行统计

    1.2.1. 继续发现!

    现在的问题是有什么现成的可以模式化的定义表单测验的JS组件?

    • 致力于 Python 的Ajax框架开发的 AMOWA团队作品,值得期待!使用之!

    1.2.2. 迁就,先!

    • KarriGell 配合注1,当前需要:

      1. jvf=%(base)s/karriweb/questionnaire/js 这样的专门虚拟目录发布,以便,其它各种应用也可以享受

      2. var ValidationRoot = "/jvf/"; JVF 实际运行的 validation-framework.js 本身也要声明所在目录

      3. ValidateMethodFactory.validateRequired = function(field, params) {
                ...
                window.location.replace("#errorDiv");
        
        使用replace 来减少不必要的页面刷新
      4. 使用p.saveJSRule("../js/validation-config.xml") 时要对应的修正写入的正确目标文件

    • KQF 对JVF 的迁就:

    1.2.2.1. 关键代码

    JVF的使用很有个性,使用外部的XML 文件进行设置,标准的J2EE行为哪!

    • 所以,对应的增补Karrigell_QuickForm

      1. addJSRule() 追加专门的JVF 规则

           1     def addJSRule(self,name,message):
           2         """add a xml rule for javascript checking
           3         """
           4         exp = self.JSvMXLnode%(name,message)
           5         self.JSvRules.append(exp)
        
      2. addJSValidation() 追加调用JVF的页面行为

           1     def addJSValidation(self):
           2         """add a javascript rule in order to validate a form field  
           3         - addRule('elem_name','required','Name is required!')
           4         """
           5         orig = "enctype='multipart/form-data'"
           6         repl = """
           7             onsubmit='return doValidate("%s");'
           8             """
           9         begin_form=self.form_list[0].replace(orig
          10                                      ,repl%self.name)
          11         self.form_list[0] = begin_form
        
      3. saveJSRule() 记录规则集合为JVF需要的XML

           1     def saveJSRule(self,xml):
           2         """exp and save a xml rule for javascript checking
           3         """
           4         exp = ""
           5         for node in self.JSvRules:
           6             exp+= node
           7         #exp = self.JSvXMLtmpl%(form,exp)
           8         open(xml,'w').write(self.JSvXMLtmpl%(self.name
           9                                              ,exp)
          10                                              )
        
      4. 对应的KQF中有预设对象

        self.JSvXMLtmpl="""<?xml version="1.0" encoding="utf-8"?>
        <!DOCTYPE validation-config SYSTEM "validation-config.dtd">
        <validation-config lang="auto"> 
                <form id="%s" show-error="errorMessage" onfail="" 
                show-type="first">
            %s
                </form>
        </validation-config>
        """
        self.JSvMXLnode = """
                        <field name="%s" 
                        display-name="%s" onfail="">
                                <depend name="required" />
                        </field>
        """
        self.JSvRules = []
        

    1.2.3. 果然不出所料

    仅仅追加少量代码就完成所想的客户端JS验证功能

    def qpubish(dict):
        ...
        ## 具体问题解析
        k.sort()
        for i in k:
            ...
            p.addJSRule("cr_ask%s"%i,"问题%s "%i)
        ## 整体行为处理
        p.addJSValidation()
        p.saveJSRule("js/validation-config.xml")
        
        p.addElement('node','</ul>','')
    
    • 果然不出所料 没有任何悬念的完成任务!

    1.3. 滥用Leo

    到现在页面都是白丁!不能忍了!加载CSS!

    • 不清楚KarriGell 的页面引用效率,直接将CSS,写入页面好了,反正有Leo来维护

    1.3.1. CSS设计技巧

    复用以前自个儿的积累是非常好的事儿!

    1.3.2. CSS

    • 每一需要CSS美化的页面都加<<k_base>> 引用,

    • 引用都是从复用代码 中clone 过来的同一节点

    • 包含的就是k_base.css 你以往积累的一个通用的CSS整体设计,少量修改后,套用中意的颜色系统

    1.4. 小节

    今天发现并引入了 KQFJVF好象有点复杂的样子……

    • 当然在故事中,这不是最终接受的方案,精彩还要继续……
    • 现在所有的基本功能都有了,接下来的就是要实用化:
      1. 有用户验证,要登录
      2. 多问卷选择/回答/编辑

    1.5. 实例下载

    使用 SVN 下载:

    1. KwDay3实例

    2. 注意有在外部安置的 JS-JVF 目录

    1.6. 讨论


    返回 KarrigellWebDev -- 快速体验K开发

    • 1 测试JS 成功引用否的小技巧:alert("Include KO!"); JS 中加入强制提示看刷页面见分晓!