summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/js/urweb.js200
-rw-r--r--src/settings.sml1
-rw-r--r--tests/timef.ur12
3 files changed, 213 insertions, 0 deletions
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 <philip@bluesmoon.info>
+ 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)<r && r>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 <xml><body>
+ <ctextbox source={date}/>
+ <ctextbox source={format}/>
+ <dyn signal={d <- signal date;
+ f <- signal format;
+ return (case read d of
+ None => <xml/>
+ | Some d => <xml>{[timef f d]}</xml>)}/>
+ </body></xml>