blob: d6c7e3650a0e52bbf75a430f90b08cf3dfab83b7 [file] [log] [blame]
/*
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
var datepicker_spawner = null
var calendarpicker_spawner = null
// makeSelect: Creates a <select> object with options
function makeSelect(options, id, selval) {
var sel = document.createElement('select')
sel.setAttribute("name", id)
sel.setAttribute("id", id)
// For each options element, create it in the DOM
for (var key in options) {
var opt = document.createElement('option')
// Hash or array?
if (typeof key == "string") {
opt.setAttribute("value", key)
// Option is selected by default?
if (key == selval) {
opt.setAttribute("selected", "selected")
}
} else {
// Option is selected by default?
if (options[key] == selval) {
opt.setAttribute("selected", "selected")
}
}
opt.text = options[key]
sel.appendChild(opt)
}
return sel
}
// splitDiv: Makes a split div with 2 elements,
// and puts div2 into the right column,
// and 'name' as text in the left one.
function splitDiv(id, name, div2) {
var div = document.createElement('div')
var subdiv = document.createElement('div')
var radio = document.createElement('input')
radio.setAttribute("type", "radio")
radio.setAttribute("name", "datepicker_radio")
radio.setAttribute("value", name)
radio.setAttribute("id", "datepicker_radio_" + id)
radio.setAttribute("onclick", "calcTimespan('"+ id + "')")
var label = document.createElement('label')
label.innerHTML = "&nbsp; " + name + ": "
label.setAttribute("for", "datepicker_radio_" + id)
subdiv.appendChild(radio)
subdiv.appendChild(label)
subdiv.style.float = "left"
div2.style.float = "left"
subdiv.style.width = "120px"
subdiv.style.height = "48px"
div2.style.height = "48px"
div2.style.width = "250px"
div.appendChild(subdiv)
div.appendChild(div2)
return div
}
// calcTimespan: Calculates the value and representational text
// for the datepicker choice and puts it in the datepicker's
// spawning input/select element.
function calcTimespan(what) {
var wat = ""
var tval = ""
// Less than N units ago?
if (what == 'lt') {
var N = document.getElementById('datepicker_lti').value
var unit = document.getElementById('datepicker_lts').value
if (N.length > 0) {
wat = "< " + N + unit + " ago"
tval = "lte=" + N + unit
}
}
// More than N units ago?
if (what == 'mt') {
var N = document.getElementById('datepicker_mti').value
var unit = document.getElementById('datepicker_mts').value
if (N.length > 0) {
wat = "> " + N + unit + " ago"
tval = "gte=" + N + unit
}
}
// Date range?
if (what == 'cd') {
var f = document.getElementById('datepicker_cfrom').value
var t = document.getElementById('datepicker_cto').value
if (f.length > 0 && t.length > 0) {
wat = "From " + f + " to " + t
tval = "dfr=" + f + "|dto=" + t
}
}
// If we calc'ed a value and spawner exists, update its key/val
if (datepicker_spawner && what && wat.length > 0) {
document.getElementById('datepicker_radio_' + what).checked = true
if (datepicker_spawner.options) {
datepicker_spawner.options[0].value = tval
datepicker_spawner.options[0].text = wat
} else if (datepicker_spawner.value) {
datepicker_spawner.value = tval
}
}
}
// datePicker: spawns a date picker with various
// timespan options right next to the parent caller.
function datePicker(parent, seedPeriod) {
datepicker_spawner = parent
var div = document.getElementById('datepicker_popup')
if (!div) {
div = document.createElement('div')
var id = parseInt(Math.random() * 10000).toString(16)
div.setAttribute("id", "datepicker_popup")
div.setAttribute("class", "datepicker")
}
div.innerHTML = ""
div.style.display = "block"
var bb = parent.getBoundingClientRect()
div.style.top = (bb.bottom + 8) + "px"
div.style.left = (bb.left + 32) + "px"
// -- Less than N $units ago
var ltdiv = document.createElement('div')
var lti = document.createElement('input')
lti.setAttribute("id", "datepicker_lti")
lti.style.width = "48px"
lti.setAttribute("onkeyup", "calcTimespan('lt')")
lti.setAttribute("onblur", "calcTimespan('lt')")
ltdiv.appendChild(lti)
var lts = makeSelect({
'd': "Day(s)",
'w': 'Week(s)',
'M': "Month(s)",
'y': "Year(s)"
}, 'datepicker_lts', 'm')
lts.setAttribute("onchange", "calcTimespan('lt')")
ltdiv.appendChild(lts)
ltdiv.appendChild(document.createTextNode(' ago'))
div.appendChild(splitDiv('lt', 'Less than', ltdiv))
// -- More than N $units ago
var mtdiv = document.createElement('div')
var mti = document.createElement('input')
mti.style.width = "48px"
mti.setAttribute("id", "datepicker_mti")
mti.setAttribute("onkeyup", "calcTimespan('mt')")
mti.setAttribute("onblur", "calcTimespan('mt')")
mtdiv.appendChild(mti)
var mts = makeSelect({
'd': "Day(s)",
'w': 'Week(s)',
'M': "Month(s)",
'y': "Year(s)"
}, 'datepicker_mts', 'm')
mtdiv.appendChild(mts)
mts.setAttribute("onchange", "calcTimespan('mt')")
mtdiv.appendChild(document.createTextNode(' ago'))
div.appendChild(splitDiv('mt', 'More than', mtdiv))
// -- Calendar timespan
var cdiv = document.createElement('div')
var cfrom = document.createElement('input')
cfrom.style.width = "90px"
cfrom.setAttribute("id", "datepicker_cfrom")
cfrom.setAttribute("onfocus", "showCalendarPicker(this)")
cfrom.setAttribute("onchange", "calcTimespan('cd')")
cdiv.appendChild(document.createTextNode('From: '))
cdiv.appendChild(cfrom)
var cto = document.createElement('input')
cto.style.width = "90px"
cto.setAttribute("id", "datepicker_cto")
cto.setAttribute("onfocus", "showCalendarPicker(this)")
cto.setAttribute("onchange", "calcTimespan('cd')")
cdiv.appendChild(document.createTextNode('To: '))
cdiv.appendChild(cto)
div.appendChild(splitDiv('cd', 'Date range', cdiv))
// -- Magic button
var okay = document.createElement('input')
okay.setAttribute("type", "button")
okay.setAttribute("value", "Okay")
okay.setAttribute("onclick", "setDatepickerDate()")
div.appendChild(okay)
parent.parentNode.appendChild(div)
document.body.setAttribute("onclick", "")
window.setTimeout(function() { document.body.setAttribute("onclick", "blurDatePicker(event)") }, 200)
lti.focus()
// This is for recalcing the set options if spawned from a
// select/input box with an existing value derived from an
// earlier call to datePicker
var ptype = ""
if (parent.value.search(/=/) != -1) {
// Less than N units ago?
if (parent.value.match(/lte/)) {
var m = parent.value.match(/lte=(\d+)([dMyw])/)
ptype = 'lt'
if (m) {
document.getElementById('datepicker_lti').value = m[1]
var sel = document.getElementById('datepicker_lts')
for (var i in sel.options) {
if (sel.options[i].value == m[2]) {
sel.options[i].selected = "selected"
} else {
sel.options[i].selected = null
}
}
}
}
// More than N units ago?
if (parent.value.match(/gte/)) {
ptype = 'mt'
var m = parent.value.match(/gte=(\d+)([dMyw])/)
if (m) {
document.getElementById('datepicker_mti').value = m[1]
var sel = document.getElementById('datepicker_mts')
for (var i in sel.options) {
if (sel.options[i].value == m[2]) {
sel.options[i].selected = "selected"
} else {
sel.options[i].selected = null
}
}
}
}
// Date range?
if (parent.value.match(/dfr/)) {
ptype = 'cd'
var mf = parent.value.match(/dfr=(\d+-\d+-\d+)/)
var mt = parent.value.match(/dto=(\d+-\d+-\d+)/)
if (mf && mt) {
document.getElementById('datepicker_cfrom').value = mf[1]
document.getElementById('datepicker_cto').value = mt[1]
}
}
calcTimespan(ptype)
}
}
function datePickerValue(seedPeriod) {
// This is for recalcing the set options if spawned from a
// select/input box with an existing value derived from an
// earlier call to datePicker
var ptype = ""
var rv = seedPeriod
if (seedPeriod && seedPeriod.search && seedPeriod.search(/=/) != -1) {
// Less than N units ago?
if (seedPeriod.match(/lte/)) {
var m = seedPeriod.match(/lte=(\d+)([dMyw])/)
ptype = 'lt'
rv = "<" + m[1] + m[2] + " ago"
}
// More than N units ago?
if (seedPeriod.match(/gte/)) {
ptype = 'mt'
var m = seedPeriod.match(/gte=(\d+)([dMyw])/)
rv = ">" + m[1] + m[2] + " ago"
}
// Date range?
if (seedPeriod.match(/dfr/)) {
ptype = 'cd'
var mf = seedPeriod.match(/dfr=(\d+-\d+-\d+)/)
var mt = seedPeriod.match(/dto=(\d+-\d+-\d+)/)
if (mf && mt) {
rv = "from " + mf[1] + " to " + mt[1]
}
}
}
return rv
}
function datePickerDouble(seedPeriod) {
// This basically takes a date-arg and doubles it backwards
// so >=3M becomes =>6M etc. Also returns the cutoff for
// the original date and the span in days of the original
var ptype = ""
var rv = seedPeriod
var dbl = seedPeriod
var tspan = 1
var dfrom = new Date()
var dto = new Date()
// datepicker range?
if (seedPeriod && seedPeriod.search && seedPeriod.search(/=/) != -1) {
// Less than N units ago?
if (seedPeriod.match(/lte/)) {
var m = seedPeriod.match(/lte=(\d+)([dMyw])/)
ptype = 'lt'
rv = "<" + m[1] + m[2] + " ago"
dbl = "lte=" + (parseInt(m[1])*2) + m[2]
if (m[2] == "M") {
dfrom.setMonth(dfrom.getMonth()-parseInt(m[1]), dfrom.getDate())
}
if (m[2] == "d") {
dfrom.setDate(dfrom.getDate()-parseInt(m[1]))
}
if (m[2] == "y") {
dfrom.setYear(dfrom.getFullYear()-parseInt(m[1]))
}
if (m[2] == "w") {
dfrom.setDate(dfrom.getDate()-(parseInt(m[1])*7))
}
tspan = parseInt((dto.getTime() - dfrom.getTime() + 5000) / (1000*86400))
}
// More than N units ago?
if (seedPeriod.match(/gte/)) {
ptype = 'mt'
var m = seedPeriod.match(/gte=(\d+)([dMyw])/)
rv = ">" + m[1] + m[2] + " ago"
dbl = "gte=" + (parseInt(m[1])*2) + m[2]
tspan = parseInt(parseInt(m[1]) * 30.4)
dfrom = null
if (m[2] == "M") {
dto.setMonth(dto.getMonth()-parseInt(m[1]), dto.getDate())
}
if (m[2] == "d") {
dto.setDate(dto.getDate()-parseInt(m[1]))
}
if (m[2] == "y") {
dto.setYear(dto.getFullYear()-parseInt(m[1]))
}
if (m[2] == "w") {
dto.setDate(dto.getDate()-(parseInt(m[1])*7))
}
tspan = null
}
// Date range?
if (seedPeriod.match(/dfr/)) {
ptype = 'cd'
var mf = seedPeriod.match(/dfr=(\d+)-(\d+)-(\d+)/)
var mt = seedPeriod.match(/dto=(\d+)-(\d+)-(\d+)/)
if (mf && mt) {
rv = "from " + mf[1] + " to " + mt[1]
dfrom = new Date(parseInt(mf[1]),parseInt(mf[2])-1,parseInt(mf[3]), 0, 0, 0)
dto = new Date(parseInt(mt[1]),parseInt(mt[2])-1,parseInt(mt[3]), 23, 59, 59)
tspan = parseInt((dto.getTime() - dfrom.getTime() + 5000) / (1000*86400))
var dpast = new Date(dfrom)
dpast.setDate(dpast.getDate() - tspan)
dbl = seedPeriod.replace(/dfr=[^|]+/, "dfr=" + (dpast.getFullYear()) + '-' + (dpast.getMonth()+1) + '-' + dpast.getDate())
} else {
tspan = 0
}
}
}
// Specific month?
else if (seedPeriod.match(/^(\d+)-(\d+)$/)) {
ptype = 'mr'
var mr = seedPeriod.match(/(\d+)-(\d+)/)
if (mr) {
rv = seedPeriod
dfrom = new Date(parseInt(mr[1]),parseInt(mr[2])-1,1, 0, 0, 0)
dto = new Date(parseInt(mr[1]),parseInt(mr[2]),0, 23, 59, 59)
tspan = parseInt((dto.getTime() - dfrom.getTime() + 5000) / (1000*86400))
var dpast = new Date(dfrom)
dpast.setDate(dpast.getDate() - tspan)
dbl = "dfr=" + (dpast.getFullYear()) + '-' + (dpast.getMonth()+1) + '-' + dpast.getDate() + "|dto=" + (dto.getFullYear()) + '-' + (dto.getMonth()+1) + '-' + dto.getDate()
} else {
tspan = 0
}
}
// just N days?
else if (parseInt(seedPeriod).toString() == seedPeriod.toString()) {
tspan = parseInt(seedPeriod)
dfrom.setDate(dfrom.getDate() - tspan)
dbl = "lte=" + (tspan*2) + "d"
}
return [dbl, dfrom, dto, tspan]
}
// set date in caller and hide datepicker again.
function setDatepickerDate() {
calcTimespan()
blurDatePicker()
}
// findParent: traverse DOM and see if we can find a parent to 'el'
// called 'name'. This is used for figuring out whether 'el' has
// lost focus or not.
function findParent(el, name) {
if (el.getAttribute && el.getAttribute("id") == name) {
return true
}
if (el.parentNode && el.parentNode.getAttribute) {
if (el.parentNode.getAttribute("id") != name) {
return findParent(el.parentNode, name)
} else {
return true
}
} else {
return false;
}
}
// function for hiding the date picker
function blurDatePicker(evt) {
var es = evt ? (evt.target || evt.srcElement) : null;
if ((!es || !es.parentNode || (!findParent(es, "datepicker_popup") && !findParent(es, "calendarpicker_popup"))) && !(es ? es : "null").toString().match(/javascript:void/)) {
document.getElementById('datepicker_popup').style.display = "none"
}
}
// draws the actual calendar inside a calendarPicker object
function drawCalendarPicker(obj, date) {
obj.focus()
// Default to NOW for calendar.
var now = new Date()
// if called with an existing date (YYYY-MM-DD),
// convert it to a JS date object and use that for
// rendering the calendar
if (date) {
var ar = date.split(/-/)
now = new Date(ar[0],parseInt(ar[1])-1,ar[2])
}
var days = ['Mon','Tue','Wed','Thu','Fri','Sat','Sun']
var mat = now
// Go to first day of the month
mat.setDate(1)
obj.innerHTML = "<h3>" + months[mat.getMonth()] + ", " + mat.getFullYear() + ":</h3>"
var tm = mat.getMonth()
// -- Nav buttons --
// back-a-year button
var a = document.createElement('a')
a.setAttribute("onclick", "drawCalendarPicker(this.parentNode, '" + (mat.getFullYear()-1) + '-' + (mat.getMonth()+1) + '-' + mat.getDate() + "');")
a.setAttribute("href", "javascript:void(0);")
a.innerHTML = "≪"
obj.appendChild(a)
// back-a-month button
a = document.createElement('a')
a.setAttribute("onclick", "drawCalendarPicker(this.parentNode, '" + mat.getFullYear() + '-' + (mat.getMonth()) + '-' + mat.getDate() + "');")
a.setAttribute("href", "javascript:void(0);")
a.innerHTML = "&lt;"
obj.appendChild(a)
// forward-a-month button
a = document.createElement('a')
a.setAttribute("onclick", "drawCalendarPicker(this.parentNode, '" + mat.getFullYear() + '-' + (mat.getMonth()+2) + '-' + mat.getDate() + "');")
a.setAttribute("href", "javascript:void(0);")
a.innerHTML = "&gt;"
obj.appendChild(a)
// forward-a-year button
a = document.createElement('a')
a.setAttribute("onclick", "drawCalendarPicker(this.parentNode, '" + (mat.getFullYear()+1) + '-' + (mat.getMonth()+1) + '-' + mat.getDate() + "');")
a.setAttribute("href", "javascript:void(0);")
a.innerHTML = "≫"
obj.appendChild(a)
obj.appendChild(document.createElement('br'))
// Table containing the dates of the selected month
var table = document.createElement('table')
table.setAttribute("border", "1")
table.style.margin = "0 auto"
// Add header day names
var tr = document.createElement('tr');
for (var m in days) {
var td = document.createElement('th')
td.innerHTML = days[m]
tr.appendChild(td)
}
table.appendChild(tr)
// Until we hit the first day in a month, add blank days
tr = document.createElement('tr');
var weekday = mat.getDay()
if (weekday == 0) {
weekday = 7
}
weekday--;
for (var i = 0; i < weekday; i++) {
var td = document.createElement('td')
tr.appendChild(td)
}
// While still in this month, add day then increment date by 1 day.
while (mat.getMonth() == tm) {
weekday = mat.getDay()
if (weekday == 0) {
weekday = 7
}
weekday--;
if (weekday == 0) {
table.appendChild(tr)
tr = document.createElement('tr');
}
td = document.createElement('td')
// onclick for setting the calendarPicker's parent to this val.
td.setAttribute("onclick", "setCalendarDate('" + mat.getFullYear() + '-' + (mat.getMonth()+1) + '-' + mat.getDate() + "');")
td.innerHTML = mat.getDate()
mat.setDate(mat.getDate()+1)
tr.appendChild(td)
}
table.appendChild(tr)
obj.appendChild(table)
}
// callback for datePicker; sets the cd value to what date was picked
function setCalendarDate(what) {
calendarpicker_spawner.value = what
var div = document.getElementById('calendarpicker_popup')
div.parentNode.focus()
div.style.display = "none"
calcTimespan('cd')
}
// caller for when someone clicks on a calendarPicker enabled field
function showCalendarPicker(parent, seedDate) {
calendarpicker_spawner = parent
// If supplied with a YYYY-MM-DD date, use this to seed the calendar
if (!seedDate) {
var m = parent.value.match(/(\d+-\d+-\d+)/)
if (m) {
seedDate = m[1]
}
}
// Show or create the calendar object
var div = document.getElementById('calendarpicker_popup')
if (!div) {
div = document.createElement('div')
div.setAttribute("id", "calendarpicker_popup")
div.setAttribute("class", "calendarpicker")
document.getElementById('datepicker_popup').appendChild(div)
div.innerHTML = "Calendar goes here..."
}
div.style.display = "block"
var bb = parent.getBoundingClientRect()
// Align with the calling object, slightly below
div.style.top = (bb.bottom + 8) + "px"
div.style.left = (bb.right - 32) + "px"
drawCalendarPicker(div, seedDate)
}