|
|
// Core JavaScript helper functions
|
|
|
'use strict';
|
|
|
|
|
|
// quickElement(tagType, parentReference [, textInChildNode, attribute, attributeValue ...]);
|
|
|
/**
|
|
|
* 快速创建并插入DOM元素
|
|
|
* 简化创建元素、添加文本、设置属性、插入父容器的流程
|
|
|
* @param {string} arguments[0] - 要创建的元素标签名(如"div"、"a")
|
|
|
* @param {HTMLElement} arguments[1] - 父容器元素(新元素将插入到该容器中)
|
|
|
* @param {string} [arguments[2]] - 新元素的文本内容(可选)
|
|
|
* @param {string} [arguments[3], arguments[4]...] - 属性名和属性值(成对传入,可选)
|
|
|
* @return {HTMLElement} 创建并插入后的新元素
|
|
|
*/
|
|
|
function quickElement() {
|
|
|
const obj = document.createElement(arguments[0]);
|
|
|
if (arguments[2]) {
|
|
|
const textNode = document.createTextNode(arguments[2]);
|
|
|
obj.appendChild(textNode);
|
|
|
}
|
|
|
const len = arguments.length;
|
|
|
for (let i = 3; i < len; i += 2) {
|
|
|
obj.setAttribute(arguments[i], arguments[i + 1]);
|
|
|
}
|
|
|
arguments[1].appendChild(obj);
|
|
|
return obj;
|
|
|
}
|
|
|
|
|
|
// "a" is reference to an object
|
|
|
/**
|
|
|
* 清空元素的所有子节点
|
|
|
* @param {HTMLElement} a - 要清空子节点的父元素
|
|
|
*/
|
|
|
function removeChildren(a) {
|
|
|
while (a.hasChildNodes()) {
|
|
|
a.removeChild(a.lastChild);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
// Find-position functions by PPK
|
|
|
// See https://www.quirksmode.org/js/findpos.html
|
|
|
// ----------------------------------------------------------------------------
|
|
|
/**
|
|
|
* 计算元素相对于文档的水平偏移量(X轴位置)
|
|
|
* @param {HTMLElement} obj - 要计算位置的元素
|
|
|
* @return {number} 元素左上角相对于文档左侧的距离(像素)
|
|
|
*/
|
|
|
function findPosX(obj) {
|
|
|
let curleft = 0;
|
|
|
// 若元素有offsetParent(定位父元素),循环向上计算偏移
|
|
|
if (obj.offsetParent) {
|
|
|
while (obj.offsetParent) {
|
|
|
curleft += obj.offsetLeft - obj.scrollLeft;
|
|
|
obj = obj.offsetParent;
|
|
|
}
|
|
|
} else if (obj.x) {
|
|
|
curleft += obj.x;
|
|
|
}
|
|
|
return curleft;
|
|
|
}
|
|
|
/**
|
|
|
* 计算元素相对于文档的垂直偏移量(Y轴位置)
|
|
|
* @param {HTMLElement} obj - 要计算位置的元素
|
|
|
* @return {number} 元素左上角相对于文档顶部的距离(像素)
|
|
|
*/
|
|
|
function findPosY(obj) {
|
|
|
let curtop = 0;
|
|
|
if (obj.offsetParent) {
|
|
|
while (obj.offsetParent) {
|
|
|
curtop += obj.offsetTop - obj.scrollTop;
|
|
|
obj = obj.offsetParent;
|
|
|
}
|
|
|
} else if (obj.y) {
|
|
|
curtop += obj.y;
|
|
|
}
|
|
|
return curtop;
|
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
// Date object extensions
|
|
|
// ----------------------------------------------------------------------------
|
|
|
{
|
|
|
/**
|
|
|
* 获取12小时制的小时数(0-11 → 1-12)
|
|
|
* @return {number} 12小时制小时数(如13点返回1,0点返回12)
|
|
|
*/
|
|
|
Date.prototype.getTwelveHours = function() {
|
|
|
return this.getHours() % 12 || 12;
|
|
|
};
|
|
|
/**
|
|
|
* 获取两位数的月份(1-9 → 01-09,10-12 → 10-12)
|
|
|
* @return {string} 两位数月份字符串
|
|
|
*/
|
|
|
Date.prototype.getTwoDigitMonth = function() {
|
|
|
return (this.getMonth() < 9) ? '0' + (this.getMonth() + 1) : (this.getMonth() + 1);
|
|
|
};
|
|
|
|
|
|
Date.prototype.getTwoDigitDate = function() {
|
|
|
return (this.getDate() < 10) ? '0' + this.getDate() : this.getDate();
|
|
|
};
|
|
|
|
|
|
Date.prototype.getTwoDigitTwelveHour = function() {
|
|
|
return (this.getTwelveHours() < 10) ? '0' + this.getTwelveHours() : this.getTwelveHours();
|
|
|
};
|
|
|
|
|
|
Date.prototype.getTwoDigitHour = function() {
|
|
|
return (this.getHours() < 10) ? '0' + this.getHours() : this.getHours();
|
|
|
};
|
|
|
|
|
|
Date.prototype.getTwoDigitMinute = function() {
|
|
|
return (this.getMinutes() < 10) ? '0' + this.getMinutes() : this.getMinutes();
|
|
|
};
|
|
|
|
|
|
Date.prototype.getTwoDigitSecond = function() {
|
|
|
return (this.getSeconds() < 10) ? '0' + this.getSeconds() : this.getSeconds();
|
|
|
};
|
|
|
|
|
|
Date.prototype.getAbbrevDayName = function() {
|
|
|
return typeof window.CalendarNamespace === "undefined"
|
|
|
? '0' + this.getDay()
|
|
|
: window.CalendarNamespace.daysOfWeekAbbrev[this.getDay()];
|
|
|
};
|
|
|
|
|
|
Date.prototype.getFullDayName = function() {
|
|
|
return typeof window.CalendarNamespace === "undefined"
|
|
|
? '0' + this.getDay()
|
|
|
: window.CalendarNamespace.daysOfWeek[this.getDay()];
|
|
|
};
|
|
|
|
|
|
Date.prototype.getAbbrevMonthName = function() {
|
|
|
return typeof window.CalendarNamespace === "undefined"
|
|
|
? this.getTwoDigitMonth()
|
|
|
: window.CalendarNamespace.monthsOfYearAbbrev[this.getMonth()];
|
|
|
};
|
|
|
|
|
|
Date.prototype.getFullMonthName = function() {
|
|
|
return typeof window.CalendarNamespace === "undefined"
|
|
|
? this.getTwoDigitMonth()
|
|
|
: window.CalendarNamespace.monthsOfYear[this.getMonth()];
|
|
|
};
|
|
|
/**
|
|
|
* 格式化日期为指定字符串(类似Python的strftime)
|
|
|
* @param {string} format - 格式化字符串(含%占位符,如“%Y-%m-%d %H:%M”)
|
|
|
* @return {string} 格式化后的日期字符串
|
|
|
*/
|
|
|
Date.prototype.strftime = function(format) {
|
|
|
const fields = {
|
|
|
a: this.getAbbrevDayName(),
|
|
|
A: this.getFullDayName(),
|
|
|
b: this.getAbbrevMonthName(),
|
|
|
B: this.getFullMonthName(),
|
|
|
c: this.toString(),
|
|
|
d: this.getTwoDigitDate(),
|
|
|
H: this.getTwoDigitHour(),
|
|
|
I: this.getTwoDigitTwelveHour(),
|
|
|
m: this.getTwoDigitMonth(),
|
|
|
M: this.getTwoDigitMinute(),
|
|
|
p: (this.getHours() >= 12) ? 'PM' : 'AM',
|
|
|
S: this.getTwoDigitSecond(),
|
|
|
w: '0' + this.getDay(),
|
|
|
x: this.toLocaleDateString(),
|
|
|
X: this.toLocaleTimeString(),
|
|
|
y: ('' + this.getFullYear()).substr(2, 4),
|
|
|
Y: '' + this.getFullYear(),
|
|
|
'%': '%'
|
|
|
};
|
|
|
let result = '', i = 0;
|
|
|
while (i < format.length) {
|
|
|
if (format.charAt(i) === '%') {
|
|
|
result += fields[format.charAt(i + 1)];
|
|
|
++i;
|
|
|
}
|
|
|
else {
|
|
|
result += format.charAt(i);
|
|
|
}
|
|
|
++i;
|
|
|
}
|
|
|
return result;
|
|
|
};
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
// String object extensions
|
|
|
// ----------------------------------------------------------------------------
|
|
|
/**
|
|
|
* 将字符串按指定格式解析为Date对象(类似Python的strptime)
|
|
|
* 支持的格式占位符:%d(日期)、%m(月份)、%Y(四位数年份)、%y(两位数年份)
|
|
|
* @param {string} format - 解析格式(如“%Y-%m-%d”“%d/%m/%y”)
|
|
|
* @return {Date} 解析后的Date对象(基于UTC时间)
|
|
|
*/
|
|
|
String.prototype.strptime = function(format) {
|
|
|
const split_format = format.split(/[.\-/]/);
|
|
|
const date = this.split(/[.\-/]/);
|
|
|
let i = 0;
|
|
|
let day, month, year;
|
|
|
while (i < split_format.length) {
|
|
|
switch (split_format[i]) {
|
|
|
case "%d":
|
|
|
day = date[i];
|
|
|
break;
|
|
|
case "%m":
|
|
|
month = date[i] - 1;
|
|
|
break;
|
|
|
case "%Y":
|
|
|
year = date[i];
|
|
|
break;
|
|
|
case "%y":
|
|
|
// A %y value in the range of [00, 68] is in the current
|
|
|
// century, while [69, 99] is in the previous century,
|
|
|
// according to the Open Group Specification.
|
|
|
if (parseInt(date[i], 10) >= 69) {
|
|
|
year = date[i];
|
|
|
} else {
|
|
|
year = (new Date(Date.UTC(date[i], 0))).getUTCFullYear() + 100;
|
|
|
}
|
|
|
break;
|
|
|
}
|
|
|
++i;
|
|
|
}
|
|
|
// Create Date object from UTC since the parsed value is supposed to be
|
|
|
// in UTC, not local time. Also, the calendar uses UTC functions for
|
|
|
// date extraction.
|
|
|
return new Date(Date.UTC(year, month, day));
|
|
|
};
|
|
|
}
|