comparison after5.rb @ 90:48afc00ef5df draft

Add filtering feature to schedule listing
author HIROSE Yuuji <yuuji@gentei.org>
date Sat, 21 Dec 2013 16:33:20 +0900
parents 00d203e72f8f
children 9ed5d139232f
comparison
equal deleted inserted replaced
89:00d203e72f8f 90:48afc00ef5df
2 # -*- coding: euc-jp -*- 2 # -*- coding: euc-jp -*-
3 # 3 #
4 # Associative Scheduling Table - after5 4 # Associative Scheduling Table - after5
5 # (C)2003, 2004, 2006, 2008, 2012, 2013 by HIROSE Yuuji [yuuji<at>gentei.org] 5 # (C)2003, 2004, 2006, 2008, 2012, 2013 by HIROSE Yuuji [yuuji<at>gentei.org]
6 # $Id: after5.rb,v 1.20 2012/12/03 15:54:20 yuuji Exp $ 6 # $Id: after5.rb,v 1.20 2012/12/03 15:54:20 yuuji Exp $
7 # Last modified Thu Dec 19 12:09:19 2013 on firestorm 7 # Last modified Sat Dec 21 16:24:53 2013 on firestorm
8 # See http://www.gentei.org/~yuuji/software/after5/ 8 # See http://www.gentei.org/~yuuji/software/after5/
9 # このスクリプトはEUCで保存してください。 9 # このスクリプトはEUCで保存してください。
10 $hgid = <<_HGID_.split[1..-2].join(" ") 10 $hgid = <<_HGID_.split[1..-2].join(" ")
11 $HGid$ 11 $HGid$
12 _HGID_ 12 _HGID_
106 def reset(name, value, text='') 106 def reset(name, value, text='')
107 sprintf "<input type=\"reset\" name=\"%s\" value=\"%s\">\n", 107 sprintf "<input type=\"reset\" name=\"%s\" value=\"%s\">\n",
108 name, value, text 108 name, value, text
109 end 109 end
110 def submit_reset(name) 110 def submit_reset(name)
111 submit(name, "GO")+reset(name, "Reset") 111 submit(name, "OK")+reset(name, "Reset")
112 end 112 end
113 113
114 def select(name, range, selected=nil) 114 def select(name, range, selected=nil)
115 #start = (b<e ? b : e) 115 #start = (b<e ? b : e)
116 #last = (b>e ? b : e) 116 #last = (b>e ? b : e)
632 @groupmap[grp] && @groupmap[grp]['name'] 632 @groupmap[grp] && @groupmap[grp]['name']
633 end 633 end
634 def name2group(name) 634 def name2group(name)
635 @groupmap.find{|g, v| v.is_a?(Hash) && v['name']==name} 635 @groupmap.find{|g, v| v.is_a?(Hash) && v['name']==name}
636 end 636 end
637 def day_all(d, user=nil, personalonly = nil) 637 def day_all(d, user=nil, personalonly = nil, filter)
638 y, m, d = d.scan(%r,(\d\d\d\d+)/(\d+)/(\d+),)[0] 638 y, m, d = d.scan(%r,(\d\d\d\d+)/(\d+)/(\d+),)[0]
639 #daydir = File.join(@dir, "%04d"%y.to_i, "%02d"%m.to_i, "%02d"%d.to_i) 639 #daydir = File.join(@dir, "%04d"%y.to_i, "%02d"%m.to_i, "%02d"%d.to_i)
640 daydir = File.join("s", "%04d"%y.to_i, "%02d"%m.to_i, "%02d"%d.to_i) 640 daydir = File.join("s", "%04d"%y.to_i, "%02d"%m.to_i, "%02d"%d.to_i)
641 sched = {} 641 sched = {}
642 grep = if filter && filter > ''
643 Regexp.new(filter.split(/\s+/).join("|"))
644 end
642 return sched unless test(?d, daydir) 645 return sched unless test(?d, daydir)
643 Dir.foreach(daydir) {|time| 646 Dir.foreach(daydir) {|time|
644 next if /^\./ =~ time 647 next if /^\./ =~ time
645 next unless /^\d\d\d\d$/ =~ time 648 next unless /^\d\d\d\d$/ =~ time
646 time.untaint 649 time.untaint
651 next if /^\./ =~ who 654 next if /^\./ =~ who
652 655
653 visible = false 656 visible = false
654 #next unless /@/ =~ who # user must be as user@do.ma.in 657 #next unless /@/ =~ who # user must be as user@do.ma.in
655 next unless account_exists(who) 658 next unless account_exists(who)
656 ## next if personalonly && who != user #2004/1/16 659 ## next if private && who != user #2004/1/16
657 who.untaint 660 who.untaint
658 dir = File.join(t, who) 661 dir = File.join(t, who)
659 next unless test(?d, dir) && test(?x, dir) 662 next unless test(?d, dir) && test(?x, dir)
660 pub = File.join(dir, 'pub') 663 pub = File.join(dir, 'pub')
661 if test(?f, pub) && test(?r, pub) && test(?s, pub) && 664 if test(?f, pub) && test(?r, pub) && test(?s, pub) &&
662 !personalonly # unneccessary if personal mode 665 !personalonly # unneccessary if personalonly mode
663 if IO.readlines(pub)[0].to_i > 0 666 if IO.readlines(pub)[0].to_i > 0
664 visible = true 667 visible = true
665 end 668 end
666 end 669 end
667 670 next if grep && (grep !~ who && grep !~ nickname(who)) # 2013/12/19
668 671
669 if ismember(user, who) || visible 672 if ismember(user, who) || visible
670 sched[time][who] = {} 673 sched[time][who] = {}
671 file = File.join(dir, @schedulefile) 674 file = File.join(dir, @schedulefile)
672 if test(?s, file) && test(?r, file) && test(?s, file) 675 if test(?s, file) && test(?r, file) && test(?s, file)
673 sched[time][who]['sched'] = IO.readlines(file).join.toeuc.chomp! 676 sched[time][who]['sched'] = IO.readlines(file).join.toeuc.chomp!
1115 @attachmentdir = "a" 1118 @attachmentdir = "a"
1116 @attachmentmax = 8*1024**2 1119 @attachmentmax = 8*1024**2
1117 @mailmode = nil 1120 @mailmode = nil
1118 @mailadmdelimiter = "/" 1121 @mailadmdelimiter = "/"
1119 @mailadmsuffix = @mailadmdelimiter + "adm" 1122 @mailadmsuffix = @mailadmdelimiter + "adm"
1120 @saveprefsregexp = /^(display(mode|days)$|nt|headline)/ 1123 @saveprefsregexp = /^(display(mode|days|filter)$|nt|headline)/
1121 @opt = { 1124 @opt = {
1122 'conf' => @mybase+".cf", 1125 'conf' => @mybase+".cf",
1123 'css' => @mybase+".css", 1126 'css' => @mybase+".css",
1124 'logfile' => 's/'+@mybase+".log", 1127 'logfile' => 's/'+@mybase+".log",
1125 "sendmail" => "/usr/sbin/sendmail", 1128 "sendmail" => "/usr/sbin/sendmail",
1180 ] 1183 ]
1181 p @cookie if $DEBUG 1184 p @cookie if $DEBUG
1182 p @params if $DEBUG 1185 p @params if $DEBUG
1183 1186
1184 ### @params['displaymode'] = @params['displaymode'] || @cookie['displaymode'] 1187 ### @params['displaymode'] = @params['displaymode'] || @cookie['displaymode']
1185 personal = /personal/i =~ @params['displaymode'] 1188 personal = /^personal/i =~ @params['displaymode']
1186 bodyclass = if personal then {'class'=>'personal'} end 1189 bodyclass = if personal then {'class'=>'personal'} end
1187 1190
1188 ## x = {"align"=>'center'} 1191 ## x = {"align"=>'center'}
1189 ## @H.element("p", x, "hoge", nil) 1192 ## @H.element("p", x, "hoge", nil)
1190 ## @H.element("p", nil, "buha", nil) 1193 ## @H.element("p", nil, "buha", nil)
1378 'display' => ['予定表示行: ', 'Display schedule of: '], 1381 'display' => ['予定表示行: ', 'Display schedule of: '],
1379 'nameonly' => ['名前のみ', 'Name Only'], 1382 'nameonly' => ['名前のみ', 'Name Only'],
1380 'head5char' => ['先頭5文字', 'Head 5 chars'], 1383 'head5char' => ['先頭5文字', 'Head 5 chars'],
1381 'headline' => ['先頭1行', 'Headline only'], 1384 'headline' => ['先頭1行', 'Headline only'],
1382 'whole' => ['長くても全部', 'Whole text'], 1385 'whole' => ['長くても全部', 'Whole text'],
1386 'filter' => ['登録者絞込', 'Selection by Registerer'],
1387 'filterhelp' => ['表示する予定を登録者アカウント名(の一部)で絞り込みできる。
1388 2つ以上の名前で絞りたいときはスペースで区切ればOK。', 'Can filter by (a part of)account name.
1389 Multiple patterns delimited by spaces are acceptable.'],
1390 'filterreset' => ['絞込解除', 'Reset Selection'],
1383 'hldays' => ['最新X日分強調', 'Hilight Recent X-days'], 1391 'hldays' => ['最新X日分強調', 'Hilight Recent X-days'],
1384 'addedtogroup' => ['をグループに追加 →', 'added to the group:'], 1392 'addedtogroup' => ['をグループに追加 →', 'added to the group:'],
1385 'removedfromgp' => ['をグループから削除:', 'removed from the group:'], 1393 'removedfromgp' => ['をグループから削除:', 'removed from the group:'],
1386 'soleadmin' => ['%s は %s の唯一の管理者なのでやめられないのだ', 1394 'soleadmin' => ['%s は %s の唯一の管理者なのでやめられないのだ',
1387 "%s is sole administrator of %s. Cannot retire."], 1395 "%s is sole administrator of %s. Cannot retire."],
1400 'aboutgroup' => ['グループ %s の操作', "Operations on group `%s'"], 1408 'aboutgroup' => ['グループ %s の操作', "Operations on group `%s'"],
1401 'groupwarn' => ['自分が参加してないグループAに、自分が参加しているグループBが含まれている場合、グループAにも加入していると見なされるので気をつけよう。管理者はグループのニックネームを変えられるよ。', 1409 'groupwarn' => ['自分が参加してないグループAに、自分が参加しているグループBが含まれている場合、グループAにも加入していると見なされるので気をつけよう。管理者はグループのニックネームを変えられるよ。',
1402 'Though you are not member of group A, you are treated as a member of A, if you join to the group B, which is a member of A. Think the nesting of groups carefully, please. Group administrator can change the group nickname.'], 1410 'Though you are not member of group A, you are treated as a member of A, if you join to the group B, which is a member of A. Think the nesting of groups carefully, please. Group administrator can change the group nickname.'],
1403 'address2send' => ['自分が参加しているグループのメンバーリストの先頭が自分。その直後にある入力欄には、そのML宛メッセージをどの宛先に配送するかを入れられる。そう、MLごとに自分への配送先を変えられるよ。', 1411 'address2send' => ['自分が参加しているグループのメンバーリストの先頭が自分。その直後にある入力欄には、そのML宛メッセージをどの宛先に配送するかを入れられる。そう、MLごとに自分への配送先を変えられるよ。',
1404 'The first entry of member list of a group to which you belongs, is you. Entry box just after your name is for address list you want to deliver messages to that ML. Thus, you can define different addresses for each ML.'], 1412 'The first entry of member list of a group to which you belongs, is you. Entry box just after your name is for address list you want to deliver messages to that ML. Thus, you can define different addresses for each ML.'],
1405 'skip:' => ['MLへの送信専用メイルアドレスは、アドレスの前に空白入れずに skip: を付けて登録できるよ(例: skip:hoge@example.com。ML登録メンバーのみの投稿を許すMLに書いてエラーを食らったときには、投稿アドレスを skip: つきで登録しとくとええよ。', "You can prefix `skip:' without any blanks to email address to register POST-ONLY address for the ML(eg. skip:you@example.com). When you get rejecting message from ML which allows only members to post, try to add POST-ONLY address to your email addresses entry of that group."], 1413 'skip:' => ['MLへの送信専用メイルアドレスは、アドレスの前に空白入れずに skip: を付けて登録できるよ(例: skip:hoge@example.com。ML登録メンバーのみの投稿を許すMLに送信して拒否メッセージを食らったときには、その送信アドレスを skip: つきで登録しとくとええよ。', "You can prefix `skip:' without any blanks to email address to register POST-ONLY address for the ML(eg. skip:you@example.com). When you get rejecting message from ML which allows only members to post, try to add POST-ONLY address to your email addresses entry of that group."],
1406 'wholemembers' => ['グループ内グループを考慮した上で、現在グループ %s への通知は以下のメンバーに送られる。', 1414 'wholemembers' => ['グループ内グループを考慮した上で、現在グループ %s への通知は以下のメンバーに送られる。',
1407 "Consiering the groups registered in another group, notification to the group `%s' is send to members as follows."], 1415 "Consiering the groups registered in another group, notification to the group `%s' is send to members as follows."],
1408 'noadmingroup' => ['管理できるグループはないっす', 1416 'noadmingroup' => ['管理できるグループはないっす',
1409 "'There's no groups under your administration."], 1417 "'There's no groups under your administration."],
1410 'nickname' => ['ニックネーム', 'nickname'], 1418 'nickname' => ['ニックネーム', 'nickname'],
1820 "<br>" + \ 1828 "<br>" + \
1821 @H.element("p"){ 1829 @H.element("p"){
1822 me = @myname+"?-"; delim = " / " 1830 me = @myname+"?-"; delim = " / "
1823 @H.a(me+'userman', msg('user', 'management')) + delim + \ 1831 @H.a(me+'userman', msg('user', 'management')) + delim + \
1824 @H.a(me+'groupman', msg('group', 'management')) + delim + \ 1832 @H.a(me+'groupman', msg('group', 'management')) + delim + \
1825 if /personal/i =~ @params['displaymode'] 1833 if /^personal/i =~ @params['displaymode']
1826 @H.a(me+'today_n', msg('normalmode')) 1834 @H.a(me+'today_n', msg('normalmode'))
1827 else 1835 else
1828 @H.a(me+'today_p', msg('personalmode')) 1836 @H.a(me+'today_p', msg('personalmode'))
1829 end 1837 end
1830 } 1838 }
1842 "." 1850 "."
1843 } 1851 }
1844 end 1852 end
1845 def footer() 1853 def footer()
1846 footer1+footer2 1854 footer1+footer2
1855 end
1856 def header_filter()
1857 filter = @params['displayfilter']
1858 if filter && filter > ""
1859 myarg = (ENV['REQUEST_URI']||"-today").sub(/.*\?/, "")
1860 @H.elementln("form", {'action'=>@myname+"?"+myarg, "method"=>"POST"}) {
1861 @H.elementln("p", {"class"=>"filter"}) {
1862 @H.element("span") {
1863 msg('filter')+"="+filter
1864 } + \
1865 @H.hidden("displayfilter", "") + \
1866 @H.submit("GO", msg('filterreset'))
1867 }
1868 }
1869 else
1870 ""
1871 end
1847 end 1872 end
1848 def nickname(userORgroup) 1873 def nickname(userORgroup)
1849 if grepgroup(userORgroup) 1874 if grepgroup(userORgroup)
1850 @sc.groupname(userORgroup) 1875 @sc.groupname(userORgroup)
1851 else 1876 else
1872 tdclass = {} 1897 tdclass = {}
1873 tdclass["width"] = "64px" if @oldagent # workaround for NN4 1898 tdclass["width"] = "64px" if @oldagent # workaround for NN4
1874 personal = /personal/ =~ @params['displaymode'] 1899 personal = /personal/ =~ @params['displaymode']
1875 headline = @params['headline'] 1900 headline = @params['headline']
1876 headlinehl = @params['headlinehl'] 1901 headlinehl = @params['headlinehl']
1902 filter = @params['displayfilter']
1877 hldays = headlinehl.to_i * 3600*24 1903 hldays = headlinehl.to_i * 3600*24
1878 recent = {'class'=>'recent'} 1904 recent = {'class'=>'recent'}
1879 monthstr = sprintf "%d/%d", day.year, day.month 1905 monthstr = sprintf "%d/%d", day.year, day.month
1880 1906
1907
1881 holiday = Holiday.new 1908 holiday = Holiday.new
1882 # create dayofweek header 1909 # create dayofweek header
1883 @O.print @H.elementln("h1", nil){monthstr} 1910 @O.print @H.elementln("h1", nil){monthstr}
1884 # which mode? 1911 # which mode?
1885 @O.print @H.p(msg(personal ? 'personalmode' : 'normalmode')) 1912 @O.print @H.p(msg(personal ? 'personalmode' : 'normalmode'))
1886 # 1913 # @O.print @H.p(sprintf("filter=%s", filter))
1914 @O.print header_filter()
1887 # display table 1915 # display table
1888 @O.print @H.startelement("table", {'border'=>"1", 'class'=>'main'}) 1916 @O.print @H.startelement("table", {'border'=>"1", 'class'=>'main'})
1889 1917
1890 # day of week 1918 # day of week
1891 @O.print @H.startelement("tr") 1919 @O.print @H.startelement("tr")
1916 # isHoliday? 1944 # isHoliday?
1917 if hd 1945 if hd
1918 @H.element("small"){hd.join("<br>")} 1946 @H.element("small"){hd.join("<br>")}
1919 end.to_s + \ 1947 end.to_s + \
1920 @H.element("p", {'class'=>'topic'}){ 1948 @H.element("p", {'class'=>'topic'}){
1921 s = @sc.day_all(date, @params['user'], personal) 1949 s = @sc.day_all(date, @params['user'], personal, filter)
1922 if !s.empty? 1950 if !s.empty?
1923 s.keys.sort.collect{|time| 1951 s.keys.sort.collect{|time|
1924 s[time].keys.sort.collect{|who| 1952 s[time].keys.sort.collect{|who|
1925 text = escape(s[time][who]['sched']) 1953 text = escape(s[time][who]['sched'])
1926 topic = sprintf "%s%s", 1954 topic = sprintf "%s%s",
1988 [msg('whole'), 'whole']] 2016 [msg('whole'), 'whole']]
1989 msg('display') + \ 2017 msg('display') + \
1990 @H.select('headline', choice, headline) + "/" + \ 2018 @H.select('headline', choice, headline) + "/" + \
1991 msg('hldays') + \ 2019 msg('hldays') + \
1992 @H.select('headlinehl', 0..30, headlinehl) + \ 2020 @H.select('headlinehl', 0..30, headlinehl) + \
2021 @H.element("abbr", {"title"=>msg('filterhelp')}) {msg('filter')} + \
2022 @H.text('displayfilter', @params['displayfilter'], 10, 80) +\
1993 @H.submit("GO", "GO") 2023 @H.submit("GO", "GO")
1994 } 2024 }
1995 @O.print footer 2025 @O.print footer
1996 ##schedule.day_all("2003/12/22") 2026 ##schedule.day_all("2003/12/22")
1997 # @O.print @H.endelement() 2027 # @O.print @H.endelement()
2013 %r,(\d\d\d\d+)/(\d\d?)/(\d\d?), =~ date and 2043 %r,(\d\d\d\d+)/(\d\d?)/(\d\d?), =~ date and
2014 [$1.to_i, $2.to_i, $3.to_i] 2044 [$1.to_i, $2.to_i, $3.to_i]
2015 end 2045 end
2016 # 2046 #
2017 # Return the string of table 2047 # Return the string of table
2018 def dayTableString(user, datestr, range, personal = nil) 2048 def dayTableString(user, datestr, range, personal = nil, filter = nil)
2019 #s = @sc.day_all(date, user, personal) 2049 #s = @sc.day_all(date, user, personal)
2020 #return '' if s.empty? 2050 #return '' if s.empty?
2021 r = '' 2051 r = ''
2022 header = @H.startelement("table", {'border'=>'1'}, true) 2052 header = @H.startelement("table", {'border'=>'1'}, true)
2023 2053
2027 d = Time.at(day+i*3600*24) 2057 d = Time.at(day+i*3600*24)
2028 date = sprintf("%04d/%02d/%02d", d.year, d.month, d.day) 2058 date = sprintf("%04d/%02d/%02d", d.year, d.month, d.day)
2029 datewn = @H.element("span", {'class'=>@wnames[d.wday]}){ 2059 datewn = @H.element("span", {'class'=>@wnames[d.wday]}){
2030 sprintf("%s(%s)", date, @msg['wnames'][@lang][d.wday]) 2060 sprintf("%s(%s)", date, @msg['wnames'][@lang][d.wday])
2031 } 2061 }
2032 s = @sc.day_all(date, user, personal) 2062 s = @sc.day_all(date, user, personal, filter)
2033 next if s.empty? 2063 next if s.empty?
2034 2064
2035 r << @H.element("tr", nil){ 2065 r << @H.element("tr", nil){
2036 @H.element("th", {'class'=>'time'}){'TIME'} + \ 2066 @H.element("th", {'class'=>'time'}){'TIME'} + \
2037 @H.element("th", nil){'Who - '+datewn+' - What'} 2067 @H.element("th", nil){'Who - '+datewn+' - What'}
2103 header + r + footer 2133 header + r + footer
2104 else 2134 else
2105 '' 2135 ''
2106 end 2136 end
2107 end 2137 end
2108 def dayTextString(user, datestr, range, personal = nil) 2138 def dayTextString(user, datestr, range, personal = nil, filter = nil)
2109 r = '' 2139 r = ''
2110 cols = 20 2140 cols = 20
2111 header = "-" * cols + "\n" 2141 header = "-" * cols + "\n"
2112 2142
2113 day = Time.mktime(*date2ymd(datestr)) 2143 day = Time.mktime(*date2ymd(datestr))
2114 i = -1 2144 i = -1
2115 while (i+=1) < range 2145 while (i+=1) < range
2116 d = Time.at(day+i*3600*24) 2146 d = Time.at(day+i*3600*24)
2117 date = sprintf("%04d/%02d/%02d", d.year, d.month, d.day) 2147 date = sprintf("%04d/%02d/%02d", d.year, d.month, d.day)
2118 datewn = sprintf("%s(%s)", date, @msg['wnames'][@lang][d.wday]) 2148 datewn = sprintf("%s(%s)", date, @msg['wnames'][@lang][d.wday])
2119 s = @sc.day_all(date, user, personal) 2149 s = @sc.day_all(date, user, personal, filter)
2120 next if s.empty? 2150 next if s.empty?
2121 2151
2122 r << sprintf("TIME Who %s - What\n", datewn) 2152 r << sprintf("TIME Who %s - What\n", datewn)
2123 2153
2124 for time in s.keys.sort 2154 for time in s.keys.sort
2277 def show(date) 2307 def show(date)
2278 if !checkauth 2308 if !checkauth
2279 return nil 2309 return nil
2280 end 2310 end
2281 user = safecopy(@params['user']) 2311 user = safecopy(@params['user'])
2282 personal = (/personal/i =~ @params['displaymode']) 2312 personal = (/^personal/i =~ @params['displaymode'])
2283 @params['displaydays'] = @params['displaydays'] || @cookie['displaydays'] 2313 @params['displaydays'] = @params['displaydays'] || @cookie['displaydays']
2314 filter = @params['displayfilter']
2284 days = @params['displaydays'].to_i 2315 days = @params['displaydays'].to_i
2285 days = (days > 0 ? days : 3) 2316 days = (days > 0 ? days : 3)
2286 2317
2287 # str = @sc.day_all(date, user, personal) 2318 outstr = dayTableString(user, date, days, personal, filter)
2288 outstr = dayTableString(user, date, days, personal)
2289 2319
2290 @O.print @H.element("h1", nil){ 2320 @O.print @H.element("h1", nil){
2291 sprintf msg('fmtdaysschedule'), date 2321 sprintf msg('fmtdaysschedule'), date
2292 } 2322 }
2293 @O.print @H.element("h2"){msg('schedtable')} 2323 @O.print @H.element("h2"){msg('schedtable')}
2294 ## @O.print @H.p() 2324 ## @O.print @H.p()
2325 @O.print header_filter()
2295 @O.print @H.elementln("form", {'action'=>@myname+"?-show+#{date}", 'method'=>'POST'}){ 2326 @O.print @H.elementln("form", {'action'=>@myname+"?-show+#{date}", 'method'=>'POST'}){
2296 @H.elementln("p"){ 2327 @H.elementln("p"){
2297 msg(personal ? 'personalmode' : 'normalmode') + "<br>" + \ 2328 msg(personal ? 'personalmode' : 'normalmode') + "<br>" + \
2298 @H.select("displaydays", 1..30, days) + msg('daystodisplay') + \ 2329 @H.select("displaydays", 1..30, days) + msg('daystodisplay') + \
2299 @H.submit("GO", "GO") 2330 @H.submit("GO", "GO")
3089 } 3120 }
3090 } + \ 3121 } + \
3091 @H.elementln("tr"){ 3122 @H.elementln("tr"){
3092 @H.element("td"){"Attachment"} + \ 3123 @H.element("td"){"Attachment"} + \
3093 @H.element("td"){ 3124 @H.element("td"){
3094 @H.element("input", "name"=>"attachment", "type"=>"file", 'multiple'=>true){} 3125 "<input name=\"attachment\" type=\"file\" multiple>"
3095 } 3126 }
3096 } + \ 3127 } + \
3097 @H.elementln("tr"){ 3128 @H.elementln("tr"){
3098 @H.element("td"){ 3129 @H.element("td"){
3099 msg('body') 3130 msg('body')
3190 @H.radio("delete2", "yes", msg('yes')) + ' ' + \ 3221 @H.radio("delete2", "yes", msg('yes')) + ' ' + \
3191 @H.radio("delete2", "no", msg('no'), true) 3222 @H.radio("delete2", "no", msg('no'), true)
3192 } 3223 }
3193 } 3224 }
3194 } + \ 3225 } + \
3195 "<br>\n" + @H.submit_reset("GO") 3226 "<br>\n" + @H.element("span", "class"=>"danger"){@H.submit_reset("OK")}
3196 } 3227 }
3197 3228
3198 3229 @O.print footer()
3199 end 3230 end
3200 def usermod() 3231 def usermod()
3201 if !checkauth 3232 if !checkauth
3202 return nil 3233 return nil
3203 end 3234 end
3642 @H.radio("delete2", "yes", msg('yes')) + ' ' + \ 3673 @H.radio("delete2", "yes", msg('yes')) + ' ' + \
3643 @H.radio("delete2", "no", msg('no'), true) 3674 @H.radio("delete2", "no", msg('no'), true)
3644 } 3675 }
3645 } 3676 }
3646 } + \ 3677 } + \
3647 "<br>\n" + @H.submit_reset("GO") 3678 "<br>\n" + @H.element("span", "class"=>"danger"){@H.submit_reset("OK")}
3648 } 3679 }
3649 3680
3650 @O.print footer() 3681 @O.print footer()
3651 end 3682 end
3652 def newgroup() 3683 def newgroup()

yatex.org