From 8cfdf845683157b756f485ea91c3fc3f2a2697c6 Mon Sep 17 00:00:00 2001 From: Adam Chlipala Date: Thu, 24 Nov 2011 11:27:51 -0500 Subject: Client-side timef --- lib/js/urweb.js | 200 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/settings.sml | 1 + tests/timef.ur | 12 ++++ 3 files changed, 213 insertions(+) create mode 100644 tests/timef.ur diff --git a/lib/js/urweb.js b/lib/js/urweb.js index 8664ec9a..3829cdb2 100644 --- a/lib/js/urweb.js +++ b/lib/js/urweb.js @@ -157,6 +157,206 @@ function stringToTime(string) { } } +/* + strftime for Javascript + Copyright (c) 2008, Philip S Tellis + All rights reserved. + + This code is distributed under the terms of the BSD licence + + Redistribution and use of this software in source and binary forms, with or without modification, + are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this list of conditions + and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, this list of + conditions and the following disclaimer in the documentation and/or other materials provided + with the distribution. + * The names of the contributors to this file may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR +TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +Date.ext = {}; +Date.ext.util = {}; +Date.ext.util.xPad=function(x, pad, r) +{ + if(typeof(r) == 'undefined') + { + r=10; + } + for( ; parseInt(x, 10)1; r/=10) + x = pad.toString() + x; + return x.toString(); +}; +Date.prototype.locale = 'en-US'; +if(document.getElementsByTagName('html') && document.getElementsByTagName('html')[0].lang) +{ + Date.prototype.locale = document.getElementsByTagName('html')[0].lang; +} +Date.ext.locales = { }; +Date.ext.locales.en = { + a: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], + A: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'], + b: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], + B: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'], + c: '%a %d %b %Y %T %Z', + p: ['AM', 'PM'], + P: ['am', 'pm'], + x: '%d/%m/%y', + X: '%T' +}; +Date.ext.locales['en-US'] = Date.ext.locales.en; +Date.ext.locales['en-US'].c = '%a %d %b %Y %r %Z'; +Date.ext.locales['en-US'].x = '%D'; +Date.ext.locales['en-US'].X = '%r'; +Date.ext.locales['en-GB'] = Date.ext.locales.en; +Date.ext.locales['en-AU'] = Date.ext.locales['en-GB']; +Date.ext.formats = { + a: function(d) { return Date.ext.locales[d.locale].a[d.getDay()]; }, + A: function(d) { return Date.ext.locales[d.locale].A[d.getDay()]; }, + b: function(d) { return Date.ext.locales[d.locale].b[d.getMonth()]; }, + B: function(d) { return Date.ext.locales[d.locale].B[d.getMonth()]; }, + c: 'toLocaleString', + C: function(d) { return Date.ext.util.xPad(parseInt(d.getFullYear()/100, 10), 0); }, + d: ['getDate', '0'], + e: ['getDate', ' '], + g: function(d) { return Date.ext.util.xPad(parseInt(Date.ext.util.G(d)/100, 10), 0); }, + G: function(d) { + var y = d.getFullYear(); + var V = parseInt(Date.ext.formats.V(d), 10); + var W = parseInt(Date.ext.formats.W(d), 10); + + if(W > V) { + y++; + } else if(W===0 && V>=52) { + y--; + } + + return y; + }, + H: ['getHours', '0'], + I: function(d) { var I=d.getHours()%12; return Date.ext.util.xPad(I===0?12:I, 0); }, + j: function(d) { + var ms = d - new Date('' + d.getFullYear() + '/1/1 GMT'); + ms += d.getTimezoneOffset()*60000; + var doy = parseInt(ms/60000/60/24, 10)+1; + return Date.ext.util.xPad(doy, 0, 100); + }, + m: function(d) { return Date.ext.util.xPad(d.getMonth()+1, 0); }, + M: ['getMinutes', '0'], + p: function(d) { return Date.ext.locales[d.locale].p[d.getHours() >= 12 ? 1 : 0 ]; }, + P: function(d) { return Date.ext.locales[d.locale].P[d.getHours() >= 12 ? 1 : 0 ]; }, + S: ['getSeconds', '0'], + u: function(d) { var dow = d.getDay(); return dow===0?7:dow; }, + U: function(d) { + var doy = parseInt(Date.ext.formats.j(d), 10); + var rdow = 6-d.getDay(); + var woy = parseInt((doy+rdow)/7, 10); + return Date.ext.util.xPad(woy, 0); + }, + V: function(d) { + var woy = parseInt(Date.ext.formats.W(d), 10); + var dow1_1 = (new Date('' + d.getFullYear() + '/1/1')).getDay(); + var idow = woy + (dow1_1 > 4 || dow1_1 <= 1 ? 0 : 1); + if(idow == 53 && (new Date('' + d.getFullYear() + '/12/31')).getDay() < 4) + { + idow = 1; + } + else if(idow === 0) + { + idow = Date.ext.formats.V(new Date('' + (d.getFullYear()-1) + '/12/31')); + } + + return Date.ext.util.xPad(idow, 0); + }, + w: 'getDay', + W: function(d) { + var doy = parseInt(Date.ext.formats.j(d), 10); + var rdow = 7-Date.ext.formats.u(d); + var woy = parseInt((doy+rdow)/7, 10); + return Date.ext.util.xPad(woy, 0, 10); + }, + y: function(d) { return Date.ext.util.xPad(d.getFullYear()%100, 0); }, + Y: 'getFullYear', + z: function(d) { + var o = d.getTimezoneOffset(); + var H = Date.ext.util.xPad(parseInt(Math.abs(o/60), 10), 0); + var M = Date.ext.util.xPad(o%60, 0); + return (o>0?'-':'+') + H + M; + }, + Z: function(d) { return d.toString().replace(/^.*\(([^)]+)\)$/, '$1'); }, + '%': function(d) { return '%'; } +}; +Date.ext.aggregates = { + c: 'locale', + D: '%m/%d/%y', + h: '%b', + n: '\n', + r: '%I:%M:%S %p', + R: '%H:%M', + t: '\t', + T: '%H:%M:%S', + x: 'locale', + X: 'locale' +}; +Date.ext.aggregates.z = Date.ext.formats.z(new Date()); +Date.ext.aggregates.Z = Date.ext.formats.Z(new Date()); +Date.ext.unsupported = { }; +function strftime(fmt, thisTime) +{ + var thisDate = new Date(); + thisDate.setTime(thisTime / 1000); + + if(!(thisDate.locale in Date.ext.locales)) + { + if(thisDate.locale.replace(/-[a-zA-Z]+$/, '') in Date.ext.locales) + { + thisDate.locale = thisDate.locale.replace(/-[a-zA-Z]+$/, ''); + } + else + { + thisDate.locale = 'en-US'; + } + } + + var d = thisDate; + while(fmt.match(/%[cDhnrRtTxXzZ]/)) + { + fmt = fmt.replace(/%([cDhnrRtTxXzZ])/g, function(m0, m1) + { + var f = Date.ext.aggregates[m1]; + return (f == 'locale' ? Date.ext.locales[d.locale][m1] : f); + }); + } + + var str = fmt.replace(/%([aAbBCdegGHIjmMpPSuUVwWyY%])/g, function(m0, m1) + { + var f = Date.ext.formats[m1]; + if(typeof(f) == 'string') { + return d[f](); + } else if(typeof(f) == 'function') { + return f.call(d, d); + } else if(typeof(f) == 'object' && typeof(f[0]) == 'string') { + return Date.ext.util.xPad(d[f[0]](), f[1]); + } else { + return m1; + } + }); + d=null; + return str; +}; + +// End of code from Philip S Tellis + // Error handling diff --git a/src/settings.sml b/src/settings.sml index 4d0e289f..23860b31 100644 --- a/src/settings.sml +++ b/src/settings.sml @@ -206,6 +206,7 @@ val basisM = foldl (fn ((k, v : string), m) => M.insert (m, ("Basis", k), v)) M. val jsFuncsBase = basisM [("alert", "alert"), ("stringToTime", "stringToTime"), ("stringToTime_error", "stringToTime_error"), + ("timef", "strftime"), ("confirm", "confrm"), ("get_client_source", "sg"), ("current", "scur"), diff --git a/tests/timef.ur b/tests/timef.ur new file mode 100644 index 00000000..1e473482 --- /dev/null +++ b/tests/timef.ur @@ -0,0 +1,12 @@ +fun main () : transaction page = + date <- source ""; + format <- source ""; + return + + + + | Some d => {[timef f d]})}/> + -- cgit v1.2.3