refactor: refactor for modern layout
- split frontend and backend. - update backend with modern Python dev strategies.
This commit is contained in:
483
frontend/static/js/api.js
Normal file
483
frontend/static/js/api.js
Normal file
@@ -0,0 +1,483 @@
|
||||
// the api use bool to return status: fail: return false, true: return data(including true and false)
|
||||
// the api use other type to return data: fail: return undefined, true: return data(if the returned value have change be null, return undefined instaed).
|
||||
|
||||
// var cached_salt = undefined
|
||||
|
||||
/*
|
||||
function ccn_api_common_salt(_username) {
|
||||
// true or false
|
||||
// gotten salt store in cached_salt.
|
||||
var gotten_data = undefined;
|
||||
$.ajax({
|
||||
url: '/api/common/salt',
|
||||
type: "POST",
|
||||
async: false,
|
||||
data: {
|
||||
username: _username
|
||||
},
|
||||
success: function (data) {
|
||||
gotten_data = data;
|
||||
}
|
||||
});
|
||||
|
||||
if (IsResponseOK(gotten_data)) {
|
||||
cached_salt = gotten_data['data'];
|
||||
return true;
|
||||
} else return false;
|
||||
}
|
||||
|
||||
function ccn_api_common_login(_username, password) {
|
||||
// return true or false, token is managed by this js file self.
|
||||
// if cached_salt is undefined, return false directly
|
||||
if (typeof(cached_salt) == undefined) return false;
|
||||
|
||||
var gotten_data = undefined;
|
||||
$.ajax({
|
||||
url: '/api/common/login',
|
||||
type: "POST",
|
||||
async: false,
|
||||
data: {
|
||||
username: _username,
|
||||
password: ComputPasswordWithSalt(password, cached_salt)
|
||||
},
|
||||
success: function (data) {
|
||||
gotten_data = data;
|
||||
}
|
||||
});
|
||||
if (IsResponseOK(gotten_data) && gotten_data['data'] != '') {
|
||||
ccn_localstorageAssist_SetApiToken(gotten_data['data']);
|
||||
cached_salt = undefined;
|
||||
return true;
|
||||
} else return false;
|
||||
}
|
||||
*/
|
||||
|
||||
// ============================================ template
|
||||
// all api can be implemented by these 2 function, except 3 token related func.
|
||||
// so all api func should use these 2 func except 3 token process api.
|
||||
function ccn_api_dataTemplate(_url, _data) {
|
||||
// return data or undefined
|
||||
var gotten_data = undefined;
|
||||
$.ajax({
|
||||
url: _url,
|
||||
type: "POST",
|
||||
async: false,
|
||||
data: _data,
|
||||
success: function (data) {
|
||||
gotten_data = data;
|
||||
}
|
||||
});
|
||||
|
||||
if (IsResponseOK(gotten_data) && !(gotten_data['data'] === null)) return gotten_data['data'];
|
||||
else return undefined;
|
||||
}
|
||||
|
||||
function ccn_api_boolTemplate(_url, _data) {
|
||||
// return true or false
|
||||
var gotten_data = undefined;
|
||||
$.ajax({
|
||||
url: _url,
|
||||
type: "POST",
|
||||
async: false,
|
||||
data: _data,
|
||||
success: function (data) {
|
||||
gotten_data = data;
|
||||
}
|
||||
});
|
||||
|
||||
return (IsResponseOK(gotten_data) && gotten_data['data']);
|
||||
}
|
||||
|
||||
// deserialize & serialize calendar description function
|
||||
|
||||
function ccn_api_serializeDescription(_description, _color) {
|
||||
var sobj = {
|
||||
description: _description,
|
||||
color: _color
|
||||
}
|
||||
return JSON.stringify(sobj);
|
||||
}
|
||||
|
||||
function ccn_api_deserializeDescription(strl) {
|
||||
try {
|
||||
return $.parseJSON(strl);
|
||||
} catch(err) {
|
||||
return {
|
||||
description: "",
|
||||
color: DefaultColor
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// ====================================================== common
|
||||
|
||||
function ccn_api_common_webLogin(_username, _password) {
|
||||
var gotten_data = undefined;
|
||||
$.ajax({
|
||||
url: '/api/common/webLogin',
|
||||
type: "POST",
|
||||
async: false,
|
||||
data: {
|
||||
username: _username,
|
||||
password: _password
|
||||
},
|
||||
success: function (data) {
|
||||
gotten_data = data;
|
||||
}
|
||||
});
|
||||
if (IsResponseOK(gotten_data)) {
|
||||
ccn_localstorageAssist_SetApiToken(gotten_data['data']);
|
||||
return true;
|
||||
} else return false;
|
||||
}
|
||||
|
||||
function ccn_api_common_logout() {
|
||||
// return true or false
|
||||
var gotten_data = undefined;
|
||||
$.ajax({
|
||||
url: '/api/common/logout',
|
||||
type: "POST",
|
||||
async: false,
|
||||
data: {
|
||||
token: ccn_localstorageAssist_GetApiToken()
|
||||
},
|
||||
success: function (data) {
|
||||
gotten_data = data;
|
||||
}
|
||||
});
|
||||
|
||||
if (IsResponseOK(gotten_data) && gotten_data['data']) {
|
||||
ccn_localstorageAssist_SetApiToken('');
|
||||
return true;
|
||||
} return false;
|
||||
}
|
||||
|
||||
function ccn_api_common_tokenValid() {
|
||||
// get from local database first, then judge it via post
|
||||
// return true or false
|
||||
var gotten_token = ccn_localstorageAssist_GetApiToken();
|
||||
if (gotten_token == '') return false;
|
||||
|
||||
var gotten_data = undefined;
|
||||
$.ajax({
|
||||
url: '/api/common/tokenValid',
|
||||
type: "POST",
|
||||
async: false,
|
||||
data: {
|
||||
token: ccn_localstorageAssist_GetApiToken()
|
||||
},
|
||||
success: function (data) {
|
||||
gotten_data = data;
|
||||
}
|
||||
});
|
||||
|
||||
if (IsResponseOK(gotten_data) && gotten_data['data']) return true;
|
||||
else {
|
||||
ccn_localstorageAssist_SetApiToken('');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// ====================================================== calendar
|
||||
|
||||
function ccn_api_calendar_getFull(_startDateTime, _endDateTime) {
|
||||
return ccn_api_dataTemplate(
|
||||
'/api/calendar/getFull',
|
||||
{
|
||||
token: ccn_localstorageAssist_GetApiToken(),
|
||||
startDateTime: _startDateTime,
|
||||
endDateTime: _endDateTime
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function ccn_api_calendar_getDetail(_uuid) {
|
||||
return ccn_api_dataTemplate(
|
||||
'/api/calendar/getDetail',
|
||||
{
|
||||
token: ccn_localstorageAssist_GetApiToken(),
|
||||
uuid: _uuid
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function ccn_api_calendar_update(_uuid, _belongTo, _title, _description, _eventDateTimeStart, _eventDateTimeEnd, _loopRules, _timezoneOffset, _lastChange) {
|
||||
var data = {};
|
||||
if (typeof(_belongTo) != 'undefined')
|
||||
data.belongTo = _belongTo;
|
||||
if (typeof(_title) != 'undefined')
|
||||
data.title = _title;
|
||||
if (typeof(_description) != 'undefined')
|
||||
data.description = _description;
|
||||
if (typeof(_eventDateTimeStart) != 'undefined')
|
||||
data.eventDateTimeStart = _eventDateTimeStart;
|
||||
if (typeof(_eventDateTimeEnd) != 'undefined')
|
||||
data.eventDateTimeEnd = _eventDateTimeEnd;
|
||||
if (typeof(_loopRules) != 'undefined')
|
||||
data.loopRules = _loopRules;
|
||||
if (typeof(_timezoneOffset) != 'undefined')
|
||||
data.timezoneOffset = _timezoneOffset;
|
||||
|
||||
data.token = ccn_localstorageAssist_GetApiToken();
|
||||
data.uuid = _uuid;
|
||||
data.lastChange = _lastChange;
|
||||
return ccn_api_dataTemplate(
|
||||
'/api/calendar/update',
|
||||
data
|
||||
);
|
||||
}
|
||||
|
||||
function ccn_api_calendar_add(_belongTo, _title, _description, _eventDateTimeStart, _eventDateTimeEnd, _loopRules, _timezoneOffset) {
|
||||
return ccn_api_dataTemplate(
|
||||
'/api/calendar/add',
|
||||
{
|
||||
token: ccn_localstorageAssist_GetApiToken(),
|
||||
belongTo: _belongTo,
|
||||
title: _title,
|
||||
description: _description,
|
||||
eventDateTimeStart: _eventDateTimeStart,
|
||||
eventDateTimeEnd: _eventDateTimeEnd,
|
||||
loopRules: _loopRules,
|
||||
timezoneOffset: _timezoneOffset
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function ccn_api_calendar_delete(_uuid, _lastChange) {
|
||||
return ccn_api_boolTemplate(
|
||||
'/api/calendar/delete',
|
||||
{
|
||||
token: ccn_localstorageAssist_GetApiToken(),
|
||||
uuid: _uuid,
|
||||
lastChange: _lastChange
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// ====================================================== collection
|
||||
|
||||
function ccn_api_collection_getFullOwn() {
|
||||
return ccn_api_dataTemplate(
|
||||
'/api/collection/getFullOwn',
|
||||
{
|
||||
token: ccn_localstorageAssist_GetApiToken()
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function ccn_api_collection_getDetailOwn(_uuid) {
|
||||
return ccn_api_dataTemplate(
|
||||
'/api/collection/getDetailOwn',
|
||||
{
|
||||
token: ccn_localstorageAssist_GetApiToken(),
|
||||
uuid: _uuid
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function ccn_api_collection_addOwn(_name) {
|
||||
return ccn_api_dataTemplate(
|
||||
'/api/collection/addOwn',
|
||||
{
|
||||
token: ccn_localstorageAssist_GetApiToken(),
|
||||
name: _name
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function ccn_api_collection_updateOwn(_uuid, _name, _lastChange) {
|
||||
return ccn_api_dataTemplate(
|
||||
'/api/collection/updateOwn',
|
||||
{
|
||||
token: ccn_localstorageAssist_GetApiToken(),
|
||||
uuid: _uuid,
|
||||
name: _name,
|
||||
lastChange: _lastChange
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function ccn_api_collection_deleteOwn(_uuid, _lastChange) {
|
||||
return ccn_api_boolTemplate(
|
||||
'/api/collection/deleteOwn',
|
||||
{
|
||||
token: ccn_localstorageAssist_GetApiToken(),
|
||||
uuid: _uuid,
|
||||
lastChange: _lastChange
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function ccn_api_collection_getSharing(_uuid) {
|
||||
return ccn_api_dataTemplate(
|
||||
'/api/collection/getSharing',
|
||||
{
|
||||
token: ccn_localstorageAssist_GetApiToken(),
|
||||
uuid: _uuid
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function ccn_api_collection_deleteSharing(_uuid, _target, _lastChange) {
|
||||
return ccn_api_dataTemplate(
|
||||
'/api/collection/deleteSharing',
|
||||
{
|
||||
token: ccn_localstorageAssist_GetApiToken(),
|
||||
uuid: _uuid,
|
||||
target: _target,
|
||||
lastChange: _lastChange
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function ccn_api_collection_addSharing(_uuid, _target, _lastChange) {
|
||||
return ccn_api_dataTemplate(
|
||||
'/api/collection/addSharing',
|
||||
{
|
||||
token: ccn_localstorageAssist_GetApiToken(),
|
||||
uuid: _uuid,
|
||||
target: _target,
|
||||
lastChange: _lastChange
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function ccn_api_collection_getShared() {
|
||||
return ccn_api_dataTemplate(
|
||||
'/api/collection/getShared',
|
||||
{
|
||||
token: ccn_localstorageAssist_GetApiToken()
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// ====================================================== todo
|
||||
|
||||
function ccn_api_todo_getFull() {
|
||||
return ccn_api_dataTemplate(
|
||||
'/api/todo/getFull',
|
||||
{
|
||||
token: ccn_localstorageAssist_GetApiToken()
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function ccn_api_todo_add() {
|
||||
return ccn_api_dataTemplate(
|
||||
'/api/todo/add',
|
||||
{
|
||||
token: ccn_localstorageAssist_GetApiToken()
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function ccn_api_todo_update(_uuid, _data, _lastChange) {
|
||||
return ccn_api_dataTemplate(
|
||||
'/api/todo/update',
|
||||
{
|
||||
token: ccn_localstorageAssist_GetApiToken(),
|
||||
uuid: _uuid,
|
||||
data: _data,
|
||||
lastChange: _lastChange
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function ccn_api_todo_delete(_uuid, _lastChange) {
|
||||
return ccn_api_boolTemplate(
|
||||
'/api/todo/delete',
|
||||
{
|
||||
token: ccn_localstorageAssist_GetApiToken(),
|
||||
uuid: _uuid,
|
||||
lastChange: _lastChange
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// ====================================================== admin
|
||||
|
||||
function ccn_api_admin_get() {
|
||||
return ccn_api_dataTemplate(
|
||||
'/api/admin/get',
|
||||
{
|
||||
token: ccn_localstorageAssist_GetApiToken()
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function ccn_api_admin_add(_username) {
|
||||
return ccn_api_dataTemplate(
|
||||
'/api/admin/add',
|
||||
{
|
||||
token: ccn_localstorageAssist_GetApiToken(),
|
||||
username: _username
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function ccn_api_admin_update(_username, _password, _isAdmin) {
|
||||
var data = {};
|
||||
if (typeof(_password) != 'undefined')
|
||||
data.password = _password;
|
||||
if (typeof(_isAdmin) != 'undefined')
|
||||
data.isAdmin = _isAdmin;
|
||||
|
||||
if (Object.getOwnPropertyNames(data).length == 0) return false;
|
||||
data.token = ccn_localstorageAssist_GetApiToken();
|
||||
data.username = _username;
|
||||
return ccn_api_boolTemplate(
|
||||
'/api/admin/update',
|
||||
data
|
||||
);
|
||||
}
|
||||
|
||||
function ccn_api_admin_delete(_username) {
|
||||
return ccn_api_boolTemplate(
|
||||
'/api/admin/delete',
|
||||
{
|
||||
token: ccn_localstorageAssist_GetApiToken(),
|
||||
username: _username
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// ====================================================== profile
|
||||
|
||||
function ccn_api_profile_isAdmin() {
|
||||
return ccn_api_boolTemplate(
|
||||
'/api/profile/isAdmin',
|
||||
{
|
||||
token: ccn_localstorageAssist_GetApiToken()
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function ccn_api_profile_changePassword(_password) {
|
||||
return ccn_api_boolTemplate(
|
||||
'/api/profile/changePassword',
|
||||
{
|
||||
token: ccn_localstorageAssist_GetApiToken(),
|
||||
password: _password
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function ccn_api_profile_getToken() {
|
||||
return ccn_api_boolTemplate(
|
||||
'/api/profile/getToken',
|
||||
{
|
||||
token: ccn_localstorageAssist_GetApiToken()
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function ccn_api_profile_deleteToken(_deleteToken) {
|
||||
return ccn_api_boolTemplate(
|
||||
'/api/profile/deleteToken',
|
||||
{
|
||||
token: ccn_localstorageAssist_GetApiToken(),
|
||||
deleteToken: _deleteToken
|
||||
}
|
||||
);
|
||||
}
|
||||
441
frontend/static/js/datetime.js
Normal file
441
frontend/static/js/datetime.js
Normal file
@@ -0,0 +1,441 @@
|
||||
// NOTE: this file is sync with dt.py. if this file or dt.py have bugs, all code should be changed
|
||||
var ccn_datetime_monthDayCount = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
|
||||
|
||||
var ccn_datetime_MIN_YEAR = 1950;
|
||||
var ccn_datetime_MAX_YEAR = 2200;
|
||||
var ccn_datetime_MIN_DATETIME = new Date(Date.UTC(ccn_datetime_MIN_YEAR, 0, 1, 0, 0, 0, 0));
|
||||
var ccn_datetime_MAX_DATETIME = new Date(Date.UTC(ccn_datetime_MAX_YEAR, 0, 1, 0, 0, 0, 0));
|
||||
var ccn_datetime_MIN_TIMESTAMP = Math.floor(ccn_datetime_MIN_DATETIME.getTime() / 60000);
|
||||
var ccn_datetime_MAX_TIMESTAMP = Math.floor(ccn_datetime_MAX_DATETIME.getTime() / 60000);
|
||||
|
||||
var ccn_datetime_DAY1_SPAN = 60 * 24;
|
||||
var ccn_datetime_DAY7_SPAN = 7 * ccn_datetime_DAY1_SPAN;
|
||||
|
||||
var ccn_datetime_precompiledLoopRules = {
|
||||
year: new RegExp(/^Y([SR]{1})([1-9]\d*)$/),
|
||||
month: new RegExp(/^M([SR]{1})([ABCD]{1})([1-9]\d*)$/),
|
||||
week: new RegExp(/^W([TF]{7})([1-9]\d*)$/),
|
||||
day: new RegExp(/^D([1-9]\d*)$/)
|
||||
};
|
||||
|
||||
var ccn_datetime_precompiledLoopStopRules = {
|
||||
infinity: new RegExp(/^F$/),
|
||||
datetime: new RegExp(/^D([1-9]\d*|0)$/),
|
||||
times: new RegExp(/^T([1-9]\d*)$/)
|
||||
}
|
||||
|
||||
/*
|
||||
return format
|
||||
[loopRules, loopStopRules] or undefined(invalid or no loop)
|
||||
|
||||
loopRules:
|
||||
year loop: [0, isStrict, yearSpan]
|
||||
month loop: [1, isStrict, monthMode, monthSpan]
|
||||
week loop: [2, 7 bool item..., weekSpan]
|
||||
day loop: [3, daySpan]
|
||||
|
||||
loopStopRules:
|
||||
infinity: [0]
|
||||
datetime: [1, timestamp]
|
||||
times: [2, times]
|
||||
*/
|
||||
function ccn_datetime_ResolveLoopRules4UI(strl) {
|
||||
if (strl == '') return undefined;
|
||||
|
||||
var sp = strl.split('-');
|
||||
if (sp.length != 2) return undefined;
|
||||
var loopRules = undefined;
|
||||
var loopStopRules = undefined;
|
||||
|
||||
if (ccn_datetime_precompiledLoopRules.year.test(sp[0])) {
|
||||
loopRules = [0, RegExp.$1 == 'S', parseInt(RegExp.$2)];
|
||||
} else if (ccn_datetime_precompiledLoopRules.month.test(sp[0])) {
|
||||
loopRules = [1, RegExp.$1 == 'S', RegExp.$2, parseInt(RegExp.$3)];
|
||||
} else if (ccn_datetime_precompiledLoopRules.week.test(sp[0])) {
|
||||
loopRules = [2];
|
||||
for (var i = 0; i < 7; i++)
|
||||
loopRules.push(RegExp.$1[i] == 'T');
|
||||
loopRules.push(parseInt(RegExp.$2));
|
||||
} else if (ccn_datetime_precompiledLoopRules.day.test(sp[0])) {
|
||||
loopRules = [3, parseInt(RegExp.$1)];
|
||||
} else return undefined;
|
||||
|
||||
|
||||
if (ccn_datetime_precompiledLoopStopRules.infinity.test(sp[1])) {
|
||||
loopStopRules = [0];
|
||||
} else if (ccn_datetime_precompiledLoopStopRules.datetime.test(sp[1])) {
|
||||
loopStopRules = [1, parseInt(RegExp.$1)];
|
||||
} else if (ccn_datetime_precompiledLoopStopRules.times.test(sp[1])) {
|
||||
loopStopRules = [2, parseInt(RegExp.$1)];
|
||||
} else return undefined;
|
||||
|
||||
return [loopRules, loopStopRules];
|
||||
}
|
||||
|
||||
// loopDateTimeStart's value is not correspond with database.
|
||||
// it is calculated by program, should be pointed to the closing
|
||||
// protential event start datetime.
|
||||
// also loopDateTimeEnd, it was clamped with the tail of legal event
|
||||
// clampStartDateTime is real clamp datetime of event start datetime.
|
||||
// loopDateTimeStart is the start datetime for detect.
|
||||
// in this section, all time should be analysed with Date((time + timezoneOffset) * 60000)
|
||||
// and use .getUTC...() functions.
|
||||
function ccn_datetime_ResolveLoopRules4Event(loopRules, loopDateTimeStart, loopDateTimeEnd, eventDateTimeStart, eventDateTimeEnd, timezoneOffset, clampStartDateTime) {
|
||||
if (loopRules == '') return [
|
||||
[Math.max(eventDateTimeStart, clampStartDateTime),
|
||||
Math.max(loopDateTimeEnd, eventDateTimeEnd)]
|
||||
];
|
||||
|
||||
var sp = loopRules.split('-');
|
||||
if (sp.length != 2) return undefined;
|
||||
var loopRules = sp[0]; // we don't need consider stop flag
|
||||
var result = new Array();
|
||||
|
||||
// compute offset and duration
|
||||
var eventDateTime = new Date((eventDateTimeStart + timezoneOffset) * 60000);
|
||||
eventDateTime.setUTCHours(0, 0, 0, 0);
|
||||
var eventOffset = eventDateTimeStart - (Math.floor(eventDateTime.getTime() / 60000) - timezoneOffset);
|
||||
var eventDuration = eventDateTimeEnd - eventDateTimeStart;
|
||||
|
||||
var detectDateTime = new Date(loopDateTimeStart * 60000);
|
||||
detectDateTime.setUTCHours(0, 0, 0, 0);
|
||||
var originalYear = eventDateTime.getUTCFullYear();
|
||||
var originalMonth = eventDateTime.getUTCMonth() + 1;
|
||||
var originalDay = eventDateTime.getUTCDate();
|
||||
|
||||
// compute event
|
||||
if (ccn_datetime_precompiledLoopRules.year.test(loopRules)) {
|
||||
var isStrict = RegExp.$1 == 'S';
|
||||
var loopSpan = parseInt(RegExp.$2);
|
||||
|
||||
var yearCount = detectDateTime.getFullYear() - originalYear;
|
||||
var isSpecial = (originalMonth == 2 && originalDay == 29);
|
||||
var realLoopSpan = (isSpecial && isStrict) ? LCM(4, loopSpan) : loopSpan;
|
||||
|
||||
//var fullSpanCount = Math.floor(yearCount / realLoopSpan);
|
||||
var remainYear = yearCount % realLoopSpan;
|
||||
//detectDateTime.setUTCFullYear(fullSpanCount + detectDateTime.getUTCFullYear(), 1, 1);
|
||||
if (remainYear != 0)
|
||||
detectDateTime.setUTCFullYear(realLoopSpan - remainYear + detectDateTime.getUTCFullYear(), 1 - 1, 1);
|
||||
|
||||
var skipFlag = false;
|
||||
while(Math.floor(detectDateTime.getTime() / 60000) + eventOffset - timezoneOffset <= loopDateTimeEnd) {
|
||||
skipFlag = false;
|
||||
if (isSpecial) {
|
||||
// is special day, 29 Feb
|
||||
// try set it in 29 Feb
|
||||
if (isStrict) {
|
||||
if (ccn_datetime_IsLeapYear(detectDateTime.getUTCFullYear())) detectDateTime.setUTCMonth(2 - 1, 29);
|
||||
else skipFlag = true; // order skip
|
||||
} else {
|
||||
if (ccn_datetime_IsLeapYear(detectDateTime.getUTCFullYear())) detectDateTime.setUTCMonth(2 - 1, 29);
|
||||
else detectDateTime.setUTCMonth(2 - 1, 28);
|
||||
}
|
||||
} else detectDateTime.setUTCMonth(originalMonth - 1, originalDay);
|
||||
|
||||
if (!skipFlag) {
|
||||
result.push(
|
||||
[Math.floor(detectDateTime.getTime() / 60000) + eventOffset - timezoneOffset,
|
||||
Math.floor(detectDateTime.getTime() / 60000) + eventOffset + eventDuration - timezoneOffset]
|
||||
);
|
||||
}
|
||||
|
||||
detectDateTime.setUTCFullYear(realLoopSpan + detectDateTime.getUTCFullYear());
|
||||
}
|
||||
|
||||
} else if (ccn_datetime_precompiledLoopRules.month.test(loopRules)) {
|
||||
var isStrict = RegExp.$1 == 'S';
|
||||
var loopMethod = RegExp.$2;
|
||||
var loopSpan = parseInt(RegExp.$3);
|
||||
|
||||
var monthsCount = ccn_datetime_MonthsCount(detectDateTime.getUTCFullYear(), detectDateTime.getUTCMonth() + 1) -
|
||||
ccn_datetime_MonthsCount(originalYear, originalMonth);
|
||||
|
||||
//var fullSpanCount = Math.floor(monthsCount / loopSpan);
|
||||
var remainMonth = monthsCount % loopSpan;
|
||||
//detectDateTime.setUTCMonth(fullSpanCount * loopSpan + detectDateTime.getUTCMonth(), 1);
|
||||
detectDateTime.setUTCDate(1);
|
||||
if (remainMonth != 0)
|
||||
detectDateTime.setUTCMonth(loopSpan - remainMonth + detectDateTime.getUTCMonth(), 1);
|
||||
|
||||
while(Math.floor(detectDateTime.getTime() / 60000) + eventOffset - timezoneOffset <= loopDateTimeEnd) {
|
||||
var data = ccn_datetime_GetRemanagedDayInMonth(originalYear, originalMonth, originalDay, detectDateTime.getUTCFullYear(), detectDateTime.getUTCMonth() + 1, isStrict);
|
||||
var predictedDay = undefined;
|
||||
switch(loopMethod) {
|
||||
case 'A':
|
||||
if (typeof(data[0]) != 'undefined') predictedDay = data[0];
|
||||
break;
|
||||
case 'B':
|
||||
if (typeof(data[1]) != 'undefined') predictedDay = data[1];
|
||||
break;
|
||||
case 'C':
|
||||
if (typeof(data[2]) != 'undefined') predictedDay = data[2];
|
||||
break;
|
||||
case 'D':
|
||||
if (typeof(data[3]) != 'undefined') predictedDay = data[3];
|
||||
break;
|
||||
}
|
||||
if (typeof(predictedDay) != 'undefined') {
|
||||
detectDateTime.setUTCDate(predictedDay);
|
||||
result.push(
|
||||
[Math.floor(detectDateTime.getTime() / 60000) + eventOffset - timezoneOffset,
|
||||
Math.floor(detectDateTime.getTime() / 60000) + eventOffset + eventDuration - timezoneOffset]
|
||||
);
|
||||
}
|
||||
|
||||
detectDateTime.setUTCMonth(loopSpan + detectDateTime.getUTCMonth(), 1);
|
||||
}
|
||||
|
||||
|
||||
} else if (ccn_datetime_precompiledLoopRules.week.test(loopRules)) {
|
||||
var loopSpan = parseInt(RegExp.$2);
|
||||
var weekOption = [];
|
||||
var weekEventCount = 0
|
||||
for (var i = 0; i < 7; i++) {
|
||||
weekOption.push(RegExp.$1[i] == 'T');
|
||||
if (RegExp.$1[i] == 'T') weekEventCount++;
|
||||
}
|
||||
|
||||
var originalWeek = ccn_datetime_DayOfWeek(originalYear, originalMonth, originalDay);
|
||||
|
||||
// try insert original event
|
||||
if (!weekOption[originalWeek]) {
|
||||
result.push(
|
||||
[eventDateTimeStart, eventDateTimeEnd]
|
||||
);
|
||||
}
|
||||
|
||||
var daysCount = ccn_datetime_DaysCount(detectDateTime.getUTCFullYear(), detectDateTime.getUTCMonth() + 1, detectDateTime.getDate()) -
|
||||
ccn_datetime_DaysCount(originalYear, originalMonth, originalDay);
|
||||
//var fullSpanCount = Math.floor(daysCount / (7 * loopSpan));
|
||||
var remainFullSpanCount = Math.floor((daysCount % (7 * loopSpan)) / 7);
|
||||
var remainDays = (daysCount % (7 * loopSpan)) % 7;
|
||||
|
||||
//detectDateTime.setUTCDate((7 * loopSpan * fullSpanCount) + detectDateTime.getUTCDate());
|
||||
if (remainFullSpanCount != 0) {
|
||||
detectDateTime.setUTCDate((loopSpan - remainFullSpanCount) * 7 + detectDateTime.getUTCDate());
|
||||
}
|
||||
var weekCounter = remainDays;
|
||||
|
||||
while(Math.floor(detectDateTime.getTime() / 60000) + eventOffset - timezoneOffset <= loopDateTimeEnd) {
|
||||
if (weekOption[(weekCounter + originalWeek) % 7])
|
||||
result.push(
|
||||
[Math.floor(detectDateTime.getTime() / 60000) + eventOffset - timezoneOffset,
|
||||
Math.floor(detectDateTime.getTime() / 60000) + eventOffset + eventDuration - timezoneOffset]
|
||||
);
|
||||
|
||||
weekCounter = (weekCounter + 1) % 7;
|
||||
detectDateTime.setUTCDate(detectDateTime.getUTCDate() + 1);
|
||||
if (weekCounter == 0)
|
||||
detectDateTime.setUTCDate(detectDateTime.getUTCDate() + (loopSpan - 1) * 7);
|
||||
}
|
||||
|
||||
} else if (ccn_datetime_precompiledLoopRules.day.test(loopRules)) {
|
||||
var loopSpan = parseInt(RegExp.$1);
|
||||
|
||||
var daysCount = ccn_datetime_DaysCount(detectDateTime.getUTCFullYear(), detectDateTime.getUTCMonth() + 1, detectDateTime.getUTCDate()) -
|
||||
ccn_datetime_DaysCount(originalYear, originalMonth, originalDay);
|
||||
//var fullSpanCount = Math.floor(daysCount / loopSpan);
|
||||
var remainDays = daysCount % loopSpan;
|
||||
//detectDateTime.setUTCDate(fullSpanCount * loopSpan + detectDateTime.getUTCDate());
|
||||
if (remainDays != 0)
|
||||
detectDateTime.setUTCDate(loopSpan - remainDays + detectDateTime.getUTCDate());
|
||||
|
||||
while(Math.floor(detectDateTime.getTime() / 60000) + eventOffset - timezoneOffset <= loopDateTimeEnd) {
|
||||
result.push(
|
||||
[Math.floor(detectDateTime.getTime() / 60000) + eventOffset - timezoneOffset,
|
||||
Math.floor(detectDateTime.getTime() / 60000) + eventOffset + eventDuration - timezoneOffset]
|
||||
);
|
||||
detectDateTime.setUTCDate(detectDateTime.getUTCDate() + loopSpan);
|
||||
}
|
||||
} else return undefined;
|
||||
|
||||
// clamp item
|
||||
var realResult = [];
|
||||
for (var i in result) {
|
||||
var start = result[i][0];
|
||||
var end = result[i][1];
|
||||
if (end > clampStartDateTime && start <= loopDateTimeEnd)
|
||||
realResult.push([Math.max(start, clampStartDateTime), Math.min(end, loopDateTimeEnd)]);
|
||||
}
|
||||
return realResult;
|
||||
}
|
||||
|
||||
function ccn_datetime_ResolveLoopRules4Text(strl, startDateTime, timezoneOffset) {
|
||||
if (strl == '') return "";
|
||||
|
||||
var sp = strl.split('-');
|
||||
if (sp.length != 2) return "";
|
||||
var loopRules = undefined;
|
||||
var loopStopRules = undefined;
|
||||
var datetimeInstance = new Date((startDateTime + timezoneOffset) * 60000)
|
||||
|
||||
if (ccn_datetime_precompiledLoopRules.year.test(sp[0])) {
|
||||
if (RegExp.$1 == 'S')
|
||||
loopRules = $.i18n.prop('ccn-i18n-datetime-loopRuleText-modeStrict');
|
||||
else
|
||||
loopRules = $.i18n.prop('ccn-i18n-datetime-loopRuleText-modeRough');
|
||||
loopRules += $.i18n.prop('ccn-i18n-datetime-loopRuleText-year')
|
||||
.format(parseInt(RegExp.$2), datetimeInstance.toLocaleDateString(undefined, {timeZone: "UTC"}));
|
||||
} else if (ccn_datetime_precompiledLoopRules.month.test(sp[0])) {
|
||||
if (RegExp.$1 == 'S')
|
||||
loopRules = $.i18n.prop('ccn-i18n-datetime-loopRuleText-modeStrict');
|
||||
else
|
||||
loopRules = $.i18n.prop('ccn-i18n-datetime-loopRuleText-modeRough');
|
||||
|
||||
var dayInMonth = ccn_datetime_GetDayInMonth(
|
||||
datetimeInstance.getUTCFullYear(),
|
||||
datetimeInstance.getUTCMonth() + 1,
|
||||
datetimeInstance.getUTCDate());
|
||||
switch(RegExp.$2) {
|
||||
case 'A':
|
||||
loopRules = $.i18n.prop('ccn-i18n-datetime-loopRuleText-monthA')
|
||||
.format(parseInt(RegExp.$3), dayInMonth[0]);
|
||||
break;
|
||||
case 'B':
|
||||
loopRules = $.i18n.prop('ccn-i18n-datetime-loopRuleText-monthB')
|
||||
.format(parseInt(RegExp.$3), dayInMonth[1]);
|
||||
break;
|
||||
case 'C':
|
||||
loopRules = $.i18n.prop('ccn-i18n-datetime-loopRuleText-monthC')
|
||||
.format(parseInt(RegExp.$3), dayInMonth[2], dayInMonth[3]);
|
||||
break;
|
||||
case 'D':
|
||||
loopRules = $.i18n.prop('ccn-i18n-datetime-loopRuleText-monthD')
|
||||
.format(parseInt(RegExp.$3), dayInMonth[4], dayInMonth[5]);
|
||||
break;
|
||||
}
|
||||
} else if (ccn_datetime_precompiledLoopRules.week.test(sp[0])) {
|
||||
var weekOfDayCache = [];
|
||||
for (var i = 0; i < 7; i++) {
|
||||
if (RegExp.$1[i] == 'T')
|
||||
weekOfDayCache.push(ccn_i18n_UniversalGetDayOfWeek(i));
|
||||
}
|
||||
|
||||
loopRules = $.i18n.prop('ccn-i18n-datetime-loopRuleText-week')
|
||||
.format(parseInt(RegExp.$2), weekOfDayCache.join(', '));
|
||||
} else if (ccn_datetime_precompiledLoopRules.day.test(sp[0])) {
|
||||
loopRules = $.i18n.prop('ccn-i18n-datetime-loopRuleText-day')
|
||||
.format(parseInt(RegExp.$1));
|
||||
} else return "";
|
||||
|
||||
|
||||
if (ccn_datetime_precompiledLoopStopRules.infinity.test(sp[1])) {
|
||||
loopStopRules = $.i18n.prop('ccn-i18n-datetime-loopStopRuleText-infinity');
|
||||
} else if (ccn_datetime_precompiledLoopStopRules.datetime.test(sp[1])) {
|
||||
loopStopRules = $.i18n.prop('ccn-i18n-datetime-loopStopRuleText-datetime')
|
||||
.format(new Date(parseInt(RegExp.$1)).toLocaleDateString());
|
||||
} else if (ccn_datetime_precompiledLoopStopRules.times.test(sp[1])) {
|
||||
loopStopRules = $.i18n.prop('ccn-i18n-datetime-loopStopRuleText-times')
|
||||
.format(parseInt(RegExp.$1));
|
||||
} else return "";
|
||||
|
||||
return (loopRules + loopStopRules);
|
||||
}
|
||||
|
||||
function ccn_datetime_LeapYearCountEx(endYear, includeThis, baseYear, includeBase) {
|
||||
if (!includeThis) endYear--;
|
||||
if (includeBase) baseYear--;
|
||||
|
||||
var endly = Math.floor(endYear / 4);
|
||||
endly -= Math.floor(endYear / 100);
|
||||
endly += Math.floor(endYear / 400);
|
||||
|
||||
var basely = Math.floor(baseYear / 4);
|
||||
basely -= Math.floor(baseYear / 100);
|
||||
basely += Math.floor(baseYear / 400);
|
||||
|
||||
return (endly - basely);
|
||||
}
|
||||
|
||||
function ccn_datetime_DaysCount(year, month, day) {
|
||||
var ly = ccn_datetime_LeapYearCountEx(year, false, 1, true);
|
||||
var days = 365 * (year - 1);
|
||||
days += ly;
|
||||
|
||||
for(var index = 1; index < month; index++)
|
||||
days += ccn_datetime_monthDayCount[index - 1];
|
||||
|
||||
if (month > 2 && ccn_datetime_IsLeapYear(year))
|
||||
days += 1;
|
||||
|
||||
days += day - 1;
|
||||
return days;
|
||||
}
|
||||
|
||||
function ccn_datetime_MonthsCount(year, month) {
|
||||
return (year - 1) * 12 + (month - 1);
|
||||
}
|
||||
|
||||
function ccn_datetime_DayOfWeek(year, month, day) {
|
||||
return ccn_datetime_DaysCount(year, month, day) % 7;
|
||||
}
|
||||
|
||||
function ccn_datetime_GetDayInMonth(year, month, day) {
|
||||
var days = ccn_datetime_monthDayCount[month - 1] + ((month == 2 && ccn_datetime_IsLeapYear(year)) ? 1 : 0);
|
||||
var firstDayOfWeek = ccn_datetime_DayOfWeek(year, month, 1);
|
||||
var dayOfWeek = (firstDayOfWeek + day - 1) % 7;
|
||||
|
||||
var dayForwards = day;
|
||||
var dayBackwards = days - day + 1;
|
||||
|
||||
var weeksForward = Math.floor((dayForwards - 1) / 7) + 1;
|
||||
var weeksBackwards = Math.floor((dayBackwards - 1) / 7) + 1;
|
||||
|
||||
return [dayForwards, dayBackwards, weeksForward, dayOfWeek, weeksBackwards, dayOfWeek];
|
||||
}
|
||||
|
||||
function ccn_datetime_GetRemanagedDayInMonth(oldYear, oldMonth, oldDay, newYear, newMonth, isStrict) {
|
||||
var ddata = ccn_datetime_GetDayInMonth(oldYear, oldMonth, oldDay);
|
||||
var mdata = ccn_datetime_GetMonthWeekStatistics(newYear, newMonth);
|
||||
var days = ccn_datetime_monthDayCount[newMonth - 1] + ((newMonth == 2 && ccn_datetime_IsLeapYear(year)) ? 1 : 0);
|
||||
var firstDayOfWeek = ccn_datetime_DayOfWeek(newYear, newMonth, 1);
|
||||
//var lastDayOfWeek = (firstDayOfWeek + days - 1) % 7;
|
||||
|
||||
if (isStrict) {
|
||||
var methodA = ddata[0] > days ? undefined : ddata[0];
|
||||
var methodB = ddata[1] > days ? undefined : (days - ddata[1] + 1);
|
||||
} else {
|
||||
var methodA = Math.min(ddata[0], days);
|
||||
var methodB = days - Math.min(ddata[1], days) + 1;
|
||||
}
|
||||
|
||||
var methodC = undefined;
|
||||
if (ddata[2] <= mdata[ddata[3]] || !isStrict) {
|
||||
var targetWeek = Math.min(ddata[2], mdata[ddata[3]]);
|
||||
methodC = 1 + (targetWeek - 1) * 7 + ((ddata[3] + 7 - firstDayOfWeek) % 7);
|
||||
}
|
||||
|
||||
var methodD = undefined;
|
||||
if (ddata[4] <= mdata[ddata[5]] || !isStrict) {
|
||||
// convert to type c and calc
|
||||
var targetWeek = mdata[ddata[5]] - Math.min(ddata[4], mdata[ddata[5]]) + 1;
|
||||
methodD = 1 + (targetWeek - 1) * 7 + ((ddata[5] + 7 - firstDayOfWeek) % 7);
|
||||
}
|
||||
|
||||
return [methodA, methodB, methodC, methodD];
|
||||
}
|
||||
|
||||
function ccn_datetime_GetMonthWeekStatistics(year, month) {
|
||||
var days = ccn_datetime_monthDayCount[month - 1] + ((month == 2 && ccn_datetime_IsLeapYear(year)) ? 1 : 0);
|
||||
var firstDayOfWeek = ccn_datetime_DayOfWeek(year, month, 1);
|
||||
|
||||
var result = [4, 4, 4, 4, 4, 4, 4];
|
||||
var remain = days % 7;
|
||||
var week = firstDayOfWeek;
|
||||
while (remain > 0) {
|
||||
result[week % 7] += 1;
|
||||
week++;
|
||||
remain--;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function ccn_datetime_IsLeapYear(year) {
|
||||
var isLeap = false;
|
||||
if (year % 4 == 0) isLeap = true;
|
||||
if (year % 100 == 0) isLeap = false;
|
||||
if (year % 400 == 0) isLeap = true;
|
||||
return isLeap;
|
||||
}
|
||||
522
frontend/static/js/datetimepicker.js
Normal file
522
frontend/static/js/datetimepicker.js
Normal file
@@ -0,0 +1,522 @@
|
||||
var ccn_datetimepicker_tabType = {
|
||||
year: 0,
|
||||
month: 1,
|
||||
day: 2,
|
||||
hour: 3,
|
||||
minute: 4
|
||||
};
|
||||
|
||||
var ccn_datetimepicker_dialPlateWidth = 200;
|
||||
var ccn_datetimepicker_dialPlateRadius = ccn_datetimepicker_dialPlateWidth / 2;
|
||||
var ccn_datetimepicker_dialPlateHourInnerPercent = 0.6;
|
||||
var ccn_datetimepicker_dialPlateHourOutterPercent = 0.8;
|
||||
var ccn_datetimepicker_dialPlateHourDistinguishPercent = 0.7;
|
||||
var ccn_datetimepicker_dialPlateMinutePercent = 0.8;
|
||||
var ccn_datetimepicker_dialPlateHourResolution = Math.PI * 2 / 12;
|
||||
var ccn_datetimepicker_dialPlateMinuteResolution = Math.PI * 2 / 60;
|
||||
|
||||
var ccn_datetimepicker_mode = undefined;
|
||||
var ccn_datetimepicker_isUTC = undefined;
|
||||
var ccn_datetimepicker_pickerIndex = undefined;
|
||||
|
||||
var ccn_datetimepicker_enableMinuteDrag = false;
|
||||
var ccn_datetimepicker_enableHourDrag = false;
|
||||
|
||||
var ccn_datetimepicker_internalDateTime = new Date();
|
||||
var ccn_datetimepicker_displayCacheDateTime = new Date();
|
||||
|
||||
// ========================================= export func
|
||||
|
||||
function ccn_datetimepicker_Insert() {
|
||||
$('body').append(ccn_template_datetimepicker.render());
|
||||
|
||||
// bind size event and trigge once
|
||||
$(window).resize(ccn_datetimepicker_RefreshSvg).resize();
|
||||
|
||||
// add data attr
|
||||
for(var i = 0; i < 3; i++) {
|
||||
for(var j = 0; j < 4; j++) {
|
||||
$('#ccn-datetimepiacker-panelMonth-table > div:nth-child({0}) > div:nth-child({1})'.format(i + 1, j + 1))
|
||||
.attr('data', i * 4 + j);
|
||||
}
|
||||
}
|
||||
|
||||
// bind header event
|
||||
$('header.pickerHeader > div').click(function() {
|
||||
ccn_datetimepicker_SwitchTab(ccn_datetimepicker_Str2TabType($(this).attr('type')));
|
||||
});
|
||||
|
||||
// bind button event
|
||||
$('#ccn-datetimepiacker-panelYear-prevBtn').click(function() {
|
||||
ccn_datetimepicker_PrevNextYear(true);
|
||||
});
|
||||
$('#ccn-datetimepiacker-panelYear-nextBtn').click(function() {
|
||||
ccn_datetimepicker_PrevNextYear(false);
|
||||
});
|
||||
$('#ccn-datetimepiacker-panelMonth-prevBtn').click(function() {
|
||||
ccn_datetimepicker_PrevNextMonth(true);
|
||||
});
|
||||
$('#ccn-datetimepiacker-panelMonth-nextBtn').click(function() {
|
||||
ccn_datetimepicker_PrevNextMonth(false);
|
||||
});
|
||||
$('#ccn-datetimepiacker-panelDay-prevBtn').click(function() {
|
||||
ccn_datetimepicker_PrevNextDay(true);
|
||||
});
|
||||
$('#ccn-datetimepiacker-panelDay-nextBtn').click(function() {
|
||||
ccn_datetimepicker_PrevNextDay(false);
|
||||
});
|
||||
|
||||
$('#ccn-datetimepiacker-panelYear-table > div > div').click(ccn_datetimepicker_ClickYear);
|
||||
$('#ccn-datetimepiacker-panelMonth-table > div > div').click(ccn_datetimepicker_ClickMonth);
|
||||
$('#ccn-datetimepiacker-panelDay-table > div:nth-child(n+1) > div').click(ccn_datetimepicker_ClickDay);
|
||||
|
||||
$('#ccn-datetimepicker-panelHour')
|
||||
.mousedown(ccn_datetimepicker_StartDragHour)
|
||||
.mousemove(ccn_datetimepicker_DraggingHour)
|
||||
.mouseup(ccn_datetimepicker_StopDragHour)
|
||||
.on('touchstart', ccn_datetimepicker_StartDragHour)
|
||||
.on('touchmove', ccn_datetimepicker_DraggingHour)
|
||||
.on('touchend', ccn_datetimepicker_StopDragHour);
|
||||
|
||||
$('#ccn-datetimepicker-panelMinute')
|
||||
.mousedown(ccn_datetimepicker_StartDragMinute)
|
||||
.mousemove(ccn_datetimepicker_DraggingMinute)
|
||||
.mouseup(ccn_datetimepicker_StopDragMinute)
|
||||
.on('touchstart', ccn_datetimepicker_StartDragMinute)
|
||||
.on('touchmove', ccn_datetimepicker_DraggingMinute)
|
||||
.on('touchend', ccn_datetimepicker_StopDragMinute);
|
||||
|
||||
$('#ccn-datetimepicker-btnConfirm').click(ccn_datetimepicker_Confirm);
|
||||
$('#ccn-datetimepicker-btnCancel').click(ccn_datetimepicker_Cancel);
|
||||
|
||||
}
|
||||
|
||||
function ccn_datetimepicker_Modal(mode, pickerIndex, isUTC) {
|
||||
ccn_datetimepicker_mode = mode;
|
||||
ccn_datetimepicker_isUTC = isUTC;
|
||||
ccn_datetimepicker_pickerIndex = pickerIndex;
|
||||
|
||||
ccn_datetimepicker_internalDateTime = ccn_datetimepicker_Get(pickerIndex, false);
|
||||
|
||||
$('header.pickerHeader > div').hide();
|
||||
switch(mode) {
|
||||
case ccn_datetimepicker_tabType.minute:
|
||||
$('header.pickerHeader > div[type=minute]').show();
|
||||
case ccn_datetimepicker_tabType.hour:
|
||||
$('header.pickerHeader > div[type=hour]').show();
|
||||
case ccn_datetimepicker_tabType.day:
|
||||
$('header.pickerHeader > div[type=day]').show();
|
||||
case ccn_datetimepicker_tabType.month:
|
||||
$('header.pickerHeader > div[type=month]').show();
|
||||
case ccn_datetimepicker_tabType.year:
|
||||
$('header.pickerHeader > div[type=year]').show();
|
||||
break;
|
||||
}
|
||||
|
||||
$('#ccn-datetimepicker-modal').addClass('is-active');
|
||||
ccn_datetimepicker_SwitchTab(mode); // this call is set in there by design. if you don't show the dialog, the call of svg resize will fail.
|
||||
}
|
||||
|
||||
function ccn_datetimepicker_Confirm() {
|
||||
// update and call callback func
|
||||
ccn_datetimepicker_Set(
|
||||
ccn_datetimepicker_pickerIndex,
|
||||
ccn_datetimepicker_internalDateTime,
|
||||
ccn_datetimepicker_isUTC,
|
||||
ccn_datetimepicker_mode
|
||||
);
|
||||
|
||||
$('#ccn-datetimepicker-modal').removeClass('is-active');
|
||||
}
|
||||
|
||||
function ccn_datetimepicker_Cancel() {
|
||||
$('#ccn-datetimepicker-modal').removeClass('is-active');
|
||||
}
|
||||
|
||||
// ========================================= internal func
|
||||
|
||||
function ccn_datetimepicker_OnSvgResize(ele) {
|
||||
var scale = 200 / Math.min(ele.width(), ele.height());
|
||||
ele.css('font-size', scale + 'em');
|
||||
}
|
||||
|
||||
function ccn_datetimepicker_SwitchTab(newTab) {
|
||||
$('div.pickerContainer > *').hide();
|
||||
|
||||
ccn_datetimepicker_displayCacheDateTime.setTime(ccn_datetimepicker_internalDateTime.getTime());
|
||||
ccn_datetimepicker_RefreshDisplay(newTab);
|
||||
|
||||
switch(newTab) {
|
||||
case ccn_datetimepicker_tabType.year:
|
||||
$('#ccn-datetimepicker-panelYear').show();
|
||||
break;
|
||||
case ccn_datetimepicker_tabType.month:
|
||||
$('#ccn-datetimepicker-panelMonth').show();
|
||||
break;
|
||||
case ccn_datetimepicker_tabType.day:
|
||||
$('#ccn-datetimepicker-panelDay').show();
|
||||
break;
|
||||
case ccn_datetimepicker_tabType.hour:
|
||||
$('#ccn-datetimepicker-panelHour').show();
|
||||
ccn_datetimepicker_RefreshSvg(); // immediately trigger once svg resize
|
||||
break;
|
||||
case ccn_datetimepicker_tabType.minute:
|
||||
$('#ccn-datetimepicker-panelMinute').show();
|
||||
ccn_datetimepicker_RefreshSvg(); // immediately trigger once svg resize
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function ccn_datetimepicker_RefreshDisplay(tab) {
|
||||
// header should be refreshed entirely
|
||||
$('#ccn-datetimepicker-datetime-year').text(ccn_datetimepicker_internalDateTime.getFullYear());
|
||||
$('#ccn-datetimepicker-datetime-month').text(ccn_datetimepicker_internalDateTime.getMonth() + 1);
|
||||
$('#ccn-datetimepicker-datetime-day').text(ccn_datetimepicker_internalDateTime.getDate());
|
||||
$('#ccn-datetimepicker-datetime-hour').text(ccn_datetimepicker_internalDateTime.getHours());
|
||||
$('#ccn-datetimepicker-datetime-minute').text(ccn_datetimepicker_internalDateTime.getMinutes());
|
||||
|
||||
// refresh tab according to specific `tab`
|
||||
switch(tab) {
|
||||
case ccn_datetimepicker_tabType.year:
|
||||
var startYear = Math.floor((ccn_datetimepicker_displayCacheDateTime.getFullYear() - ccn_datetime_MIN_YEAR) / 12) * 12 + ccn_datetime_MIN_YEAR;
|
||||
var counter = startYear;
|
||||
for(var i = 0; i < 3; i++) {
|
||||
for(var j = 0; j < 4; j++, counter++) {
|
||||
var ele = $('#ccn-datetimepiacker-panelYear-table > div:nth-child({0}) > div:nth-child({1})'.format(i + 1, j + 1));
|
||||
if (counter < ccn_datetime_MAX_YEAR) {
|
||||
ele.attr('data', counter)
|
||||
.text(counter);
|
||||
} else {
|
||||
ele.attr('data', '')
|
||||
.html(' ');
|
||||
}
|
||||
|
||||
if (counter == ccn_datetimepicker_internalDateTime.getFullYear()) ele.attr('picked', 'true');
|
||||
else ele.attr('picked', 'false');
|
||||
}
|
||||
}
|
||||
|
||||
$('#ccn-datetimepiacker-panelYear-title')
|
||||
.text('{0} - {1}'.format(startYear, startYear + 12 < ccn_datetime_MAX_YEAR ? startYear + 12 : ccn_datetime_MAX_YEAR));
|
||||
|
||||
break;
|
||||
case ccn_datetimepicker_tabType.month:
|
||||
$('#ccn-datetimepiacker-panelMonth-table > div > div').attr('picked', 'false');
|
||||
if (ccn_datetimepicker_internalDateTime.getFullYear() == ccn_datetimepicker_displayCacheDateTime.getFullYear()) {
|
||||
var month = ccn_datetimepicker_internalDateTime.getMonth();
|
||||
$('#ccn-datetimepiacker-panelMonth-table > div:nth-child({0}) > div:nth-child({1})'.format(Math.floor(month / 4) + 1, (month % 4) + 1))
|
||||
.attr('picked', 'true');
|
||||
}
|
||||
|
||||
$('#ccn-datetimepiacker-panelMonth-title')
|
||||
.text(ccn_datetimepicker_displayCacheDateTime.getFullYear());
|
||||
|
||||
break;
|
||||
case ccn_datetimepicker_tabType.day:
|
||||
var gottenYear = ccn_datetimepicker_displayCacheDateTime.getFullYear();
|
||||
var gottenMonth = ccn_datetimepicker_displayCacheDateTime.getMonth() + 1;
|
||||
var counter = -ccn_datetime_DayOfWeek(gottenYear, gottenMonth, 1);
|
||||
var days = ccn_datetime_monthDayCount[gottenMonth - 1] + ((gottenMonth == 2 && ccn_datetime_IsLeapYear(gottenYear)) ? 1 : 0);
|
||||
for(var i = 0; i < 6; i++) {
|
||||
for(var j = 0; j < 7; j++, counter++) {
|
||||
var ele = $('#ccn-datetimepiacker-panelDay-table > div:nth-child({0}) > div:nth-child({1})'.format(i + 2, j + 1));
|
||||
if (counter < 0 || counter >= days) ele.attr('data', '').html(' ');
|
||||
else ele.attr('data', counter + 1).text(counter + 1);
|
||||
|
||||
if (counter + 1 == ccn_datetimepicker_internalDateTime.getDate()) ele.attr('picked', 'true');
|
||||
else ele.attr('picked', 'false');
|
||||
}
|
||||
}
|
||||
|
||||
$('#ccn-datetimepiacker-panelDay-title')
|
||||
.text('{0} - {1}'.format(
|
||||
ccn_datetimepicker_displayCacheDateTime.getFullYear(),
|
||||
ccn_i18n_UniversalGetMonth(ccn_datetimepicker_displayCacheDateTime.getMonth())
|
||||
));
|
||||
|
||||
break;
|
||||
case ccn_datetimepicker_tabType.hour:
|
||||
var gottenHour = ccn_datetimepicker_displayCacheDateTime.getHours();
|
||||
var newX = Math.cos((3 - gottenHour) * Math.PI * 2 / 12);
|
||||
var newY = Math.sin((3 - gottenHour) * Math.PI * 2 / 12);
|
||||
var radius = ccn_datetimepicker_dialPlateRadius * (gottenHour < 12 ? ccn_datetimepicker_dialPlateHourOutterPercent : ccn_datetimepicker_dialPlateHourInnerPercent);
|
||||
newX = newX * radius + ccn_datetimepicker_dialPlateRadius;
|
||||
newY = (-newY * radius) + ccn_datetimepicker_dialPlateRadius;
|
||||
|
||||
$('#ccn-datetimepicker-panelHour > line')
|
||||
.attr('x2', newX)
|
||||
.attr('y2', newY);
|
||||
|
||||
$('#ccn-datetimepicker-panelHour > circle[type=symbol]')
|
||||
.attr('cx', newX)
|
||||
.attr('cy', newY);
|
||||
|
||||
break;
|
||||
case ccn_datetimepicker_tabType.minute:
|
||||
var gottenMinute = ccn_datetimepicker_displayCacheDateTime.getMinutes();
|
||||
var newX = Math.cos((15 - gottenMinute) * Math.PI * 2 / 60);
|
||||
var newY = Math.sin((15 - gottenMinute) * Math.PI * 2 / 60);
|
||||
var radius = ccn_datetimepicker_dialPlateRadius * ccn_datetimepicker_dialPlateMinutePercent;
|
||||
newX = newX * radius + ccn_datetimepicker_dialPlateRadius;
|
||||
newY = (-newY * radius) + ccn_datetimepicker_dialPlateRadius;
|
||||
|
||||
$('#ccn-datetimepicker-panelMinute > line')
|
||||
.attr('x2', newX)
|
||||
.attr('y2', newY);
|
||||
|
||||
$('#ccn-datetimepicker-panelMinute > circle[type=symbol]')
|
||||
.attr('cx', newX)
|
||||
.attr('cy', newY);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function ccn_datetimepicker_RefreshSvg() {
|
||||
// svg resize only can be called when the svg is showing.
|
||||
// so call this func in window resize event or
|
||||
// displaying svg.
|
||||
$('div.pickerContainer > svg').each(function() {
|
||||
ccn_datetimepicker_OnSvgResize($(this));
|
||||
});
|
||||
}
|
||||
|
||||
function ccn_datetimepicker_Str2TabType(strl) {
|
||||
switch(strl) {
|
||||
case 'year':
|
||||
return ccn_datetimepicker_tabType.year
|
||||
case 'month':
|
||||
return ccn_datetimepicker_tabType.month
|
||||
case 'day':
|
||||
return ccn_datetimepicker_tabType.day
|
||||
case 'hour':
|
||||
return ccn_datetimepicker_tabType.hour
|
||||
case 'minute':
|
||||
return ccn_datetimepicker_tabType.minute
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function ccn_datetimepicker_GetUniformedXY(mouseOrTouchEvent, elements) {
|
||||
var offset = {
|
||||
left: elements.offset().left,
|
||||
top: elements.offset().top,
|
||||
halfWidth: elements.width() / 2,
|
||||
halfHeight: elements.height() / 2,
|
||||
halfSquareWidthHeight: Math.min(elements.width(), elements.height()) / 2
|
||||
}
|
||||
if(typeof(mouseOrTouchEvent.pageX) != 'undefined' && typeof(mouseOrTouchEvent.pageY) != 'undefined') {
|
||||
offset.realX = mouseOrTouchEvent.pageX;
|
||||
offset.realY = mouseOrTouchEvent.pageY;
|
||||
} else if(typeof(mouseOrTouchEvent.targetTouches) != 'undefined' && mouseOrTouchEvent.targetTouches.length >= 1) {
|
||||
offset.realX = mouseOrTouchEvent.targetTouches[0].pageX;
|
||||
offset.realY = mouseOrTouchEvent.targetTouches[0].pageY;
|
||||
} else {
|
||||
offset.realX = 0;
|
||||
offset.realY = 0;
|
||||
}
|
||||
|
||||
var _x = (offset.realX - offset.left - offset.halfWidth) / offset.halfSquareWidthHeight * ccn_datetimepicker_dialPlateRadius;
|
||||
var _y = -((offset.realY - offset.top - offset.halfHeight) / offset.halfSquareWidthHeight * ccn_datetimepicker_dialPlateRadius);
|
||||
|
||||
return {x: _x, y: _y};
|
||||
}
|
||||
|
||||
function ccn_datetimepicker_PrevNextYear(isPrev) {
|
||||
ccn_datetimepicker_displayCacheDateTime.setFullYear(
|
||||
ccn_datetimepicker_displayCacheDateTime.getFullYear() + (isPrev ? -12 : 12));
|
||||
|
||||
ccn_datetimepicker_ClampDateTime(ccn_datetimepicker_displayCacheDateTime);
|
||||
ccn_datetimepicker_RefreshDisplay(ccn_datetimepicker_tabType.year);
|
||||
}
|
||||
|
||||
function ccn_datetimepicker_PrevNextMonth(isPrev) {
|
||||
ccn_datetimepicker_displayCacheDateTime.setFullYear(
|
||||
ccn_datetimepicker_displayCacheDateTime.getFullYear() + (isPrev ? -1 : 1));
|
||||
|
||||
ccn_datetimepicker_ClampDateTime(ccn_datetimepicker_displayCacheDateTime);
|
||||
ccn_datetimepicker_RefreshDisplay(ccn_datetimepicker_tabType.month);
|
||||
}
|
||||
|
||||
function ccn_datetimepicker_PrevNextDay(isPrev) {
|
||||
ccn_datetimepicker_displayCacheDateTime.setMonth(
|
||||
ccn_datetimepicker_displayCacheDateTime.getMonth() + (isPrev ? -1 : 1));
|
||||
|
||||
ccn_datetimepicker_ClampDateTime(ccn_datetimepicker_displayCacheDateTime);
|
||||
ccn_datetimepicker_RefreshDisplay(ccn_datetimepicker_tabType.day);
|
||||
}
|
||||
|
||||
function ccn_datetimepicker_ClickYear() {
|
||||
var ele = $(this);
|
||||
if (ele.attr('data') == '') return;
|
||||
|
||||
ccn_datetimepicker_internalDateTime.setFullYear(parseInt(ele.attr('data')));
|
||||
ccn_datetimepicker_ClampDateTime(ccn_datetimepicker_internalDateTime);
|
||||
|
||||
if (ccn_datetimepicker_mode != ccn_datetimepicker_tabType.year)
|
||||
ccn_datetimepicker_SwitchTab(ccn_datetimepicker_tabType.month);
|
||||
else
|
||||
ccn_datetimepicker_RefreshDisplay(ccn_datetimepicker_tabType.year);
|
||||
}
|
||||
|
||||
function ccn_datetimepicker_ClickMonth() {
|
||||
var ele = $(this);
|
||||
if (ele.attr('data') == '') return;
|
||||
|
||||
ccn_datetimepicker_internalDateTime.setFullYear(
|
||||
ccn_datetimepicker_displayCacheDateTime.getFullYear(),
|
||||
parseInt(ele.attr('data'))
|
||||
);
|
||||
ccn_datetimepicker_ClampDateTime(ccn_datetimepicker_internalDateTime);
|
||||
|
||||
if (ccn_datetimepicker_mode != ccn_datetimepicker_tabType.month)
|
||||
ccn_datetimepicker_SwitchTab(ccn_datetimepicker_tabType.day);
|
||||
else
|
||||
ccn_datetimepicker_RefreshDisplay(ccn_datetimepicker_tabType.month);
|
||||
}
|
||||
|
||||
function ccn_datetimepicker_ClickDay() {
|
||||
var ele = $(this);
|
||||
if (ele.attr('data') == '') return;
|
||||
|
||||
ccn_datetimepicker_internalDateTime.setFullYear(
|
||||
ccn_datetimepicker_displayCacheDateTime.getFullYear(),
|
||||
ccn_datetimepicker_displayCacheDateTime.getMonth(),
|
||||
parseInt(ele.attr('data'))
|
||||
);
|
||||
ccn_datetimepicker_ClampDateTime(ccn_datetimepicker_internalDateTime);
|
||||
|
||||
if (ccn_datetimepicker_mode != ccn_datetimepicker_tabType.day)
|
||||
ccn_datetimepicker_SwitchTab(ccn_datetimepicker_tabType.hour);
|
||||
else
|
||||
ccn_datetimepicker_RefreshDisplay(ccn_datetimepicker_tabType.day);
|
||||
}
|
||||
|
||||
|
||||
function ccn_datetimepicker_StartDragHour() { ccn_datetimepicker_enableHourDrag = true; }
|
||||
function ccn_datetimepicker_DraggingHour(e) {
|
||||
if (!ccn_datetimepicker_enableHourDrag) return;
|
||||
|
||||
var offset = ccn_datetimepicker_GetUniformedXY(e, $('#ccn-datetimepicker-panelHour'));
|
||||
var x = offset.x;
|
||||
var y = offset.y;
|
||||
|
||||
var distance = Math.sqrt(x * x + y * y);
|
||||
var angle = Math.acos(x / distance);
|
||||
if (y < 0) angle = Math.PI * 2 - angle; // correct negative y axis angle
|
||||
|
||||
angle += (ccn_datetimepicker_dialPlateHourResolution / 2); // correct offset
|
||||
if (angle > Math.PI * 2)
|
||||
angle -= Math.PI * 2;
|
||||
|
||||
var number = Math.floor(angle / ccn_datetimepicker_dialPlateHourResolution);
|
||||
if (number >= 12) number = 11; // prevent unexpected result at the edge.
|
||||
number = (15 - number) % 12;
|
||||
if (distance < ccn_datetimepicker_dialPlateRadius * ccn_datetimepicker_dialPlateHourDistinguishPercent)
|
||||
number += 12;
|
||||
|
||||
// judge
|
||||
if (ccn_datetimepicker_displayCacheDateTime.getHours() != number) {
|
||||
ccn_datetimepicker_displayCacheDateTime.setHours(number);
|
||||
ccn_datetimepicker_RefreshDisplay(ccn_datetimepicker_tabType.hour);
|
||||
}
|
||||
|
||||
e.preventDefault();
|
||||
}
|
||||
function ccn_datetimepicker_StopDragHour() {
|
||||
ccn_datetimepicker_enableHourDrag = false;
|
||||
|
||||
ccn_datetimepicker_internalDateTime.setHours(ccn_datetimepicker_displayCacheDateTime.getHours());
|
||||
ccn_datetimepicker_ClampDateTime(ccn_datetimepicker_internalDateTime);
|
||||
|
||||
if (ccn_datetimepicker_mode != ccn_datetimepicker_tabType.hour)
|
||||
ccn_datetimepicker_SwitchTab(ccn_datetimepicker_tabType.minute);
|
||||
}
|
||||
|
||||
|
||||
function ccn_datetimepicker_StartDragMinute() { ccn_datetimepicker_enableMinuteDrag = true; }
|
||||
function ccn_datetimepicker_DraggingMinute(e) {
|
||||
if (!ccn_datetimepicker_enableMinuteDrag) return;
|
||||
|
||||
var offset = ccn_datetimepicker_GetUniformedXY(e, $('#ccn-datetimepicker-panelMinute'));
|
||||
var x = offset.x;
|
||||
var y = offset.y;
|
||||
|
||||
var distance = Math.sqrt(x * x + y * y);
|
||||
var angle = Math.acos(x / distance);
|
||||
if (y < 0) angle = Math.PI * 2 - angle; // correct negative y axis angle
|
||||
|
||||
angle += (ccn_datetimepicker_dialPlateMinuteResolution / 2); // correct offset
|
||||
if (angle > Math.PI * 2)
|
||||
angle -= Math.PI * 2;
|
||||
|
||||
var number = Math.floor(angle / ccn_datetimepicker_dialPlateMinuteResolution);
|
||||
if (number >= 60) number = 59; // prevent unexpected result at the edge.
|
||||
number = (75 - number) % 60;
|
||||
|
||||
// judge
|
||||
if (ccn_datetimepicker_displayCacheDateTime.getMinutes() != number) {
|
||||
ccn_datetimepicker_displayCacheDateTime.setMinutes(number);
|
||||
ccn_datetimepicker_RefreshDisplay(ccn_datetimepicker_tabType.minute);
|
||||
}
|
||||
|
||||
e.preventDefault();
|
||||
}
|
||||
function ccn_datetimepicker_StopDragMinute() {
|
||||
ccn_datetimepicker_enableMinuteDrag = false;
|
||||
|
||||
ccn_datetimepicker_internalDateTime.setMinutes(ccn_datetimepicker_displayCacheDateTime.getMinutes());
|
||||
ccn_datetimepicker_ClampDateTime(ccn_datetimepicker_internalDateTime);
|
||||
|
||||
// no page need to go to
|
||||
// but we need refresh current page
|
||||
ccn_datetimepicker_RefreshDisplay(ccn_datetimepicker_tabType.minute);
|
||||
}
|
||||
|
||||
|
||||
function ccn_datetimepicker_ClampDateTime(dateObj) {
|
||||
if (dateObj < ccn_datetime_MIN_DATETIME)
|
||||
dateObj.setTime(ccn_datetime_MIN_DATETIME.getTime());
|
||||
if (dateObj >= ccn_datetime_MAX_DATETIME)
|
||||
dateObj.setTime(ccn_datetime_MAX_DATETIME.getTime());
|
||||
}
|
||||
|
||||
// ========================================================== universal function
|
||||
|
||||
function ccn_datetimepicker_Set(pickerIndex, dt, isUTC, mode) {
|
||||
var ele = $('[datetimepicker=' + pickerIndex + ']');
|
||||
while(true) {
|
||||
if (mode < ccn_datetimepicker_tabType.year) break;
|
||||
ele.attr('datetimepicker-year', isUTC ? dt.getUTCFullYear() : dt.getFullYear());
|
||||
if (mode < ccn_datetimepicker_tabType.month) break;
|
||||
ele.attr('datetimepicker-month', (isUTC ? dt.getUTCMonth() : dt.getMonth()) + 1);
|
||||
if (mode < ccn_datetimepicker_tabType.day) break;
|
||||
ele.attr('datetimepicker-day', isUTC ? dt.getUTCDate() : dt.getDate());
|
||||
if (mode < ccn_datetimepicker_tabType.hour) break;
|
||||
ele.attr('datetimepicker-hour', isUTC ? dt.getUTCHours() : dt.getHours());
|
||||
if (mode < ccn_datetimepicker_tabType.minute) break;
|
||||
ele.attr('datetimepicker-minute', isUTC ? dt.getUTCMinutes() : dt.getMinutes());
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (typeof(ele.prop('funcs')) != 'undefined' && typeof(ele.prop('funcs').callback) == 'function')
|
||||
ele.prop('funcs').callback();
|
||||
}
|
||||
|
||||
function ccn_datetimepicker_Get(pickerIndex, isUTC) {
|
||||
var ele = $('[datetimepicker=' + pickerIndex + ']');
|
||||
year = ele.attr('datetimepicker-year');
|
||||
month = ele.attr('datetimepicker-month');
|
||||
day = ele.attr('datetimepicker-day');
|
||||
hour = ele.attr('datetimepicker-hour');
|
||||
minute = ele.attr('datetimepicker-minute');
|
||||
if (IsUndefinedOrEmpty(year)) year = ccn_datetime_MIN_YEAR;
|
||||
if (IsUndefinedOrEmpty(month)) month = 1;
|
||||
if (IsUndefinedOrEmpty(day)) day = 1;
|
||||
if (IsUndefinedOrEmpty(hour)) hour = 0;
|
||||
if (IsUndefinedOrEmpty(minute)) minute = 0;
|
||||
|
||||
if (isUTC) return new Date(Date.UTC(year, parseInt(month) - 1, day, hour, minute, 0, 0));
|
||||
else return new Date(year, parseInt(month) - 1, day, hour, minute, 0, 0);
|
||||
}
|
||||
61
frontend/static/js/headerNav.js
Normal file
61
frontend/static/js/headerNav.js
Normal file
@@ -0,0 +1,61 @@
|
||||
function ccn_headerNav_Insert() {
|
||||
$('body').prepend(ccn_template_headerNav.render());
|
||||
}
|
||||
|
||||
function ccn_headerNav_LoggedRefresh() {
|
||||
if (ccn_api_common_tokenValid()) {
|
||||
// logged, show all nav button and logout button
|
||||
$("#ccn-header-nav-home").show();
|
||||
$("#ccn-header-nav-collection").show();
|
||||
$("#ccn-header-nav-calendar").show();
|
||||
$("#ccn-header-nav-todo").show();
|
||||
$("#ccn-header-nav-admin").show();
|
||||
|
||||
$("#ccn-header-user-login").hide();
|
||||
$("#ccn-header-user-logout").show();
|
||||
} else {
|
||||
$("#ccn-header-nav-home").show();
|
||||
$("#ccn-header-nav-collection").hide();
|
||||
$("#ccn-header-nav-calendar").hide();
|
||||
$("#ccn-header-nav-todo").hide();
|
||||
$("#ccn-header-nav-admin").hide();
|
||||
|
||||
$("#ccn-header-user-login").show();
|
||||
$("#ccn-header-user-logout").hide();
|
||||
}
|
||||
}
|
||||
|
||||
// bind language process and internal process function such as logout and expand menu
|
||||
function ccn_headerNav_BindEvents() {
|
||||
// bind function
|
||||
$("#ccn-header-language > *").each(function(){
|
||||
$(this).click(function(){
|
||||
ccn_i18n_ChangeLanguage($(this).attr("language"));
|
||||
ccn_i18n_LoadLanguage();
|
||||
ccn_i18n_ApplyLanguage();
|
||||
});
|
||||
});
|
||||
|
||||
// bind logout
|
||||
$("#ccn-header-user-logout").click(function() {
|
||||
if (ccn_api_common_logout()) {
|
||||
// ok, logout
|
||||
// jump into home page again
|
||||
window.location.href = '/web/home';
|
||||
return;
|
||||
|
||||
} else ccn_messagebox_Show($.i18n.prop("ccn-i18n-js-fail-logout"));
|
||||
});
|
||||
|
||||
// bind burger menu
|
||||
// copy from bulma website
|
||||
// Check for click events on the navbar burger icon
|
||||
$(".navbar-burger").click(function() {
|
||||
|
||||
// Toggle the "is-active" class on both the "navbar-burger" and the "navbar-menu"
|
||||
$(".navbar-burger").toggleClass("is-active");
|
||||
$(".navbar-menu").toggleClass("is-active");
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
89
frontend/static/js/i18n.js
Normal file
89
frontend/static/js/i18n.js
Normal file
@@ -0,0 +1,89 @@
|
||||
var ccn_i18n_i18nSupported = ['en-US', 'zh-CN'];
|
||||
var ccn_i18n_currentLanguage = 'en-US';
|
||||
var ccn_pages_enumPages = {
|
||||
home : 0,
|
||||
calendar: 1,
|
||||
todo: 2,
|
||||
admin: 3,
|
||||
login: 4,
|
||||
collection: 5,
|
||||
event: 6
|
||||
};
|
||||
var ccn_pages_currentPage = ccn_pages_enumPages.home;
|
||||
|
||||
// judge current language
|
||||
ccn_i18n_currentLanguage = ccn_localstorageAssist_Get('ccn-i18n', 'en-US');
|
||||
if (ccn_i18n_i18nSupported.indexOf(ccn_i18n_currentLanguage) == -1){
|
||||
ccn_localstorageAssist_Set('ccn-i18n', 'en-US');
|
||||
ccn_i18n_currentLanguage = 'en-US';
|
||||
}
|
||||
|
||||
function ccn_i18n_ChangeLanguage(newLang) {
|
||||
if (ccn_i18n_i18nSupported.indexOf(newLang) == -1) return false;
|
||||
ccn_i18n_currentLanguage = newLang;
|
||||
ccn_localstorageAssist_Set('ccn-i18n', newLang);
|
||||
return true;
|
||||
}
|
||||
|
||||
function ccn_i18n_LoadLanguage() {
|
||||
$.i18n.properties({
|
||||
name: 'strings_' + ccn_i18n_currentLanguage,
|
||||
path: '/static/i18n/',
|
||||
encoding: 'utf-8',
|
||||
mode: 'map',
|
||||
async: false,
|
||||
cache: false,
|
||||
language: ccn_i18n_currentLanguage
|
||||
});
|
||||
}
|
||||
|
||||
function ccn_i18n_ApplyLanguage() {
|
||||
//set usual block
|
||||
var cache = $("[i18n-name]");
|
||||
cache.each(function() {
|
||||
$(this).html($.i18n.prop($(this).attr('i18n-name')));
|
||||
});
|
||||
|
||||
//set unusual block
|
||||
//set title
|
||||
switch(ccn_pages_currentPage) {
|
||||
case ccn_pages_enumPages.home:
|
||||
$('#ccn-pageName').html($.i18n.prop('ccn-i18n-pageName-home'));
|
||||
break;
|
||||
case ccn_pages_enumPages.calendar:
|
||||
$('#ccn-pageName').html($.i18n.prop('ccn-i18n-pageName-calendar'));
|
||||
break;
|
||||
case ccn_pages_enumPages.todo:
|
||||
$('#ccn-pageName').html($.i18n.prop('ccn-i18n-pageName-todo'));
|
||||
break;
|
||||
case ccn_pages_enumPages.admin:
|
||||
$('#ccn-pageName').html($.i18n.prop('ccn-i18n-pageName-admin'));
|
||||
break;
|
||||
case ccn_pages_enumPages.login:
|
||||
$('#ccn-pageName').html($.i18n.prop('ccn-i18n-pageName-login'));
|
||||
break;
|
||||
case ccn_pages_enumPages.collection:
|
||||
$('#ccn-pageName').html($.i18n.prop('ccn-i18n-pageName-collection'));
|
||||
break;
|
||||
case ccn_pages_enumPages.event:
|
||||
$('#ccn-pageName').html($.i18n.prop('ccn-i18n-pageName-event'));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function ccn_i18n_ApplyLanguage2Content(ctx) {
|
||||
ctx.find("[i18n-name]").each(function() {
|
||||
$(this).html($.i18n.prop($(this).attr('i18n-name')));
|
||||
});
|
||||
}
|
||||
|
||||
// note: month is zero based
|
||||
function ccn_i18n_UniversalGetMonth(month) {
|
||||
return $.i18n.prop('ccn-i18n-universal-month-' + (month + 1));
|
||||
}
|
||||
|
||||
// note: day of week is zero based
|
||||
function ccn_i18n_UniversalGetDayOfWeek(dayOfWeek) {
|
||||
return $.i18n.prop('ccn-i18n-universal-week-' + (dayOfWeek + 1));
|
||||
}
|
||||
|
||||
21
frontend/static/js/localStorageAssist.js
Normal file
21
frontend/static/js/localStorageAssist.js
Normal file
@@ -0,0 +1,21 @@
|
||||
function ccn_localstorageAssist_Get(index, defaultValue) {
|
||||
var cache = localStorage.getItem(index);
|
||||
if (cache == null) {
|
||||
ccn_localstorageAssist_Set(index, defaultValue);
|
||||
return defaultValue;
|
||||
} else return cache;
|
||||
}
|
||||
|
||||
function ccn_localstorageAssist_Set(index, value) {
|
||||
localStorage.setItem(index, value);
|
||||
}
|
||||
|
||||
// =================================== seperated data getter setter
|
||||
|
||||
function ccn_localstorageAssist_GetApiToken() {
|
||||
return ccn_localstorageAssist_Get('ccn-token', '');
|
||||
}
|
||||
|
||||
function ccn_localstorageAssist_SetApiToken(value) {
|
||||
ccn_localstorageAssist_Set('ccn-token', value);
|
||||
}
|
||||
19
frontend/static/js/messagebox.js
Normal file
19
frontend/static/js/messagebox.js
Normal file
@@ -0,0 +1,19 @@
|
||||
function ccn_messagebox_Insert() {
|
||||
$('body').append(ccn_template_messagebox.render());
|
||||
}
|
||||
|
||||
function ccn_messagebox_Show(/*title,*/ info) {
|
||||
//$('#ccn-messagebox-title').text(title);
|
||||
$('#ccn-messagebox-body').text(info);
|
||||
|
||||
$('#ccn-messagebox-modal').addClass('is-active');
|
||||
}
|
||||
|
||||
function ccn_messagebox_BindEvent() {
|
||||
$('#ccn-messagebox-btnClose').click(ccn_messagebox_Hide);
|
||||
$('#ccn-messagebox-btnConfirm').click(ccn_messagebox_Hide);
|
||||
}
|
||||
|
||||
function ccn_messagebox_Hide() {
|
||||
$('#ccn-messagebox-modal').removeClass('is-active');
|
||||
}
|
||||
265
frontend/static/js/page/admin.js
Normal file
265
frontend/static/js/page/admin.js
Normal file
@@ -0,0 +1,265 @@
|
||||
var ccn_admin_userListCache = [];
|
||||
var ccn_admin_tokenListCache = [];
|
||||
|
||||
$(document).ready(function() {
|
||||
ccn_pages_currentPage = ccn_pages_enumPages.admin;
|
||||
|
||||
// template process
|
||||
ccn_template_Load();
|
||||
|
||||
// nav process
|
||||
ccn_headerNav_Insert();
|
||||
ccn_headerNav_BindEvents();
|
||||
ccn_headerNav_LoggedRefresh();
|
||||
|
||||
// messagebox process
|
||||
ccn_messagebox_Insert();
|
||||
ccn_messagebox_BindEvent();
|
||||
|
||||
// bind tab control switcher and set current tab
|
||||
$("#tabcontrol-tab-1-1").click(function(){
|
||||
ccn_tabcontrol_SwitchTab(1, 1);
|
||||
});
|
||||
$("#tabcontrol-tab-1-2").click(function(){
|
||||
ccn_tabcontrol_SwitchTab(1, 2);
|
||||
});
|
||||
$("#tabcontrol-tab-1-3").click(function(){
|
||||
ccn_tabcontrol_SwitchTab(1, 3);
|
||||
});
|
||||
ccn_tabcontrol_SwitchTab(1, 1);
|
||||
|
||||
// load user tab according to admin status
|
||||
if(!ccn_api_profile_isAdmin())
|
||||
$('#tabcontrol-tab-1-3').hide();
|
||||
|
||||
// apply i18n
|
||||
ccn_i18n_LoadLanguage();
|
||||
ccn_i18n_ApplyLanguage();
|
||||
|
||||
// bind event
|
||||
$('#ccn-admin-profile-btnChangePassword').click(ccn_admin_profile_ChangePassword);
|
||||
$('#ccn-admin-tokenList-btnRefresh').click(ccn_admin_tokenList_Refresh);
|
||||
$('#ccn-admin-userList-btnAdd').click(ccn_admin_userList_Add);
|
||||
$('#ccn-admin-userList-btnRefresh').click(ccn_admin_userList_Refresh);
|
||||
});
|
||||
|
||||
// ================== profile
|
||||
|
||||
function ccn_admin_profile_ChangePassword() {
|
||||
var newpassword = $('#ccn-admin-profile-inputPassword').val();
|
||||
if (newpassword == "") return;
|
||||
|
||||
var result = ccn_api_profile_changePassword(newpassword);
|
||||
if(result) {
|
||||
ccn_messagebox_Show($.i18n.prop("ccn-i18n-js-success"));
|
||||
$('#ccn-admin-profile-inputPassword').val('');
|
||||
} else
|
||||
ccn_messagebox_Show($.i18n.prop("ccn-i18n-js-fail-update"));
|
||||
|
||||
}
|
||||
|
||||
// ================== token
|
||||
|
||||
function ccn_admin_tokenList_Refresh() {
|
||||
ccn_admin_tokenListCache = new Array();
|
||||
var listDOM = $('#ccn-admin-tokenList');
|
||||
listDOM.empty();
|
||||
|
||||
var renderdata = {
|
||||
uuid: undefined,
|
||||
isMe: undefined,
|
||||
ua: undefined,
|
||||
ip: undefined,
|
||||
expireOn: undefined
|
||||
}
|
||||
var gottenDateTime = new Date();
|
||||
|
||||
var result = ccn_api_profile_getToken();
|
||||
if(typeof(result) != 'undefined') {
|
||||
for(var index in result) {
|
||||
var item = result[index];
|
||||
renderdata.uuid = item[1];
|
||||
renderdata.isMe = ccn_localstorageAssist_GetApiToken() == item[1];
|
||||
renderdata.ua = item[3];
|
||||
renderdata.ip = item[4];
|
||||
gottenDateTime.setTime(item[2] * 1000);
|
||||
renderdata.expireOn = gottenDateTime.toLocaleString();
|
||||
|
||||
listDOM.append(ccn_template_tokenItem.render(renderdata));
|
||||
|
||||
// bind event
|
||||
var uuid = renderdata.uuid;
|
||||
$("#ccn-tokenItem-btnLogout-" + uuid).click(ccn_admin_tokenList_ItemDelete);
|
||||
|
||||
// add into cache
|
||||
ccn_admin_tokenListCache[uuid] = item;
|
||||
}
|
||||
|
||||
ccn_i18n_ApplyLanguage2Content(listDOM);
|
||||
}
|
||||
}
|
||||
|
||||
function ccn_admin_tokenList_ItemDelete() {
|
||||
var uuid = $(this).attr("uuid");
|
||||
|
||||
var result = ccn_api_profile_deleteToken(uuid);
|
||||
|
||||
if(!result) {
|
||||
// fail
|
||||
ccn_messagebox_Show($.i18n.prop("ccn-i18n-js-fail-delete"));
|
||||
} else {
|
||||
// remove body
|
||||
$("#ccn-tokenItem-" + uuid).remove();
|
||||
}
|
||||
}
|
||||
|
||||
// ================== user list
|
||||
|
||||
function ccn_admin_userList_RefreshCacheList() {
|
||||
ccn_admin_userListCache = new Array();
|
||||
|
||||
var result = ccn_api_admin_get();
|
||||
if(typeof(result) != 'undefined') {
|
||||
for(var index in result) {
|
||||
ccn_admin_userListCache[index] = result[index];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function ccn_admin_userList_RenderItem(item, index, listDOM) {
|
||||
var renderdata = {
|
||||
uuid: index, // use index for uuid. there are no uuid for user
|
||||
username: item[0]
|
||||
}
|
||||
|
||||
// render
|
||||
listDOM.append(ccn_template_userItem.render(renderdata));
|
||||
|
||||
// set mode
|
||||
var uuid = index;
|
||||
ccn_admin_userList_ChangeDisplayMode(uuid, false, item[1])
|
||||
|
||||
// bind event
|
||||
$("#ccn-userItem-btnEdit-" + uuid).click(ccn_admin_userList_ItemEdit);
|
||||
$("#ccn-userItem-btnDelete-" + uuid).click(ccn_admin_userList_ItemDelete);
|
||||
$("#ccn-userItem-btnUpdate-" + uuid).click(ccn_admin_userList_ItemUpdate);
|
||||
$("#ccn-userItem-btnCancelUpdate-" + uuid).click(ccn_admin_userList_ItemCancelUpdate);
|
||||
}
|
||||
|
||||
function ccn_admin_userList_RenderCacheList() {
|
||||
$('#ccn-admin-userList').empty();
|
||||
|
||||
var listDOM = $('#ccn-admin-userList');
|
||||
for(var index in ccn_admin_userListCache) {
|
||||
ccn_admin_userList_RenderItem(
|
||||
ccn_admin_userListCache[index],
|
||||
index,
|
||||
listDOM
|
||||
)
|
||||
}
|
||||
|
||||
ccn_i18n_ApplyLanguage2Content(listDOM);
|
||||
}
|
||||
|
||||
function ccn_admin_userList_ChangeDisplayMode(uuid, isEdit, isAdmin) {
|
||||
if (typeof(isAdmin) != 'undefined') {
|
||||
if (isAdmin)
|
||||
$("#ccn-userItem-iconIsAdmin-" + uuid).show();
|
||||
else
|
||||
$("#ccn-userItem-iconIsAdmin-" + uuid).hide();
|
||||
}
|
||||
|
||||
if (typeof(isEdit) != 'undefined') {
|
||||
if (isEdit) {
|
||||
$("#ccn-userItem-btnEdit-" + uuid).hide();
|
||||
$("#ccn-userItem-btnDelete-" + uuid).hide();
|
||||
$("#ccn-userItem-btnUpdate-" + uuid).show();
|
||||
$("#ccn-userItem-btnCancelUpdate-" + uuid).show();
|
||||
|
||||
$("#ccn-userItem-boxPassword-" + uuid).show();
|
||||
$("#ccn-userItem-boxIsAdmin-" + uuid).show();
|
||||
} else {
|
||||
$("#ccn-userItem-btnEdit-" + uuid).show();
|
||||
$("#ccn-userItem-btnDelete-" + uuid).show();
|
||||
$("#ccn-userItem-btnUpdate-" + uuid).hide();
|
||||
$("#ccn-userItem-btnCancelUpdate-" + uuid).hide();
|
||||
|
||||
$("#ccn-userItem-boxPassword-" + uuid).hide();
|
||||
$("#ccn-userItem-boxIsAdmin-" + uuid).hide();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function ccn_admin_userList_Refresh() {
|
||||
// refresh and render once
|
||||
ccn_admin_userList_RefreshCacheList();
|
||||
ccn_admin_userList_RenderCacheList();
|
||||
}
|
||||
|
||||
function ccn_admin_userList_Add() {
|
||||
var username = $('#ccn-admin-userList-inputUsername').val();
|
||||
if (username == "") return;
|
||||
|
||||
var result = ccn_api_admin_add(username);
|
||||
if (typeof(result) == 'undefined') {
|
||||
ccn_messagebox_Show($.i18n.prop("ccn-i18n-js-fail-add"));
|
||||
} else {
|
||||
// render
|
||||
var index = ccn_admin_userListCache.push(result) - 1;
|
||||
var listDOM = $('#ccn-admin-userList');
|
||||
ccn_admin_userList_RenderItem(result, index, listDOM);
|
||||
ccn_i18n_ApplyLanguage2Content(listDOM);
|
||||
}
|
||||
}
|
||||
|
||||
function ccn_admin_userList_ItemEdit() {
|
||||
var uuid = $(this).attr("uuid");
|
||||
|
||||
// copy isAdmin to checkbox and clean password box
|
||||
$('#ccn-userItem-inputIsAdmin-' + uuid).prop("checked", ccn_admin_userListCache[uuid][1]);
|
||||
$('#ccn-userItem-inputPassword-' + uuid).val('');
|
||||
|
||||
// switch to edit mode
|
||||
ccn_admin_userList_ChangeDisplayMode(uuid, true, undefined);
|
||||
}
|
||||
|
||||
function ccn_admin_userList_ItemDelete() {
|
||||
var uuid = $(this).attr("uuid");
|
||||
|
||||
var result = ccn_api_admin_delete(ccn_admin_userListCache[uuid][0]);
|
||||
|
||||
if(!result) {
|
||||
// fail
|
||||
ccn_messagebox_Show($.i18n.prop("ccn-i18n-js-fail-delete"));
|
||||
} else {
|
||||
// remove body
|
||||
$("#ccn-userItem-" + uuid).remove();
|
||||
}
|
||||
}
|
||||
|
||||
function ccn_admin_userList_ItemUpdate() {
|
||||
var uuid = $(this).attr("uuid");
|
||||
var newpassword = $('#ccn-userItem-inputPassword-' + uuid).val();
|
||||
var isAdmin = $('#ccn-userItem-inputIsAdmin-' + uuid).prop("checked");
|
||||
|
||||
var result = ccn_api_admin_update(
|
||||
ccn_admin_userListCache[uuid][0],
|
||||
newpassword == "" ? undefined : newpassword,
|
||||
isAdmin == ccn_admin_userListCache[uuid][1] ? undefined : isAdmin);
|
||||
|
||||
if (!result) {
|
||||
// fail
|
||||
ccn_messagebox_Show($.i18n.prop("ccn-i18n-js-fail-update"));
|
||||
} else {
|
||||
// safely update data
|
||||
ccn_admin_userListCache[uuid][1] = isAdmin
|
||||
|
||||
// switch to normal mode
|
||||
ccn_admin_userList_ChangeDisplayMode(uuid, false, isAdmin);
|
||||
}
|
||||
}
|
||||
|
||||
function ccn_admin_userList_ItemCancelUpdate() {
|
||||
var uuid = $(this).attr("uuid");
|
||||
ccn_admin_userList_ChangeDisplayMode(uuid, false, undefined);
|
||||
}
|
||||
376
frontend/static/js/page/calendar.js
Normal file
376
frontend/static/js/page/calendar.js
Normal file
@@ -0,0 +1,376 @@
|
||||
// 2 list which will store sharing and shared collection's display mode.
|
||||
// key is uuid, value is bool
|
||||
var ccn_calendar_owned_displayCache = [];
|
||||
var ccn_calendar_shared_displayCache = [];
|
||||
|
||||
// modal editing object.
|
||||
// undefined mean add
|
||||
// not undefined mean update(a copy of calendar event)
|
||||
var ccn_calendar_eventModal_editing = undefined;
|
||||
var ccn_calendar_eventModal_collectionCache = [];
|
||||
var ccn_calendar_calendar_listCache = [];
|
||||
var ccn_calendar_calendar_displayCache = [];
|
||||
var ccn_calendar_calendar_displayDateTime = 0;
|
||||
|
||||
$(document).ready(function() {
|
||||
ccn_pages_currentPage = ccn_pages_enumPages.calendar;
|
||||
|
||||
// template process
|
||||
ccn_template_Load();
|
||||
|
||||
// nav process
|
||||
ccn_headerNav_Insert();
|
||||
ccn_headerNav_BindEvents();
|
||||
ccn_headerNav_LoggedRefresh();
|
||||
|
||||
// messagebox process
|
||||
ccn_messagebox_Insert();
|
||||
ccn_messagebox_BindEvent();
|
||||
|
||||
// process calendar it self
|
||||
ccn_calendar_calendar_LoadCalendarBody();
|
||||
|
||||
// init datetimepicker and preset
|
||||
ccn_datetimepicker_Insert();
|
||||
var nowtime = new Date();
|
||||
ccn_datetimepicker_Set(1, nowtime, false, ccn_datetimepicker_tabType.month);
|
||||
|
||||
// bind tab control switcher and set current tab
|
||||
$("#tabcontrol-tab-1-1").click(function(){
|
||||
ccn_tabcontrol_SwitchTab(1, 1);
|
||||
});
|
||||
$("#tabcontrol-tab-1-2").click(function(){
|
||||
ccn_tabcontrol_SwitchTab(1, 2);
|
||||
});
|
||||
$("#tabcontrol-tab-1-3").click(function(){
|
||||
ccn_tabcontrol_SwitchTab(1, 3);
|
||||
});
|
||||
ccn_tabcontrol_SwitchTab(1, 1);
|
||||
|
||||
// apply i18n
|
||||
ccn_i18n_LoadLanguage();
|
||||
ccn_i18n_ApplyLanguage();
|
||||
|
||||
//refresh once
|
||||
ccn_calendar_collection_Refresh();
|
||||
ccn_calendar_calendar_Refresh();
|
||||
ccn_calendar_calendar_Analyse();
|
||||
ccn_calendar_calendar_Render();
|
||||
|
||||
// bind event
|
||||
$('#ccn-calendar-collection-btnRefresh').click(ccn_calendar_collection_Refresh);
|
||||
|
||||
$('#ccn-calendar-calendar-btnJump')
|
||||
.prop('funcs', {callback: ccn_calendar_calendar_btnRefresh})
|
||||
.click(function() {
|
||||
ccn_datetimepicker_Modal(
|
||||
ccn_datetimepicker_tabType.month,
|
||||
1,
|
||||
false);
|
||||
});
|
||||
$('#ccn-calendar-calendar-btnToday').click(ccn_calendar_calendar_btnToday);
|
||||
$('#ccn-calendar-calendar-btnAdd').click(ccn_calendar_calendar_btnAdd);
|
||||
});
|
||||
|
||||
// ================== calendar
|
||||
|
||||
function ccn_calendar_calendar_LoadCalendarBody() {
|
||||
$('#ccn-calendar-calendarBody').append(ccn_template_calendarItem.render());
|
||||
}
|
||||
|
||||
// this function only refresh cache list
|
||||
function ccn_calendar_calendar_Refresh() {
|
||||
var gottenDateTime = ccn_datetimepicker_Get(1, false);
|
||||
var gottenYear = gottenDateTime.getFullYear();
|
||||
var gottenMonth = gottenDateTime.getMonth() + 1;
|
||||
$('#ccn-calendar-calendar-textMonth').text('{0} - {1}'.format(gottenYear, ccn_i18n_UniversalGetMonth(gottenMonth - 1)));
|
||||
// don't need to set anything, because its default value is enough to use.
|
||||
|
||||
var gottenWeek = ccn_datetime_DayOfWeek(gottenYear, gottenMonth, 1);
|
||||
var startTimestamp = Math.floor(gottenDateTime.getTime() / 60000) - gottenWeek * ccn_datetime_DAY1_SPAN;
|
||||
var endTimestamp = startTimestamp + ccn_datetime_DAY1_SPAN * 6 * 7 - 1;
|
||||
|
||||
ccn_calendar_calendar_listCache = new Array();
|
||||
var result = ccn_api_calendar_getFull(startTimestamp, endTimestamp);
|
||||
if (typeof(result) != 'undefined') {
|
||||
for(var index in result) {
|
||||
ccn_calendar_calendar_listCache[result[index][0]] = result[index];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// this function take responsibility to analyse event
|
||||
// call datetime function to resolve loop event
|
||||
// and split event if some event cross 2+ days
|
||||
function ccn_calendar_calendar_Analyse() {
|
||||
// first, we need construct ccn_calendar_calendar_displayCache
|
||||
ccn_calendar_calendar_displayCache = new Array();
|
||||
var gottenDateTime = ccn_datetimepicker_Get(1, false);
|
||||
var gottenYear = gottenDateTime.getFullYear();
|
||||
var gottenMonth = gottenDateTime.getMonth() + 1;
|
||||
var gottenWeek = ccn_datetime_DayOfWeek(gottenYear, gottenMonth, 1);
|
||||
var startTimestamp = Math.floor(gottenDateTime.getTime() / 60000) - gottenWeek * ccn_datetime_DAY1_SPAN;
|
||||
var endTimestamp = startTimestamp + ccn_datetime_DAY1_SPAN * 6 * 7 - 1;
|
||||
gottenDateTime.setTime(startTimestamp * 60000);
|
||||
for(var index = 0; index < 6 * 7; index++) {
|
||||
ccn_calendar_calendar_displayCache.push({
|
||||
month: gottenDateTime.getMonth() + 1,
|
||||
day: gottenDateTime.getDate(),
|
||||
dayOfWeek: gottenDateTime.getWeekday() + 1,
|
||||
subcalendar: "",
|
||||
isCurrentMonth: (gottenDateTime.getMonth() + 1) == gottenMonth,
|
||||
events: new Array()
|
||||
});
|
||||
gottenDateTime.setTime(gottenDateTime.getTime() + ccn_datetime_DAY1_SPAN * 60000);
|
||||
}
|
||||
|
||||
var mytimezone = -(new Date().getTimezoneOffset());
|
||||
// then analyse each event
|
||||
for(var index in ccn_calendar_calendar_listCache) {
|
||||
var item = ccn_calendar_calendar_listCache[index];
|
||||
var deserializedDescription = ccn_api_deserializeDescription(item[3]);
|
||||
|
||||
var minStartTimestamp = startTimestamp - (item[6] - item[5]);
|
||||
var result = ccn_datetime_ResolveLoopRules4Event(
|
||||
item[8],
|
||||
item[9] < minStartTimestamp ? minStartTimestamp : item[9],
|
||||
Math.min(item[10], endTimestamp),
|
||||
item[5],
|
||||
item[6],
|
||||
item[7],
|
||||
startTimestamp
|
||||
);
|
||||
if(typeof(result) != 'undefined') {
|
||||
for(var i in result) {
|
||||
var it = result[i];
|
||||
// try get event belong to which cell
|
||||
var eventDateTime = new Date(it[0] * 60000);
|
||||
var count = Math.floor((it[0] - startTimestamp) / ccn_datetime_DAY1_SPAN);
|
||||
var exitFlag = false;
|
||||
// then split event
|
||||
while(count < 6 * 7) {
|
||||
var eventItem = {
|
||||
uuid: item[0],
|
||||
belongTo: item[1],
|
||||
title: item[2],
|
||||
description: deserializedDescription.description,
|
||||
color: deserializedDescription.color,
|
||||
isVisible: true,
|
||||
isLocked: typeof(ccn_calendar_owned_displayCache[item[0]]) != 'undefined',
|
||||
loopText: ccn_datetime_ResolveLoopRules4Text(item[8], item[5], item[7]),
|
||||
timezoneWarning: mytimezone != item[7],
|
||||
start: eventDateTime.toLocaleTimeString(),
|
||||
end: undefined // filled in follwing code
|
||||
}
|
||||
eventDateTime.setHours(23, 59, 0, 0);
|
||||
if (it[1] <= Math.floor(eventDateTime.getTime() / 60000)) {
|
||||
exitFlag = true;
|
||||
eventDateTime.setTime(it[1] * 60000);
|
||||
}
|
||||
eventItem.end = eventDateTime.toLocaleTimeString();
|
||||
ccn_calendar_calendar_displayCache[count].events.push(eventItem);
|
||||
if (exitFlag) break;
|
||||
else eventDateTime.setMinutes(eventDateTime.getMinutes() + 1, 0, 0);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// just use produced ccn_calendar_calendar_displayCache
|
||||
// to re-generate ui
|
||||
function ccn_calendar_calendar_Render() {
|
||||
// todo: add / migrate subcalendar feature here
|
||||
|
||||
|
||||
// analyse visible data
|
||||
for(var i in ccn_calendar_calendar_displayCache) {
|
||||
for(var j in ccn_calendar_calendar_displayCache[i].events) {
|
||||
var gottenOwnedVisible = ccn_calendar_owned_displayCache[
|
||||
ccn_calendar_calendar_displayCache[i].events[j].belongTo
|
||||
];
|
||||
if (typeof(gottenOwnedVisible) == 'undefined') gottenOwnedVisible = false;
|
||||
var gottenSharedVisible = ccn_calendar_shared_displayCache[
|
||||
ccn_calendar_calendar_displayCache[i].events[j].belongTo
|
||||
];
|
||||
if (typeof(gottenSharedVisible) == 'undefined') gottenSharedVisible = false;
|
||||
|
||||
ccn_calendar_calendar_displayCache[i].events[j].isVisible = gottenOwnedVisible || gottenSharedVisible;
|
||||
}
|
||||
}
|
||||
|
||||
// just render them
|
||||
var listDOM = $('#ccn-calendar-scheduleList');
|
||||
listDOM.empty();
|
||||
listDOM.append(ccn_template_scheduleItem.render({renderdata: ccn_calendar_calendar_displayCache}));
|
||||
// link click event
|
||||
$('div.schedule-event-outter').click(ccn_calendar_calendar_ItemUpdate);
|
||||
|
||||
// all data has been alanysed, feedback to calendar body.
|
||||
var counter = 0;
|
||||
for(var i = 0; i < 6; i++) {
|
||||
for(var j = 0; j < 7; j++) {
|
||||
var item = ccn_calendar_calendar_displayCache[counter];
|
||||
var lenEvents = item.events.length;
|
||||
var eventsCounter = 0;
|
||||
|
||||
$('#ccn-calendarItem-' + i + '-' + j).attr('isCurrentMonth', item.isCurrentMonth ? 'true' : 'false');
|
||||
|
||||
$('#ccn-calendarItem-title-' + i + '-' + j).text(item.day);
|
||||
$('#ccn-calendarItem-desc-' + i + '-' + j).text(item.subcalendar);
|
||||
|
||||
|
||||
for(; eventsCounter < Math.min(lenEvents, 4); eventsCounter++) {
|
||||
$('#ccn-calendarItem-eventBox' + (eventsCounter + 1) + '-' + i + '-' + j)
|
||||
.css('background', item.events[eventsCounter].color)
|
||||
.attr('enableDisplay', 'true');
|
||||
}
|
||||
if (lenEvents > 4) {
|
||||
// more than 4 item, write number
|
||||
$('#ccn-calendarItem-task-' + i + '-' + j).text(
|
||||
$.i18n.prop('ccn-i18n-calendar-calendar-stripedEvents').format(lenEvents.toString())
|
||||
);
|
||||
} else {
|
||||
// otherwise, wipe out number
|
||||
$('#ccn-calendarItem-task-' + i + '-' + j).html(' ');
|
||||
// set others div are blank
|
||||
for(; eventsCounter < 4; eventsCounter++) {
|
||||
$('#ccn-calendarItem-eventBox' + (eventsCounter + 1) + '-' + i + '-' + j)
|
||||
.attr('enableDisplay', 'false');
|
||||
}
|
||||
}
|
||||
|
||||
counter++;
|
||||
}
|
||||
}
|
||||
|
||||
ccn_i18n_ApplyLanguage2Content(listDOM);
|
||||
}
|
||||
|
||||
function ccn_calendar_calendar_btnRefresh() {
|
||||
ccn_calendar_calendar_Refresh();
|
||||
ccn_calendar_calendar_Analyse();
|
||||
ccn_calendar_calendar_Render();
|
||||
}
|
||||
|
||||
function ccn_calendar_calendar_btnToday() {
|
||||
var nowtime = new Date();
|
||||
ccn_datetimepicker_Set(1, nowtime, false, ccn_datetimepicker_tabType.month);
|
||||
ccn_calendar_calendar_Refresh();
|
||||
ccn_calendar_calendar_Analyse();
|
||||
ccn_calendar_calendar_Render();
|
||||
}
|
||||
|
||||
function ccn_calendar_calendar_btnAdd() {
|
||||
window.location.href = '/web/eventAdd';
|
||||
}
|
||||
|
||||
function ccn_calendar_calendar_ItemUpdate() {
|
||||
var uuid = $(this).attr("uuid");
|
||||
window.location.href = '/web/eventUpdate/' + uuid;
|
||||
}
|
||||
|
||||
// ============================= collection
|
||||
|
||||
function ccn_calendar_collection_Refresh() {
|
||||
ccn_calendar_owned_displayCache = new Array();
|
||||
ccn_calendar_shared_displayCache = new Array();
|
||||
|
||||
// render shared
|
||||
var result = ccn_api_collection_getShared();
|
||||
var listDOM = $('#ccn-calendar-sharedList');
|
||||
listDOM.empty();
|
||||
var renderdata = {
|
||||
uuid: undefined,
|
||||
name: undefined,
|
||||
username: undefined
|
||||
}
|
||||
if (typeof(result) != 'undefined') {
|
||||
for(var index in result) {
|
||||
var item = result[index];
|
||||
renderdata.uuid = item[0];
|
||||
renderdata.name = item[1];
|
||||
renderdata.username = item[2];
|
||||
|
||||
listDOM.append(ccn_template_displaySharedItem.render(renderdata));
|
||||
|
||||
// change display
|
||||
var uuid = renderdata.uuid;
|
||||
ccn_calendar_shared_ChangeDisplayMode(uuid, true);
|
||||
|
||||
// push into display list
|
||||
ccn_calendar_shared_displayCache[uuid] = true;
|
||||
|
||||
// bind event
|
||||
$('#ccn-displaySharedItem-btnHide-' + uuid).click(ccn_calendar_shared_ItemSwitchDisplay);
|
||||
$('#ccn-displaySharedItem-btnShow-' + uuid).click(ccn_calendar_shared_ItemSwitchDisplay);
|
||||
}
|
||||
}
|
||||
|
||||
ccn_i18n_ApplyLanguage2Content(listDOM);
|
||||
|
||||
// render owned
|
||||
result = ccn_api_collection_getFullOwn();
|
||||
listDOM = $('#ccn-calendar-ownedList');
|
||||
listDOM.empty();
|
||||
renderdata = {
|
||||
uuid: undefined,
|
||||
name: undefined
|
||||
}
|
||||
if (typeof(result) != 'undefined') {
|
||||
for(var index in result) {
|
||||
var item = result[index];
|
||||
renderdata.uuid = item[0];
|
||||
renderdata.name = item[1];
|
||||
|
||||
// render
|
||||
listDOM.append(ccn_template_displayOwnedItem.render(renderdata));
|
||||
|
||||
// set mode
|
||||
var uuid = renderdata.uuid;
|
||||
ccn_calendar_owned_ChangeDisplayMode(uuid, true);
|
||||
|
||||
// push into display list
|
||||
ccn_calendar_owned_displayCache[uuid] = true;
|
||||
|
||||
// bind event
|
||||
$('#ccn-displayOwnedItem-btnHide-' + uuid).click(ccn_calendar_owned_ItemSwitchDisplay);
|
||||
$('#ccn-displayOwnedItem-btnShow-' + uuid).click(ccn_calendar_owned_ItemSwitchDisplay);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function ccn_calendar_owned_ItemSwitchDisplay() {
|
||||
var uuid = $(this).attr("uuid");
|
||||
ccn_calendar_owned_displayCache[uuid] = !(ccn_calendar_owned_displayCache[uuid]);
|
||||
ccn_calendar_owned_ChangeDisplayMode(uuid, ccn_calendar_owned_displayCache[uuid]);
|
||||
}
|
||||
|
||||
function ccn_calendar_shared_ItemSwitchDisplay() {
|
||||
var uuid = $(this).attr("uuid");
|
||||
ccn_calendar_shared_displayCache[uuid] = !(ccn_calendar_shared_displayCache[uuid]);
|
||||
ccn_calendar_shared_ChangeDisplayMode(uuid, ccn_calendar_shared_displayCache[uuid]);
|
||||
}
|
||||
|
||||
function ccn_calendar_shared_ChangeDisplayMode(uuid, isShow) {
|
||||
if (isShow) {
|
||||
$('#ccn-displaySharedItem-btnHide-' + uuid).show();
|
||||
$('#ccn-displaySharedItem-btnShow-' + uuid).hide();
|
||||
} else {
|
||||
$('#ccn-displaySharedItem-btnHide-' + uuid).hide();
|
||||
$('#ccn-displaySharedItem-btnShow-' + uuid).show();
|
||||
}
|
||||
}
|
||||
|
||||
function ccn_calendar_owned_ChangeDisplayMode(uuid, isShow) {
|
||||
if (isShow) {
|
||||
$('#ccn-displayOwnedItem-btnHide-' + uuid).show();
|
||||
$('#ccn-displayOwnedItem-btnShow-' + uuid).hide();
|
||||
} else {
|
||||
$('#ccn-displayOwnedItem-btnHide-' + uuid).hide();
|
||||
$('#ccn-displayOwnedItem-btnShow-' + uuid).show();
|
||||
}
|
||||
}
|
||||
288
frontend/static/js/page/collection.js
Normal file
288
frontend/static/js/page/collection.js
Normal file
@@ -0,0 +1,288 @@
|
||||
// 3 used cache list
|
||||
var ccn_collection_owned_listCache = [];
|
||||
var ccn_collection_sharing_listCache = [];
|
||||
|
||||
// current editing sharing collection
|
||||
var ccn_collection_sharing_editingOwned = undefined; // the uuid of owned collection
|
||||
|
||||
$(document).ready(function() {
|
||||
ccn_pages_currentPage = ccn_pages_enumPages.collection;
|
||||
|
||||
// template process
|
||||
ccn_template_Load();
|
||||
|
||||
// nav process
|
||||
ccn_headerNav_Insert();
|
||||
ccn_headerNav_BindEvents();
|
||||
ccn_headerNav_LoggedRefresh();
|
||||
|
||||
// messagebox process
|
||||
ccn_messagebox_Insert();
|
||||
ccn_messagebox_BindEvent();
|
||||
|
||||
// apply i18n
|
||||
ccn_i18n_LoadLanguage();
|
||||
ccn_i18n_ApplyLanguage();
|
||||
|
||||
//refresh once
|
||||
ccn_collection_owned_Refresh();
|
||||
|
||||
// bind event
|
||||
//$('#ccn-calendar-shared-btnRefresh').click(ccn_calendar_shared_Refresh);
|
||||
$('#ccn-collection-owned-btnAdd').click(ccn_collection_owned_Add);
|
||||
$('#ccn-collection-owned-btnRefresh').click(ccn_collection_owned_Refresh);
|
||||
$('#ccn-collection-sharing-btnAdd').click(ccn_collection_sharing_Add);
|
||||
$('#ccn-collection-sharing-btnRefresh').click(ccn_collection_sharing_Refresh);
|
||||
|
||||
});
|
||||
|
||||
|
||||
function ccn_collection_owned_Refresh() {
|
||||
ccn_collection_owned_listCache = new Array();
|
||||
ccn_collection_sharing_displayCache = new Array();
|
||||
|
||||
var result = ccn_api_collection_getFullOwn();
|
||||
if(typeof(result) != 'undefined') {
|
||||
for(var index in result) {
|
||||
ccn_collection_owned_listCache[result[index][0]] = result[index];
|
||||
}
|
||||
}
|
||||
|
||||
// render
|
||||
var listDOM = $('#ccn-collection-ownedList');
|
||||
listDOM.empty();
|
||||
for(var index in ccn_collection_owned_listCache) {
|
||||
ccn_collection_owned_RenderItem(
|
||||
ccn_collection_owned_listCache[index],
|
||||
listDOM
|
||||
);
|
||||
}
|
||||
|
||||
// also, order sharing list clean
|
||||
ccn_collection_sharing_editingOwned = undefined;
|
||||
ccn_collection_sharing_Refresh();
|
||||
}
|
||||
|
||||
function ccn_collection_owned_RenderItem(item, listDOM) {
|
||||
var renderdata = {
|
||||
uuid: item[0],
|
||||
name: item[1]
|
||||
}
|
||||
|
||||
// render
|
||||
listDOM.append(ccn_template_ownedItem.render(renderdata));
|
||||
|
||||
// set mode
|
||||
var uuid = renderdata.uuid;
|
||||
ccn_collection_owned_ChangeDisplayMode(uuid, false);
|
||||
|
||||
// bind event
|
||||
$('#ccn-ownedItem-btnEdit-' + uuid).click(ccn_collection_owned_ItemEdit);
|
||||
$('#ccn-ownedItem-btnDelete-' + uuid).click(ccn_collection_owned_ItemDelete);
|
||||
$('#ccn-ownedItem-btnShare-' + uuid).click(ccn_collection_owned_ItemShare);
|
||||
$('#ccn-ownedItem-btnUpdate-' + uuid).click(ccn_collection_owned_ItemUpdate);
|
||||
$('#ccn-ownedItem-btnCancelUpdate-' + uuid).click(ccn_collection_owned_ItemCancelUpdate);
|
||||
|
||||
}
|
||||
|
||||
function ccn_collection_owned_ChangeDisplayMode(uuid, isEdit) {
|
||||
if (isEdit) {
|
||||
$('#ccn-ownedItem-btnEdit-' + uuid).hide();
|
||||
$('#ccn-ownedItem-btnShare-' + uuid).hide();
|
||||
$('#ccn-ownedItem-btnDelete-' + uuid).hide();
|
||||
|
||||
$('#ccn-ownedItem-btnUpdate-' + uuid).show();
|
||||
$('#ccn-ownedItem-btnCancelUpdate-' + uuid).show();
|
||||
|
||||
$('#ccn-ownedItem-textName-' + uuid).hide();
|
||||
$('#ccn-ownedItem-boxName-' + uuid).show();
|
||||
} else {
|
||||
$('#ccn-ownedItem-btnEdit-' + uuid).show();
|
||||
$('#ccn-ownedItem-btnShare-' + uuid).show();
|
||||
$('#ccn-ownedItem-btnDelete-' + uuid).show();
|
||||
|
||||
$('#ccn-ownedItem-btnUpdate-' + uuid).hide();
|
||||
$('#ccn-ownedItem-btnCancelUpdate-' + uuid).hide();
|
||||
|
||||
$('#ccn-ownedItem-textName-' + uuid).show();
|
||||
$('#ccn-ownedItem-boxName-' + uuid).hide();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
function ccn_collection_sharing_Refresh() {
|
||||
ccn_collection_sharing_listCache = new Array();
|
||||
|
||||
if (typeof(ccn_collection_sharing_editingOwned) != 'undefined') {
|
||||
var result = ccn_api_collection_getSharing(ccn_collection_sharing_editingOwned);
|
||||
if (typeof(result) != 'undefined') {
|
||||
for(var index in result) {
|
||||
ccn_collection_sharing_listCache[index] = result[index];
|
||||
// also, sharingTarget don't have uuid, use index instead
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// update editing text
|
||||
$('#ccn-collection-sharing-sharingEditing').text(
|
||||
typeof(ccn_collection_sharing_editingOwned) == 'undefined' ?
|
||||
'' :
|
||||
ccn_collection_owned_listCache[ccn_collection_sharing_editingOwned][1]
|
||||
);
|
||||
|
||||
// if editing is undefined, hide container
|
||||
if (typeof(ccn_collection_sharing_editingOwned) == 'undefined')
|
||||
$('#ccn-collection-sharing-container').hide();
|
||||
else
|
||||
$('#ccn-collection-sharing-container').show();
|
||||
|
||||
|
||||
var listDOM = $('#ccn-collection-sharingList');
|
||||
listDOM.empty();
|
||||
for(var index in ccn_collection_sharing_listCache) {
|
||||
ccn_collection_sharing_RenderItem(
|
||||
ccn_collection_sharing_listCache[index],
|
||||
index,
|
||||
listDOM
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
function ccn_collection_sharing_RenderItem(item, index, listDOM) {
|
||||
var renderdata = {
|
||||
uuid: index,
|
||||
username: item
|
||||
}
|
||||
|
||||
// render
|
||||
listDOM.append(ccn_template_sharingItem.render(renderdata));
|
||||
|
||||
// bind event
|
||||
var uuid = index;
|
||||
$("#ccn-sharingItem-btnDelete-" + uuid).click(ccn_collection_sharing_ItemDelete);
|
||||
}
|
||||
|
||||
// ========================= input operation
|
||||
|
||||
function ccn_collection_owned_Add() {
|
||||
var newname = $('#ccn-collection-owned-inputAdd').val();
|
||||
if (newname == "") return;
|
||||
|
||||
var result = ccn_api_collection_addOwn(newname);
|
||||
if (typeof(result) == 'undefined') ccn_messagebox_Show($.i18n.prop("ccn-i18n-js-fail-add"));
|
||||
else {
|
||||
// second get. get detail
|
||||
result = ccn_api_collection_getDetailOwn(result);
|
||||
|
||||
if (typeof(result) == 'undefined') ccn_messagebox_Show($.i18n.prop("ccn-i18n-js-fail-get"));
|
||||
else {
|
||||
// render
|
||||
ccn_collection_owned_listCache[result[0]] = result;
|
||||
var listDOM = $('#ccn-collection-ownedList');
|
||||
ccn_collection_owned_RenderItem(result, listDOM);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function ccn_collection_owned_ItemEdit() {
|
||||
var uuid = $(this).attr("uuid");
|
||||
|
||||
// preset inputbox
|
||||
$('#ccn-ownedItem-inputName-' + uuid).val(
|
||||
ccn_collection_owned_listCache[uuid][1]
|
||||
);
|
||||
|
||||
// switch to edit mode
|
||||
ccn_collection_owned_ChangeDisplayMode(uuid, true);
|
||||
}
|
||||
|
||||
function ccn_collection_owned_ItemDelete() {
|
||||
var uuid = $(this).attr("uuid");
|
||||
|
||||
var result = ccn_api_collection_deleteOwn(
|
||||
uuid,
|
||||
ccn_collection_owned_listCache[uuid][2]
|
||||
);
|
||||
if (!result) ccn_messagebox_Show($.i18n.prop("ccn-i18n-js-fail-delete"));
|
||||
else {
|
||||
$('#ccn-ownedItem-' + uuid).remove();
|
||||
|
||||
// also, we should notice sharing target, and try clean it
|
||||
if (ccn_collection_sharing_editingOwned == uuid) {
|
||||
ccn_collection_sharing_editingOwned = undefined;
|
||||
ccn_collection_sharing_Refresh();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function ccn_collection_owned_ItemUpdate() {
|
||||
var uuid = $(this).attr("uuid");
|
||||
var newname = $('#ccn-ownedItem-inputName-' + uuid).val();
|
||||
|
||||
var result = ccn_api_collection_updateOwn(uuid, newname, ccn_collection_owned_listCache[uuid][2]);
|
||||
if (typeof(result) == 'undefined') ccn_messagebox_Show($.i18n.prop("ccn-i18n-js-fail-update"));
|
||||
else {
|
||||
// update last change
|
||||
ccn_collection_owned_listCache[uuid][2] = result;
|
||||
ccn_collection_owned_listCache[uuid][1] = newname;
|
||||
// update elements
|
||||
$('#ccn-ownedItem-textName-' + uuid).text(newname);
|
||||
// if editing, update sharing target
|
||||
if (ccn_collection_sharing_editingOwned == uuid)
|
||||
ccn_collection_sharing_Refresh();
|
||||
// back to normal mode
|
||||
ccn_collection_owned_ChangeDisplayMode(uuid, false);
|
||||
}
|
||||
}
|
||||
|
||||
function ccn_collection_owned_ItemCancelUpdate() {
|
||||
var uuid = $(this).attr("uuid");
|
||||
ccn_collection_owned_ChangeDisplayMode(uuid, false);
|
||||
}
|
||||
|
||||
function ccn_collection_owned_ItemShare() {
|
||||
var uuid = $(this).attr("uuid");
|
||||
ccn_collection_sharing_editingOwned = uuid;
|
||||
ccn_collection_sharing_Refresh();
|
||||
}
|
||||
|
||||
|
||||
function ccn_collection_sharing_Add() {
|
||||
var newusername = $('#ccn-collection-sharing-inputAdd').val();
|
||||
if (newusername == "" || typeof(ccn_collection_sharing_editingOwned) == 'undefined') return;
|
||||
|
||||
var result = ccn_api_collection_addSharing(
|
||||
ccn_collection_sharing_editingOwned,
|
||||
newusername,
|
||||
ccn_collection_owned_listCache[ccn_collection_sharing_editingOwned][2]
|
||||
);
|
||||
if (typeof(result) == 'undefined') ccn_messagebox_Show($.i18n.prop("ccn-i18n-js-fail-add"));
|
||||
else {
|
||||
// add new item
|
||||
var index = ccn_collection_sharing_listCache.push(newusername) - 1;
|
||||
var listDOM = $('#ccn-collection-sharingList');
|
||||
ccn_collection_sharing_RenderItem(newusername, index, listDOM);
|
||||
// update last change
|
||||
ccn_collection_owned_listCache[ccn_collection_sharing_editingOwned][2] = result;
|
||||
}
|
||||
}
|
||||
|
||||
function ccn_collection_sharing_ItemDelete() {
|
||||
var uuid = $(this).attr("uuid");
|
||||
var username = ccn_collection_sharing_listCache[uuid];
|
||||
|
||||
var result = ccn_api_collection_deleteSharing(
|
||||
ccn_collection_sharing_editingOwned,
|
||||
username,
|
||||
ccn_collection_owned_listCache[ccn_collection_sharing_editingOwned][2]
|
||||
);
|
||||
if (typeof(result) == 'undefined') ccn_messagebox_Show($.i18n.prop("ccn-i18n-js-fail-delete"));
|
||||
else {
|
||||
// remove item in ui
|
||||
$('#ccn-sharingItem-' + uuid).remove();
|
||||
// update last change
|
||||
ccn_collection_owned_listCache[ccn_collection_sharing_editingOwned][2] = result;
|
||||
}
|
||||
}
|
||||
|
||||
447
frontend/static/js/page/event.js
Normal file
447
frontend/static/js/page/event.js
Normal file
@@ -0,0 +1,447 @@
|
||||
// if it is undefined, current mode is add
|
||||
// or it is the detail data gotten from api
|
||||
var ccn_event_editingEvent = undefined;
|
||||
var ccn_event_collectionCache = [];
|
||||
|
||||
$(document).ready(function() {
|
||||
ccn_pages_currentPage = ccn_pages_enumPages.event;
|
||||
|
||||
// template process
|
||||
ccn_template_Load();
|
||||
|
||||
// nav process
|
||||
ccn_headerNav_Insert();
|
||||
ccn_headerNav_BindEvents();
|
||||
ccn_headerNav_LoggedRefresh();
|
||||
|
||||
// messagebox process
|
||||
ccn_messagebox_Insert();
|
||||
ccn_messagebox_BindEvent();
|
||||
|
||||
// init datetimepicker
|
||||
ccn_datetimepicker_Insert();
|
||||
|
||||
// apply i18n
|
||||
ccn_i18n_LoadLanguage();
|
||||
ccn_i18n_ApplyLanguage();
|
||||
|
||||
// bind event
|
||||
$('input[type=radio][name=loop-method]').click(ccn_event_RefreshRadioDiaplay);
|
||||
$('input[type=radio][name=loop-end]').click(ccn_event_RefreshRadioDiaplay);
|
||||
|
||||
$('#ccn-event-btnSubmit').click(ccn_event_btnSubmit);
|
||||
$('#ccn-event-btnCancel').click(ccn_event_btnCancel);
|
||||
$('#ccn-event-btnSpot').click(ccn_event_btnSpot);
|
||||
$('#ccn-event-btnFullDay').click(ccn_event_btnFullDay);
|
||||
$('#ccn-event-btnStartDateTime')
|
||||
.prop('funcs', {callback: function() {
|
||||
ccn_event_UpdateDateTimePickerButton(1);
|
||||
ccn_event_RefreshLoopMonthType();
|
||||
}})
|
||||
.click(ccn_event_btnDateTimePicker);
|
||||
$('#ccn-event-btnEndDateTime')
|
||||
.prop('funcs', {callback: function() {ccn_event_UpdateDateTimePickerButton(2);}})
|
||||
.click(ccn_event_btnDateTimePicker);
|
||||
$('#ccn-event-btnLoopStopDateTime')
|
||||
.prop('funcs', {callback: function() {ccn_event_UpdateDateTimePickerButton(3);}})
|
||||
.click(ccn_event_btnDateTimePicker);
|
||||
|
||||
// init form
|
||||
ccn_event_Init();
|
||||
|
||||
// refresh once
|
||||
ccn_event_RefreshRadioDiaplay();
|
||||
ccn_event_RefreshLoopMonthType();
|
||||
});
|
||||
|
||||
|
||||
function ccn_event_Init() {
|
||||
// we need init some elements first
|
||||
|
||||
// we need all radio and checkbox's checked is false, not undefined.
|
||||
$('input[type=radio]').prop("checked", false);
|
||||
$('input[type=checkbox]').prop("checked", false);
|
||||
|
||||
// init span picker
|
||||
$('.spanpicker').attr('max', 100)
|
||||
.attr('min', 1)
|
||||
.attr('step', 1)
|
||||
.val(1);
|
||||
|
||||
// in there, we need get uuid from meta
|
||||
var uuid = $('meta[name=uuid]').attr('content');
|
||||
if (uuid != "")
|
||||
ccn_event_editingEvent = ccn_api_calendar_getDetail(uuid);
|
||||
// if ccn_event_editingEvent is undefined, init following content with add mode
|
||||
// otherwise, init as update mode
|
||||
var isAdd = typeof(ccn_event_editingEvent) == 'undefined';
|
||||
var deserializeDescription = isAdd ? undefined : ccn_api_deserializeDescription(ccn_event_editingEvent[3]);
|
||||
|
||||
// init title and description
|
||||
$('#ccn-event-inputTitle').val(
|
||||
isAdd ? '' : ccn_event_editingEvent[2]
|
||||
);
|
||||
$('#ccn-event-inputDescription').val(
|
||||
isAdd ? '' : deserializeDescription.description
|
||||
);
|
||||
$('#ccn-event-inputColor').val(
|
||||
isAdd ? DefaultColor : deserializeDescription.color
|
||||
);
|
||||
|
||||
// init collection picker, first we need query data
|
||||
// and render it
|
||||
var collectionDOM = $('#ccn-event-inputCollection');
|
||||
collectionDOM.empty();
|
||||
ccn_event_collectionCache = new Array();
|
||||
var result = ccn_api_collection_getFullOwn();
|
||||
if (typeof(result) != 'undefined') {
|
||||
var renderdata = {
|
||||
val: undefined,
|
||||
name: undefined
|
||||
}
|
||||
|
||||
for (var index in result) {
|
||||
var item = result[index];
|
||||
ccn_event_collectionCache.push(item[0])
|
||||
renderdata.val = item[0];
|
||||
renderdata.name = item[1];
|
||||
collectionDOM.append(
|
||||
ccn_template_optionItem.render(renderdata)
|
||||
);
|
||||
}
|
||||
}
|
||||
// in add mode, set as -1, otherwise try to match original data
|
||||
// indexOf will return -1 if no matched item
|
||||
collectionDOM.val(isAdd ? '' : ccn_event_editingEvent[1]);
|
||||
|
||||
// init start and end datetime
|
||||
if (isAdd) {
|
||||
// in add mode, init 2 datetime picker as close hours based time.
|
||||
var currentDateTime = new Date();
|
||||
currentDateTime.setMilliseconds(0);
|
||||
currentDateTime.setSeconds(0);
|
||||
currentDateTime.setMinutes(0);
|
||||
ccn_datetimepicker_Set(1, currentDateTime, false);
|
||||
|
||||
// time span is 2 hours
|
||||
currentDateTime.setHours(currentDateTime.getHours() + 2);
|
||||
ccn_datetimepicker_Set(2, currentDateTime, false);
|
||||
} else {
|
||||
// in update mode, match it with original data
|
||||
var originalDateTime = new Date((ccn_event_editingEvent[5] + ccn_event_editingEvent[7]) * 60000);
|
||||
ccn_datetimepicker_Set(1, originalDateTime, true);
|
||||
|
||||
originalDateTime = new Date((ccn_event_editingEvent[6] + ccn_event_editingEvent[7]) * 60000);
|
||||
ccn_datetimepicker_Set(2, originalDateTime, true);
|
||||
}
|
||||
|
||||
// setup timezone here
|
||||
// to prevent some error
|
||||
// because following isAdd will change its meaning
|
||||
$('#ccn-event-timezone-radioKeep').prop('checked', true); // give a default value
|
||||
var nowtime = new Date();
|
||||
SmarterShowHide(
|
||||
(!isAdd) && (-nowtime.getTimezoneOffset()) != ccn_event_editingEvent[7],
|
||||
$('#ccn-event-boxTimezone')
|
||||
);
|
||||
|
||||
// ========================
|
||||
// now we need resolve loop rules and set related data
|
||||
if (!isAdd) {
|
||||
data = ccn_datetime_ResolveLoopRules4UI(ccn_event_editingEvent[8]);
|
||||
if (typeof(data) == 'undefined') isAdd = true; // init as add
|
||||
}
|
||||
|
||||
// give some value with a default value
|
||||
$('#ccn-event-loopMonth-radioA').prop('checked', true);
|
||||
$('#ccn-event-loopWeek-check' + (nowtime.getWeekday() + 1)).prop('checked', true);
|
||||
$('#ccn-event-strictMode-radioStrict').prop('checked', true);
|
||||
|
||||
// real process
|
||||
if (isAdd) {
|
||||
$('#ccn-event-radioLoopNever').prop('checked', true);
|
||||
} else {
|
||||
switch(data[0][0]) {
|
||||
case 0:
|
||||
$('#ccn-event-radioLoopYear').prop('checked', true);
|
||||
$('#ccn-event-loopYear-inputSpan').val(data[0][2]);
|
||||
if (data[0][1]) $('#ccn-event-strictMode-radioStrict').prop('checked', true);
|
||||
else $('#ccn-event-strictMode-radioRough').prop('checked', true);
|
||||
break;
|
||||
case 1:
|
||||
$('#ccn-event-radioLoopMonth').prop('checked', true);
|
||||
$('#ccn-event-loopMonth-inputSpan').val(data[0][3]);
|
||||
$('#ccn-event-loopMonth-radio' + data[0][2]).prop('checked', true);
|
||||
if (data[0][1]) $('#ccn-event-strictMode-radioStrict').prop('checked', true);
|
||||
else $('#ccn-event-strictMode-radioRough').prop('checked', true);
|
||||
break;
|
||||
case 2:
|
||||
$('#ccn-event-radioLoopWeek').prop('checked', true);
|
||||
$('#ccn-event-loopWeek-inputSpan').val(data[0][8]);
|
||||
for(var i = 1; i <= 7; i++) {
|
||||
$('#ccn-event-loopWeek-check' + i).prop('checked', data[0][i]);
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
$('#ccn-event-radioLoopDay').prop('checked', true);
|
||||
$('#ccn-event-loopDay-inputSpan').val(data[0][1]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// give some item a default value
|
||||
ccn_datetimepicker_Set(3, nowtime, false);
|
||||
|
||||
if (isAdd) {
|
||||
$('#ccn-event-loopStop-radioForever').prop('checked', true);
|
||||
} else {
|
||||
switch(data[1][0]) {
|
||||
case 0:
|
||||
$('#ccn-event-loopStop-radioForever').prop('checked', true);
|
||||
break;
|
||||
case 1:
|
||||
$('#ccn-event-loopStop-radioDateTime').prop('checked', true);
|
||||
var stopDatetime = new Date((data[1][1] + ccn_event_editingEvent[7]) * 60000);
|
||||
ccn_datetimepicker_Set(3, stopDatetime, true);
|
||||
break;
|
||||
case 2:
|
||||
$('#ccn-event-loopStop-radioTimes').prop('checked', true);
|
||||
$('#ccn-event-loopStop-inputTimes').val(data[1][1]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// refresh some ui element according to form options
|
||||
function ccn_event_RefreshRadioDiaplay() {
|
||||
// loop method
|
||||
// note: no loop control loop stop's display
|
||||
// note: year and month loop also control strict mode display
|
||||
SmarterShowHide(!$('#ccn-event-radioLoopNever').prop('checked'), $('#ccn-event-boxLoopStop'));
|
||||
|
||||
SmarterShowHide($('#ccn-event-radioLoopDay').prop('checked'), $('#ccn-event-boxLoopDay'));
|
||||
SmarterShowHide($('#ccn-event-radioLoopWeek').prop('checked'), $('#ccn-event-boxLoopWeek'));
|
||||
SmarterShowHide($('#ccn-event-radioLoopMonth').prop('checked'), $('#ccn-event-boxLoopMonth'));
|
||||
SmarterShowHide($('#ccn-event-radioLoopYear').prop('checked'), $('#ccn-event-boxLoopYear'));
|
||||
|
||||
SmarterShowHide(
|
||||
$('#ccn-event-radioLoopMonth').prop('checked') || $('#ccn-event-radioLoopYear').prop('checked'),
|
||||
$('#ccn-event-boxStrictMode')
|
||||
);
|
||||
|
||||
// loop stop
|
||||
SmarterShowHide($('#ccn-event-loopStop-radioForever').prop('checked'), undefined);
|
||||
SmarterShowHide($('#ccn-event-loopStop-radioDateTime').prop('checked'), $('#ccn-event-boxLoopStopDateTime'));
|
||||
SmarterShowHide($('#ccn-event-loopStop-radioTimes').prop('checked'), $('#ccn-event-boxLoopStopTimes'));
|
||||
|
||||
}
|
||||
|
||||
function ccn_event_RefreshLoopMonthType() {
|
||||
var picker = ccn_datetimepicker_Get(1, false);
|
||||
var data = ccn_datetime_GetDayInMonth(picker.getFullYear(), picker.getMonth() + 1, picker.getDate());
|
||||
|
||||
$('#ccn-event-loopMonth-textA').text($.i18n.prop('ccn-i18n-event-loopWeek-optionA').format(data[0]));
|
||||
$('#ccn-event-loopMonth-textB').text($.i18n.prop('ccn-i18n-event-loopWeek-optionB').format(data[1]));
|
||||
$('#ccn-event-loopMonth-textC').text($.i18n.prop('ccn-i18n-event-loopWeek-optionC').format(data[2], data[3] + 1));
|
||||
$('#ccn-event-loopMonth-textD').text($.i18n.prop('ccn-i18n-event-loopWeek-optionD').format(data[4], data[5] + 1));
|
||||
}
|
||||
|
||||
function ccn_event_UpdateDateTimePickerButton(index) {
|
||||
switch(index) {
|
||||
case 1:
|
||||
$('#ccn-event-btnStartDateTime-text').text(
|
||||
ccn_datetimepicker_Get(1, false).toLocaleString()
|
||||
);
|
||||
break;
|
||||
case 2:
|
||||
$('#ccn-event-btnEndDateTime-text').text(
|
||||
ccn_datetimepicker_Get(2, false).toLocaleString()
|
||||
);
|
||||
break;
|
||||
case 3:
|
||||
$('#ccn-event-btnLoopStopDateTime-text').text(
|
||||
ccn_datetimepicker_Get(3, false).toLocaleDateString()
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// return undefined to indicate an error
|
||||
// or
|
||||
// [belongTo, title, description, eventDateTimeStart, eventDateTimeEnd, timezoneOffset, loopRules]
|
||||
function ccn_event_GetForm() {
|
||||
// basic
|
||||
var title = $('#ccn-event-inputTitle').val();
|
||||
if (title == '') return undefined;
|
||||
var description = $('#ccn-event-inputDescription').val();
|
||||
if (description == '') return undefined;
|
||||
var color = $('#ccn-event-inputColor').val();
|
||||
if (color == '') return undefined;
|
||||
var belongTo = $('#ccn-event-inputCollection').val();
|
||||
if (belongTo == null) return undefined; // if no selected item, val return null, not undefined
|
||||
|
||||
var isAdd = typeof(ccn_event_editingEvent) == 'undefined';
|
||||
var keepTimezone = $('#ccn-event-timezone-radioKeep').prop('checked');
|
||||
var isStrict = $('#ccn-event-strictMode-radioStrict').prop('checked');
|
||||
|
||||
// time
|
||||
var eventDateTimeStart = undefined;
|
||||
var eventDateTimeEnd = undefined;
|
||||
var timezoneOffset = undefined;
|
||||
if ((!isAdd) && (!keepTimezone)) {
|
||||
// get datetime as utc, then minus original timezone to get unix timestamp
|
||||
timezoneOffset = ccn_event_editingEvent[7]; // keep timezone
|
||||
eventDateTimeStart = Math.floor(ccn_datetimepicker_Get(1, true).getTime() / 60000) - timezoneOffset;
|
||||
eventDateTimeEnd = Math.floor(ccn_datetimepicker_Get(2, true).getTime() / 60000) - timezoneOffset;
|
||||
} else {
|
||||
// use my timezone, resolve presented data as my local time
|
||||
var cache = ccn_datetimepicker_Get(1, false);
|
||||
timezoneOffset = -cache.getTimezoneOffset();
|
||||
eventDateTimeStart = Math.floor(cache.getTime() / 60000);
|
||||
eventDateTimeEnd = Math.floor(ccn_datetimepicker_Get(2, false).getTime() / 60000);
|
||||
}
|
||||
|
||||
// loopRules
|
||||
var loopRules = undefined;
|
||||
if ($('#ccn-event-radioLoopNever').prop('checked')) {
|
||||
loopRules = "";
|
||||
} else if ($('#ccn-event-radioLoopDay').prop('checked')) {
|
||||
loopRules = "D{0}".format($('#ccn-event-loopDay-inputSpan').val());
|
||||
} else if ($('#ccn-event-radioLoopWeek').prop('checked')) {
|
||||
var cache = ""
|
||||
for(var i = 1; i < 8; i++)
|
||||
cache += $('#ccn-event-loopWeek-check' + i).prop('checked') ? 'T' : 'F';
|
||||
loopRules = 'W{0}{1}'.format(
|
||||
cache,
|
||||
$('#ccn-event-loopWeek-inputSpan').val()
|
||||
);
|
||||
} else if ($('#ccn-event-radioLoopMonth').prop('checked')) {
|
||||
var cache = undefined;
|
||||
if ($('#ccn-event-loopMonth-radioA').prop('checked')) cache='A';
|
||||
else if ($('#ccn-event-loopMonth-radioB').prop('checked')) cache='B';
|
||||
else if ($('#ccn-event-loopMonth-radioC').prop('checked')) cache='C';
|
||||
else if ($('#ccn-event-loopMonth-radioD').prop('checked')) cache='D';
|
||||
else return undefined;
|
||||
|
||||
loopRules = "M{0}{1}{2}".format(
|
||||
isStrict ? "S" : "R",
|
||||
cache,
|
||||
$('#ccn-event-loopMonth-inputSpan').val()
|
||||
);
|
||||
} else if ($('#ccn-event-radioLoopYear').prop('checked')) {
|
||||
loopRules = "Y{0}{1}".format(
|
||||
isStrict ? "S" : "R",
|
||||
$('#ccn-event-loopYear-inputSpan').val()
|
||||
);
|
||||
}
|
||||
|
||||
// no need to process stop if this is not a loop event
|
||||
if (loopRules != "") {
|
||||
loopRules += '-';
|
||||
if ($('#ccn-event-loopStop-radioForever').prop('checked')) {
|
||||
loopRules += 'F';
|
||||
} else if ($('#ccn-event-loopStop-radioDateTime').prop('checked')) {
|
||||
var timestamp = undefined;
|
||||
if ((!isAdd) && (!keepTimezone)) {
|
||||
// keep timezone
|
||||
var cache = ccn_datetimepicker_Get(3, true);
|
||||
cache.setUTCHours(23);
|
||||
cache.setUTCMinutes(59);
|
||||
timestamp = Math.floor(cache.getTime() / 60000) - timezoneOffset;
|
||||
} else {
|
||||
// use my timezone
|
||||
timestamp = Math.floor(ccn_datetimepicker_Get(3, false).getTime() / 60000);
|
||||
}
|
||||
|
||||
loopRules += 'D{0}'.format(timestamp);
|
||||
} else if ($('#ccn-event-loopStop-radioTimes').prop('checked')) {
|
||||
loopRules += 'T{0}'.format($('#ccn-event-loopStop-inputTimes').val());
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
belongTo,
|
||||
title,
|
||||
ccn_api_serializeDescription(
|
||||
description,
|
||||
color
|
||||
),
|
||||
eventDateTimeStart,
|
||||
eventDateTimeEnd,
|
||||
timezoneOffset,
|
||||
loopRules
|
||||
];
|
||||
}
|
||||
|
||||
function ccn_event_btnSpot() {
|
||||
var datetime = ccn_datetimepicker_Get(1, false);
|
||||
datetime.setMinutes(datetime.getMinutes() + 1);
|
||||
ccn_datetimepicker_Set(2, datetime, false);
|
||||
}
|
||||
|
||||
function ccn_event_btnFullDay() {
|
||||
var datetime = ccn_datetimepicker_Get(1, false);
|
||||
datetime.setMinutes(0);
|
||||
datetime.setHours(0);
|
||||
ccn_datetimepicker_Set(1, datetime, false);
|
||||
datetime.setMinutes(59);
|
||||
datetime.setHours(23);
|
||||
ccn_datetimepicker_Set(2, datetime, false);
|
||||
}
|
||||
|
||||
function ccn_event_btnDateTimePicker() {
|
||||
switch(parseInt($(this).attr('datetimepicker'))) {
|
||||
case 1:
|
||||
ccn_datetimepicker_Modal(ccn_datetimepicker_tabType.minute, 1, false);
|
||||
break;
|
||||
case 2:
|
||||
ccn_datetimepicker_Modal(ccn_datetimepicker_tabType.minute, 2, false);
|
||||
break;
|
||||
case 3:
|
||||
ccn_datetimepicker_Modal(ccn_datetimepicker_tabType.day, 3, false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function ccn_event_btnCancel() {
|
||||
window.location.href = '/web/calendar';
|
||||
}
|
||||
|
||||
function ccn_event_btnSubmit() {
|
||||
var submitData = ccn_event_GetForm();
|
||||
if (typeof(submitData) == 'undefined') {
|
||||
ccn_messagebox_Show($.i18n.prop("ccn-i18n-js-fail-form"));
|
||||
return;
|
||||
}
|
||||
|
||||
var isAdd = typeof(ccn_event_editingEvent) == 'undefined';
|
||||
if (isAdd) {
|
||||
var result = ccn_api_calendar_add(
|
||||
submitData[0],
|
||||
submitData[1],
|
||||
submitData[2],
|
||||
submitData[3],
|
||||
submitData[4],
|
||||
submitData[6],
|
||||
submitData[5]
|
||||
);
|
||||
if (typeof(result) == 'undefined') ccn_messagebox_Show($.i18n.prop("ccn-i18n-js-fail-add"));
|
||||
else window.location.href = '/web/calendar';
|
||||
} else {
|
||||
var result = ccn_api_calendar_update(
|
||||
ccn_event_editingEvent[0],
|
||||
ccn_event_editingEvent[1] == submitData[0] ? undefined : submitData[0],
|
||||
ccn_event_editingEvent[2] == submitData[1] ? undefined : submitData[1],
|
||||
ccn_event_editingEvent[3] == submitData[2] ? undefined : submitData[2],
|
||||
ccn_event_editingEvent[5] == submitData[3] ? undefined : submitData[3],
|
||||
ccn_event_editingEvent[6] == submitData[4] ? undefined : submitData[4],
|
||||
ccn_event_editingEvent[8] == submitData[6] ? undefined : submitData[6],
|
||||
ccn_event_editingEvent[7] == submitData[5] ? undefined : submitData[5],
|
||||
ccn_event_editingEvent[4]
|
||||
);
|
||||
if (typeof(result) == 'undefined') ccn_messagebox_Show($.i18n.prop("ccn-i18n-js-fail-update"));
|
||||
else window.location.href = '/web/calendar';
|
||||
}
|
||||
}
|
||||
|
||||
19
frontend/static/js/page/home.js
Normal file
19
frontend/static/js/page/home.js
Normal file
@@ -0,0 +1,19 @@
|
||||
$(document).ready(function() {
|
||||
ccn_pages_currentPage = ccn_pages_enumPages.home;
|
||||
|
||||
// template process
|
||||
ccn_template_Load();
|
||||
|
||||
// nav process
|
||||
ccn_headerNav_Insert();
|
||||
ccn_headerNav_BindEvents();
|
||||
ccn_headerNav_LoggedRefresh();
|
||||
|
||||
// messagebox process
|
||||
ccn_messagebox_Insert();
|
||||
ccn_messagebox_BindEvent();
|
||||
|
||||
// apply i18n
|
||||
ccn_i18n_LoadLanguage();
|
||||
ccn_i18n_ApplyLanguage();
|
||||
});
|
||||
58
frontend/static/js/page/login.js
Normal file
58
frontend/static/js/page/login.js
Normal file
@@ -0,0 +1,58 @@
|
||||
$(document).ready(function() {
|
||||
ccn_pages_currentPage = ccn_pages_enumPages.login;
|
||||
|
||||
// template process
|
||||
ccn_template_Load();
|
||||
|
||||
// nav process
|
||||
ccn_headerNav_Insert();
|
||||
ccn_headerNav_BindEvents();
|
||||
ccn_headerNav_LoggedRefresh();
|
||||
|
||||
// messagebox process
|
||||
ccn_messagebox_Insert();
|
||||
ccn_messagebox_BindEvent();
|
||||
|
||||
// apply i18n
|
||||
ccn_i18n_LoadLanguage();
|
||||
ccn_i18n_ApplyLanguage();
|
||||
|
||||
// bind login event
|
||||
$("#ccn-login-form-login").click(ccn_login_startLogin);
|
||||
});
|
||||
|
||||
function ccn_login_startLogin() {
|
||||
// disable all ui first
|
||||
$("#ccn-login-form-login").attr("disabled",true);
|
||||
$("#ccn-login-form-username").attr("disabled",true);
|
||||
$("#ccn-login-form-password").attr("disabled",true);
|
||||
|
||||
// get form data
|
||||
username = $("#ccn-login-form-username").val();
|
||||
password = $("#ccn-login-form-password").val();
|
||||
|
||||
/*
|
||||
// try get salt
|
||||
if (ccn_api_common_salt(username)) {
|
||||
// continue login
|
||||
if (ccn_api_common_login(username, password)) {
|
||||
// ok, logged
|
||||
// jump into home page again
|
||||
window.location.href = '/web/home';
|
||||
|
||||
} else ccn_messagebox_Show($.i18n.prop("ccn-i18n-js-fail-login"));
|
||||
} else ccn_messagebox_Show($.i18n.prop("ccn-i18n-js-fail-login"));
|
||||
*/
|
||||
if (ccn_api_common_webLogin(username, password)) {
|
||||
// ok, logged
|
||||
// jump into home page again
|
||||
window.location.href = '/web/home';
|
||||
return;
|
||||
|
||||
} else ccn_messagebox_Show($.i18n.prop("ccn-i18n-js-fail-login"));
|
||||
|
||||
// retore ui
|
||||
$("#ccn-login-form-login").removeAttr("disabled");
|
||||
$("#ccn-login-form-username").removeAttr("disabled");
|
||||
$("#ccn-login-form-password").removeAttr("disabled");
|
||||
}
|
||||
190
frontend/static/js/page/todo.js
Normal file
190
frontend/static/js/page/todo.js
Normal file
@@ -0,0 +1,190 @@
|
||||
var ccn_todo_todoListCache = [];
|
||||
|
||||
$(document).ready(function() {
|
||||
ccn_pages_currentPage = ccn_pages_enumPages.todo;
|
||||
|
||||
// template process
|
||||
ccn_template_Load();
|
||||
|
||||
// nav process
|
||||
ccn_headerNav_Insert();
|
||||
ccn_headerNav_BindEvents();
|
||||
ccn_headerNav_LoggedRefresh();
|
||||
|
||||
// messagebox process
|
||||
ccn_messagebox_Insert();
|
||||
ccn_messagebox_BindEvent();
|
||||
|
||||
// apply i18n
|
||||
ccn_i18n_LoadLanguage();
|
||||
ccn_i18n_ApplyLanguage();
|
||||
|
||||
// refresh once
|
||||
ccn_todo_Refresh();
|
||||
|
||||
// bind event
|
||||
$("#ccn-todo-btnAdd").click(ccn_todo_Add);
|
||||
$("#ccn-todo-btnRefresh").click(ccn_todo_Refresh);
|
||||
});
|
||||
|
||||
function ccn_todo_RefreshCacheList() {
|
||||
// clean list cache first
|
||||
ccn_todo_todoListCache = new Array();
|
||||
|
||||
var result = ccn_api_todo_getFull();
|
||||
if(typeof(result) != 'undefined') {
|
||||
for(var index in result) {
|
||||
ccn_todo_todoListCache[result[index][0]] = result[index];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function ccn_todo_RenderCacheList() {
|
||||
// clean list first
|
||||
$("#ccn-todo-todoList").empty();
|
||||
|
||||
var renderdata = {
|
||||
uuid: undefined,
|
||||
data: undefined
|
||||
};
|
||||
|
||||
var listDOM = $("#ccn-todo-todoList");
|
||||
for(var index in ccn_todo_todoListCache) {
|
||||
// update render data
|
||||
var item = ccn_todo_todoListCache[index];
|
||||
renderdata.uuid = item[0];
|
||||
renderdata.data = LineBreaker2Br(item[2]);
|
||||
|
||||
// render
|
||||
listDOM.append(ccn_template_todoItem.render(renderdata));
|
||||
|
||||
// set mode
|
||||
var uuid = renderdata.uuid;
|
||||
ccn_todo_ChangeDisplayMode(uuid, false);
|
||||
|
||||
// bind event
|
||||
$("#ccn-todoItem-btnEdit-" + uuid).click(ccn_todo_ItemEdit);
|
||||
$("#ccn-todoItem-btnDelete-" + uuid).click(ccn_todo_ItemDelete);
|
||||
$("#ccn-todoItem-btnUpdate-" + uuid).click(ccn_todo_ItemUpdate);
|
||||
$("#ccn-todoItem-btnCancelUpdate-" + uuid).click(ccn_todo_ItemCancelUpdate);
|
||||
}
|
||||
}
|
||||
|
||||
function ccn_todo_ChangeDisplayMode(uuid, isEdit) {
|
||||
if(isEdit) {
|
||||
// 4 buttons
|
||||
$("#ccn-todoItem-btnEdit-" + uuid).hide();
|
||||
$("#ccn-todoItem-btnDelete-" + uuid).hide();
|
||||
$("#ccn-todoItem-btnUpdate-" + uuid).show();
|
||||
$("#ccn-todoItem-btnCancelUpdate-" + uuid).show();
|
||||
|
||||
// 2 elements
|
||||
$("#ccn-todoItem-p-" + uuid).hide();
|
||||
$("#ccn-todoItem-textarea-" + uuid).show();
|
||||
} else {
|
||||
$("#ccn-todoItem-btnEdit-" + uuid).show();
|
||||
$("#ccn-todoItem-btnDelete-" + uuid).show();
|
||||
$("#ccn-todoItem-btnUpdate-" + uuid).hide();
|
||||
$("#ccn-todoItem-btnCancelUpdate-" + uuid).hide();
|
||||
|
||||
$("#ccn-todoItem-p-" + uuid).show();
|
||||
$("#ccn-todoItem-textarea-" + uuid).hide();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function ccn_todo_Refresh() {
|
||||
// refresh and render once
|
||||
ccn_todo_RefreshCacheList();
|
||||
ccn_todo_RenderCacheList();
|
||||
}
|
||||
|
||||
function ccn_todo_Add() {
|
||||
var result = ccn_api_todo_add();
|
||||
if (typeof(result) == 'undefined') {
|
||||
// fail
|
||||
ccn_messagebox_Show($.i18n.prop("ccn-i18n-js-fail-add"));
|
||||
} else {
|
||||
// add into cache
|
||||
ccn_todo_todoListCache[result[0]] = result;
|
||||
|
||||
// render
|
||||
var listDOM = $("#ccn-todo-todoList");
|
||||
listDOM.append(ccn_template_todoItem.render({
|
||||
uuid: result[0],
|
||||
data: LineBreaker2Br(result[2])
|
||||
}));
|
||||
|
||||
// set mode
|
||||
var uuid = result[0];
|
||||
ccn_todo_ChangeDisplayMode(uuid, false);
|
||||
|
||||
// bind event
|
||||
$("#ccn-todoItem-btnEdit-" + uuid).click(ccn_todo_ItemEdit);
|
||||
$("#ccn-todoItem-btnDelete-" + uuid).click(ccn_todo_ItemDelete);
|
||||
$("#ccn-todoItem-btnUpdate-" + uuid).click(ccn_todo_ItemUpdate);
|
||||
$("#ccn-todoItem-btnCancelUpdate-" + uuid).click(ccn_todo_ItemCancelUpdate);
|
||||
}
|
||||
}
|
||||
|
||||
function ccn_todo_ItemEdit() {
|
||||
var uuid = $(this).attr("uuid");
|
||||
|
||||
// copy current data to textarea
|
||||
$("#ccn-todoItem-textarea-" + uuid).val(
|
||||
ccn_todo_todoListCache[uuid][2]
|
||||
);
|
||||
|
||||
// switch to edit mode
|
||||
ccn_todo_ChangeDisplayMode(uuid, true);
|
||||
}
|
||||
|
||||
function ccn_todo_ItemDelete() {
|
||||
var uuid = $(this).attr("uuid");
|
||||
|
||||
var result = ccn_api_todo_delete(
|
||||
uuid,
|
||||
ccn_todo_todoListCache[uuid][3]
|
||||
);
|
||||
|
||||
if(!result) {
|
||||
// fail
|
||||
ccn_messagebox_Show($.i18n.prop("ccn-i18n-js-fail-delete"));
|
||||
} else {
|
||||
// remove body
|
||||
$("#ccn-todoItem-" + uuid).remove();
|
||||
}
|
||||
}
|
||||
|
||||
function ccn_todo_ItemUpdate() {
|
||||
var uuid = $(this).attr("uuid");
|
||||
|
||||
var newData = $("#ccn-todoItem-textarea-" + uuid).val();
|
||||
var result = ccn_api_todo_update(
|
||||
uuid,
|
||||
newData,
|
||||
ccn_todo_todoListCache[uuid][3]
|
||||
);
|
||||
|
||||
if (typeof(result) == 'undefined') {
|
||||
// fail
|
||||
ccn_messagebox_Show($.i18n.prop("ccn-i18n-js-fail-update"));
|
||||
} else {
|
||||
// safely update data & lastChanged and control
|
||||
ccn_todo_todoListCache[uuid][2] = newData;
|
||||
ccn_todo_todoListCache[uuid][3] = result;
|
||||
$("#ccn-todoItem-p-" + uuid).html(LineBreaker2Br(newData));
|
||||
|
||||
// switch to normal mode
|
||||
ccn_todo_ChangeDisplayMode(uuid, false);
|
||||
}
|
||||
}
|
||||
|
||||
function ccn_todo_ItemCancelUpdate() {
|
||||
var uuid = $(this).attr("uuid");
|
||||
// clean data
|
||||
$("#ccn-todoItem-textarea-" + uuid).val("");
|
||||
// switch to normal mode
|
||||
ccn_todo_ChangeDisplayMode(uuid, false);
|
||||
}
|
||||
10
frontend/static/js/tabcontrol.js
Normal file
10
frontend/static/js/tabcontrol.js
Normal file
@@ -0,0 +1,10 @@
|
||||
// all args are based on 1
|
||||
function ccn_tabcontrol_SwitchTab(tabcontrolGroup, targetTabIndex) {
|
||||
// close all panel and tab
|
||||
$(".tabcontrol-tab-" + tabcontrolGroup).removeClass("is-active");
|
||||
$(".tabcontrol-panel-" + tabcontrolGroup).hide();
|
||||
|
||||
// show specific
|
||||
$("#tabcontrol-tab-" + tabcontrolGroup + "-" + targetTabIndex).addClass("is-active");
|
||||
$("#tabcontrol-panel-" + tabcontrolGroup + "-" + targetTabIndex).show();
|
||||
}
|
||||
50
frontend/static/js/template.js
Normal file
50
frontend/static/js/template.js
Normal file
@@ -0,0 +1,50 @@
|
||||
var ccn_template_headerNav = undefined;
|
||||
var ccn_template_messagebox = undefined;
|
||||
var ccn_template_datetimepicker = undefined;
|
||||
var ccn_template_calendarItem = undefined;
|
||||
var ccn_template_scheduleItem = undefined;
|
||||
var ccn_template_ownedItem = undefined;
|
||||
var ccn_template_sharingItem = undefined;
|
||||
var ccn_template_displayOwnedItem = undefined;
|
||||
var ccn_template_displaySharedItem = undefined;
|
||||
var ccn_template_userItem = undefined;
|
||||
var ccn_template_todoItem = undefined;
|
||||
var ccn_template_optionItem = undefined;
|
||||
var ccn_template_tokenItem = undefined;
|
||||
|
||||
function ccn_template_Load() {
|
||||
ccn_template_headerNav = ccn_template_TemplateLoader('headerNav');
|
||||
ccn_template_messagebox = ccn_template_TemplateLoader('messagebox');
|
||||
ccn_template_datetimepicker = ccn_template_TemplateLoader('datetimepicker');
|
||||
|
||||
ccn_template_calendarItem = ccn_template_TemplateLoader('calendarItem');
|
||||
ccn_template_scheduleItem = ccn_template_TemplateLoader('scheduleItem');
|
||||
ccn_template_displayOwnedItem = ccn_template_TemplateLoader('displayOwnedItem');
|
||||
ccn_template_displaySharedItem = ccn_template_TemplateLoader('displaySharedItem');
|
||||
|
||||
ccn_template_todoItem = ccn_template_TemplateLoader('todoItem');
|
||||
ccn_template_userItem = ccn_template_TemplateLoader('userItem');
|
||||
ccn_template_tokenItem = ccn_template_TemplateLoader('tokenItem');
|
||||
|
||||
ccn_template_ownedItem = ccn_template_TemplateLoader('ownedItem');
|
||||
ccn_template_sharingItem = ccn_template_TemplateLoader('sharingItem');
|
||||
ccn_template_optionItem = ccn_template_TemplateLoader('optionItem');
|
||||
|
||||
}
|
||||
|
||||
function ccn_template_TemplateLoader(templateName) {
|
||||
var elements = $("#jsrender-tmpl-" + templateName);
|
||||
if (elements.length == 0) return undefined;
|
||||
var cache = undefined;
|
||||
|
||||
$.ajax({
|
||||
url: elements.attr('src'),
|
||||
type: "GET",
|
||||
async: false,
|
||||
success: function (data) {
|
||||
cache = $.templates(data);
|
||||
}
|
||||
});
|
||||
|
||||
return cache;
|
||||
}
|
||||
70
frontend/static/js/utils.js
Normal file
70
frontend/static/js/utils.js
Normal file
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
function ComputPasswordWithSalt(password, salt) {
|
||||
return ComputeSHA256(ComputeSHA256(password) + salt.toString());
|
||||
}
|
||||
|
||||
function ComputeSHA256(strl) {
|
||||
var tempstr = new TextEncoder().encode(strl);
|
||||
var hashedStrl = undefined
|
||||
var shitpromise = crypto.subtle.digest('SHA-256', tempstr);
|
||||
Promise.all(shitpromise).then(function(result) {
|
||||
hashedStrl = result;
|
||||
});
|
||||
var hashArray = Array.from(new Uint8Array(hashedStrl));
|
||||
var hashHex = hashArray.map(b => ('00' + b.toString(16)).slice(-2)).join('');
|
||||
return hashHex.toLowerCase();
|
||||
}
|
||||
*/
|
||||
var DefaultColor = '#536dfe';
|
||||
|
||||
function IsResponseOK(data) {
|
||||
if (typeof (data) == 'undefined') {
|
||||
console.log("Fail to execute an api!");
|
||||
return false;
|
||||
}
|
||||
if (!data['success']) {
|
||||
console.log("Fail to execute an api! Reason:");
|
||||
console.log(data['error']);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function LineBreaker2Br(strl) {
|
||||
return $('<div>').text(strl).html().replace(/\n/g, '<br />');
|
||||
}
|
||||
|
||||
function IsUndefinedOrEmpty(data) {
|
||||
return (typeof (data) == 'undefined' || data == "");
|
||||
}
|
||||
|
||||
function SmarterShowHide(boolean, element) {
|
||||
if (typeof (element) == 'undefined') return;
|
||||
if (boolean) element.show();
|
||||
else element.hide();
|
||||
}
|
||||
|
||||
function GCD(a, b) {
|
||||
if (b == 0) return a;
|
||||
return GCD(b, a % b);
|
||||
}
|
||||
|
||||
function LCM(a, b) {
|
||||
return a / GCD(a, b) * b;
|
||||
}
|
||||
|
||||
String.prototype.format = function() {
|
||||
var e = arguments;
|
||||
return !!this && this.replace(
|
||||
/\{(\d+)\}/g,
|
||||
function (t, n) {
|
||||
return e[n].toString() ? e[n].toString() : t;
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
Date.prototype.getWeekday = function() {
|
||||
var temp = this.getDay();
|
||||
if (temp == 0) return 6;
|
||||
else return temp - 1;
|
||||
};
|
||||
Reference in New Issue
Block a user