1
0

refactor: introduce modern frontend

This commit is contained in:
2026-04-28 15:47:32 +08:00
parent a0e3385670
commit 37435eeb66
71 changed files with 3582 additions and 0 deletions

8
frontend/.editorconfig Normal file
View File

@@ -0,0 +1,8 @@
[*.{js,jsx,mjs,cjs,ts,tsx,mts,cts,vue,css,scss,sass,less,styl}]
charset = utf-8
indent_size = 2
indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true
end_of_line = lf
max_line_length = 100

1
frontend/.gitattributes vendored Normal file
View File

@@ -0,0 +1 @@
* text=auto eol=lf

39
frontend/.gitignore vendored Normal file
View File

@@ -0,0 +1,39 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
.DS_Store
dist
dist-ssr
coverage
*.local
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
*.tsbuildinfo
.eslintcache
# Cypress
/cypress/videos/
/cypress/screenshots/
# Vitest
__screenshots__/
# Vite
*.timestamp-*-*.mjs

10
frontend/.oxlintrc.json Normal file
View File

@@ -0,0 +1,10 @@
{
"$schema": "./node_modules/oxlint/configuration_schema.json",
"plugins": ["eslint", "typescript", "unicorn", "oxc", "vue"],
"env": {
"browser": true
},
"categories": {
"correctness": "error"
}
}

48
frontend/README.md Normal file
View File

@@ -0,0 +1,48 @@
# coleaf-frontend
This template should help get you started developing with Vue 3 in Vite.
## Recommended IDE Setup
[VS Code](https://code.visualstudio.com/) + [Vue (Official)](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur).
## Recommended Browser Setup
- Chromium-based browsers (Chrome, Edge, Brave, etc.):
- [Vue.js devtools](https://chromewebstore.google.com/detail/vuejs-devtools/nhdogjmejiglipccpnnnanhbledajbpd)
- [Turn on Custom Object Formatter in Chrome DevTools](http://bit.ly/object-formatters)
- Firefox:
- [Vue.js devtools](https://addons.mozilla.org/en-US/firefox/addon/vue-js-devtools/)
- [Turn on Custom Object Formatter in Firefox DevTools](https://fxdx.dev/firefox-devtools-custom-object-formatters/)
## Type Support for `.vue` Imports in TS
TypeScript cannot handle type information for `.vue` imports by default, so we replace the `tsc` CLI with `vue-tsc` for type checking. In editors, we need [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) to make the TypeScript language service aware of `.vue` types.
## Customize configuration
See [Vite Configuration Reference](https://vite.dev/config/).
## Project Setup
```sh
pnpm install
```
### Compile and Hot-Reload for Development
```sh
pnpm dev
```
### Type-Check, Compile and Minify for Production
```sh
pnpm build
```
### Lint with [ESLint](https://eslint.org/)
```sh
pnpm lint
```

1
frontend/env.d.ts vendored Normal file
View File

@@ -0,0 +1 @@
/// <reference types="vite/client" />

23
frontend/eslint.config.ts Normal file
View File

@@ -0,0 +1,23 @@
import { globalIgnores } from 'eslint/config'
import { defineConfigWithVueTs, vueTsConfigs } from '@vue/eslint-config-typescript'
import pluginVue from 'eslint-plugin-vue'
import pluginOxlint from 'eslint-plugin-oxlint'
// To allow more languages other than `ts` in `.vue` files, uncomment the following lines:
// import { configureVueProject } from '@vue/eslint-config-typescript'
// configureVueProject({ scriptLangs: ['ts', 'tsx'] })
// More info at https://github.com/vuejs/eslint-config-typescript/#advanced-setup
export default defineConfigWithVueTs(
{
name: 'app/files-to-lint',
files: ['**/*.{vue,ts,mts,tsx}'],
},
globalIgnores(['**/dist/**', '**/dist-ssr/**', '**/coverage/**']),
...pluginVue.configs['flat/essential'],
vueTsConfigs.recommended,
...pluginOxlint.buildFromOxlintConfigFile('.oxlintrc.json'),
)

16
frontend/index.html Normal file
View File

@@ -0,0 +1,16 @@
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="UTF-8">
<link rel="icon" href="/favicon.ico">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>coconut-leaf</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>

44
frontend/package.json Normal file
View File

@@ -0,0 +1,44 @@
{
"name": "coleaf-frontend",
"version": "2.0.0",
"private": true,
"type": "module",
"scripts": {
"dev": "vite",
"build": "run-p type-check \"build-only {@}\" --",
"preview": "vite preview",
"build-only": "vite build",
"type-check": "vue-tsc --build",
"lint": "run-s lint:*",
"lint:oxlint": "oxlint . --fix",
"lint:eslint": "eslint . --fix --cache"
},
"dependencies": {
"@fortawesome/fontawesome-free": "^7.2.0",
"@fortawesome/vue-fontawesome": "^3.2.0",
"bulma": "^1.0.4",
"pinia": "^3.0.4",
"vue": "^3.5.32",
"vue-router": "^5.0.4"
},
"devDependencies": {
"@tsconfig/node24": "^24.0.4",
"@types/node": "^24.12.2",
"@vitejs/plugin-vue": "^6.0.6",
"@vue/eslint-config-typescript": "^14.7.0",
"@vue/tsconfig": "^0.9.1",
"eslint": "^10.2.1",
"eslint-plugin-oxlint": "~1.60.0",
"eslint-plugin-vue": "~10.8.0",
"jiti": "^2.6.1",
"npm-run-all2": "^8.0.4",
"oxlint": "~1.60.0",
"typescript": "~6.0.0",
"vite": "^8.0.8",
"vite-plugin-vue-devtools": "^8.1.1",
"vue-tsc": "^3.2.6"
},
"engines": {
"node": "^20.19.0 || >=22.12.0"
}
}

3168
frontend/pnpm-lock.yaml generated Normal file

File diff suppressed because it is too large Load Diff

BIN
frontend/public/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

49
frontend/src/App.vue Normal file
View File

@@ -0,0 +1,49 @@
<script setup lang="ts"></script>
<template>
<nav class="navbar has-shadow is-spaced bd-navbar" role="navigation" aria-label="main navigation">
<div class="navbar-brand">
<router-link class="navbar-item" to="/">
<img src="/public/favicon.ico"><b style="margin:0 0 0 14px;">coconut-leaf</b>
</router-link>
<a role="button" class="navbar-burger burger" aria-label="menu" aria-expanded="false"
data-target="coleaf-navbar">
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
</a>
</div>
<div id="coleaf-navbar" class="navbar-menu">
<div class="navbar-start">
<router-link class="navbar-item" to="/home">Home</router-link>
<router-link class="navbar-item" to="/collection">Collection</router-link>
<router-link class="navbar-item" to="/calendar">Calendar</router-link>
<router-link class="navbar-item" to="/todo">Todo</router-link>
<router-link class="navbar-item" to="/admin">Admin</router-link>
</div>
<div class="navbar-end">
<p class="navbar-item">
<a class="button is-primary" href="/login">Login</a>
</p>
<p class="navbar-item">
<a class="button is-primary">Logout</a>
</p>
<div class="navbar-item has-dropdown is-hoverable">
<a class="navbar-link"></a>
<div class="navbar-dropdown">
<a language="en-US" class="navbar-item">English</a>
<a language="zh-CN" class="navbar-item">简体中文</a>
</div>
</div>
</div>
</div>
</nav>
<!-- The output result of router -->
<router-view></router-view>
</template>
<style scoped></style>

12
frontend/src/main.ts Normal file
View File

@@ -0,0 +1,12 @@
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'
import router from './router'
const app = createApp(App)
app.use(createPinia())
app.use(router)
app.mount('#app')

View File

@@ -0,0 +1,29 @@
import { createRouter, createWebHistory } from 'vue-router'
import Home from '../views/Home.vue'
import Collection from '@/views/Collection.vue'
import Calendar from '@/views/Calendar.vue'
import Todo from '@/views/Todo.vue'
import Admin from '@/views/Admin.vue'
import Page404 from '@/views/Page404.vue'
const routes = [
{ path: '/home', component: Home },
{ path: '/collection', component: Collection },
{ path: '/calendar', component: Calendar},
{ path: '/todo', component: Todo},
{ path: '/admin', component: Admin },
{ path: '/404', component: Page404 },
{ path: '/', redirect: '/home' },
{ path: '/:pathMatch(.*)*', redirect: '/404' },
];
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes: routes,
});
export default router

View File

@@ -0,0 +1,12 @@
import { ref, computed } from 'vue'
import { defineStore } from 'pinia'
export const useCounterStore = defineStore('counter', () => {
const count = ref(0)
const doubleCount = computed(() => count.value * 2)
function increment() {
count.value++
}
return { count, doubleCount, increment }
})

View File

@@ -0,0 +1,8 @@
<script setup lang="ts"></script>
<template>
<h1>Congratulations</h1>
<p>This is admin.</p>
</template>
<style scoped></style>

View File

@@ -0,0 +1,8 @@
<script setup lang="ts"></script>
<template>
<h1>Congratulations</h1>
<p>This is calendar.</p>
</template>
<style scoped></style>

View File

@@ -0,0 +1,8 @@
<script setup lang="ts"></script>
<template>
<h1>Congratulations</h1>
<p>This is collection.</p>
</template>
<style scoped></style>

View File

@@ -0,0 +1,8 @@
<script setup lang="ts"></script>
<template>
<h1>Congratulations</h1>
<p>This is home.</p>
</template>
<style scoped></style>

View File

@@ -0,0 +1,8 @@
<script setup lang="ts"></script>
<template>
<h1>Congratulations</h1>
<p>404 Not Found</p>
</template>
<style scoped></style>

View File

@@ -0,0 +1,8 @@
<script setup lang="ts"></script>
<template>
<h1>Congratulations</h1>
<p>This is todo.</p>
</template>
<style scoped></style>

View File

@@ -1,62 +0,0 @@
div.user-item {
display: flex;
flex-flow: row;
align-items: flex-start;
padding: 1.25rem;
margin-bottom: 1.25rem;
}
div.user-item-words {
display: flex;
flex-flow: column;
align-items: flex-start;
flex-grow: 1;
flex-basis: 0;
word-break: break-all;
}
div.user-item-icon {
margin-left: 0.75rem;
}
div.token-item {
display: flex;
flex-flow: row;
align-items: flex-start;
padding: 1.25rem;
margin-bottom: 1.25rem;
}
div.token-item-words {
display: flex;
flex-flow: column;
align-items: flex-start;
flex-grow: 1;
flex-basis: 0;
word-break: break-all;
}
div.token-item-icon {
margin-left: 0.75rem;
}
div.control-list {
display: flex;
flex-flow: row;
flex-wrap: wrap;
}
div.control-list > * {
margin-right: 0.75rem;
margin-bottom: 0.75rem;
}

View File

@@ -1,159 +0,0 @@
#ccn-calendar-calendarBody > div:nth-child(n+2) > div {
border-top: 0 solid black;
border-left: 0 solid black;
border-right: 1px solid black;
border-bottom: 1px solid black;
padding: 0.75em;
display: flex;
flex-flow: column;
align-items: flex-start;
overflow: hidden;
}
#ccn-calendar-calendarBody > div:nth-child(n+2) > div:nth-child(1) {
border-left: 1px solid black;
}
#ccn-calendar-calendarBody > div:nth-child(2) > div {
border-top: 1px solid black;
}
#ccn-calendar-calendarBody > div > div {
flex-grow: 1;
flex-basis: 0;
flex-shrink: 0;
overflow: hidden;
}
#ccn-calendar-calendarBody > div > div[isCurrentMonth=false] {
background: #d0d0d0;
}
#ccn-calendar-calendarBody > div {
display: flex;
flex-flow: row;
}
div.calendarItem-eventBox {
border: 1px solid black;
border-radius: 2px;
margin-top: 0.2rem;
height: 0.75rem;
width: 100%;
}
div.calendarItem-eventBox[enableDisplay=true] {
visibility: visible;
}
div.calendarItem-eventBox[enableDisplay=false] {
visibility: hidden;
}
div.schedule-day {
display: flex;
flex-flow: column;
}
div.schedule-day-words {
margin-top: 0.75rem;
margin-bottom: 0.75rem;
}
div.schedule-event-list {
display: flex;
flex-flow: column;
}
div.schedule-event-outter {
display: flex;
flex-flow: row;
align-items: flex-start;
margin-bottom: 1.25rem;
}
div.schedule-event-inner {
display: flex;
flex-flow: row;
align-items: flex-start;
padding: 1.25rem;
}
div.schedule-event-words {
display: flex;
flex-flow: column;
align-items: flex-start;
flex-grow: 1;
flex-basis: 0;
word-break: break-all;
}
div.schedule-event-icon {
margin-left: 0.75rem;
}
div.schedule-event-color {
width: 0.75rem;
height: 100%;
}
#ccn-calendar-scheduleList div.schedule-day:nth-child(n+2) {
border-top: 1px solid rgba(219,219,219,.5);
}
div.collection-item {
display: flex;
flex-flow: row;
align-items: flex-start;
padding: 1.25rem;
margin-bottom: 1.25rem;
}
div.collection-item-words {
flex-grow: 1;
flex-basis: 0;
word-break: break-all;
}
div.collection-item-icon {
margin-left: 0.75rem;
}
div.control-list {
display: flex;
flex-flow: row;
flex-wrap: wrap;
}
div.control-list > * {
margin-right: 0.75rem;
margin-bottom: 0.75rem;
margin-left: 0 !important;
}

View File

@@ -1,34 +0,0 @@
div.collection-item {
display: flex;
flex-flow: row;
align-items: flex-start;
padding: 1.25rem;
margin-bottom: 1.25rem;
}
div.collection-item-words {
flex-grow: 1;
flex-basis: 0;
word-break: break-all;
}
div.collection-item-icon {
margin-left: 0.75rem;
}
div.control-list {
display: flex;
flex-flow: row;
flex-wrap: wrap;
}
div.control-list > * {
margin-right: 0.75rem;
margin-bottom: 0.75rem;
margin-left: 0 !important;
}

View File

@@ -1,117 +0,0 @@
div.perfectTable {
display: flex;
flex-flow: column;
}
/*
div.perfectTable > div > div:nth-child(1) {
border-left: 1px solid black;
}
div.perfectTable > div:nth-child(1) > div {
border-top: 1px solid black;
}
*/
div.perfectTable > div > div {
/*border-top: 0 solid black;
border-left: 0 solid black;
border-right: 1px solid black;
border-bottom: 1px solid black;
padding: 0.75em;*/
flex-grow: 1;
flex-basis: 0;
flex-shrink: 0;
overflow: hidden;
display: flex;
justify-content: center;
padding-top: 1rem;
padding-bottom: 1rem;
}
div.perfectTable > div {
display: flex;
flex-flow: row;
}
div.perfectTable > div > div[picked=true] {
background: hsl(171, 100%, 41%);
color: #fff;
}
div.pickerContainer {
display: flex;
align-items: center;
flex-flow: row;
justify-content: center;
}
div.pickerContainer > div {
flex-grow: 1;
flex-shrink: 1;
flex-basis: 0;
}
div.pickerContainer > svg {
width: 100%;
height: 100%;
}
div.pickerContainer > svg > text {
dominant-baseline: middle;
text-anchor: middle;
user-select: none;
cursor: default;
}
div.pickerContainer > svg > circle[type=background] {
stroke-width: 0;
fill: #d0d0d0;
}
div.pickerContainer > svg > circle[type=symbol] {
stroke-width: 0;
fill: hsl(171, 100%, 41%); /* $primary */
}
div.pickerContainer > svg > line {
stroke-width: 0.125em;
stroke: hsl(171, 100%, 41%); /* $primary */
}
header.pickerHeader {
display: flex;
flex-flow: row;
flex-grow: 0;
flex-basis: 0;
flex-shrink: 0;
justify-content: space-between;
}
header.pickerHeader > div {
display: flex;
flex-flow: column;
flex-grow: 1;
flex-basis: 0;
flex-shrink: 0;
}

View File

@@ -1,17 +0,0 @@
div.control-list {
display: flex;
flex-flow: row;
flex-wrap: wrap;
}
div.control-list > * {
margin-right: 0.75rem;
margin-bottom: 0.75rem;
margin-left: 0 !important;
}
#ccn-event-eventFormBody > section {
border-top: 1px solid rgba(219,219,219,.5);
}

View File

@@ -1,32 +0,0 @@
div.todo-item {
display: flex;
flex-flow: row;
align-items: flex-start;
padding: 1.25rem;
margin-bottom: 1.25rem;
}
div.todo-item-words {
flex-grow: 1;
flex-basis: 0;
word-break: break-all;
}
div.todo-item-icon {
margin-left: 0.75rem;
}
div.control-list {
display: flex;
flex-flow: row;
flex-wrap: wrap;
}
div.control-list > * {
margin-right: 0.75rem;
margin-bottom: 0.75rem;
}

View File

@@ -1,140 +0,0 @@
ccn-i18n-pageName-home=coconut-leaf - A light, self-host calendar system.
ccn-i18n-pageName-collection=coconut-leaf - Collection
ccn-i18n-pageName-calendar=coconut-leaf - Calendar
ccn-i18n-pageName-event=coconut-leaf - Event
ccn-i18n-pageName-todo=coconut-leaf - Todo
ccn-i18n-pageName-admin=coconut-leaf - Admin
ccn-i18n-pageName-login=coconut-leaf - Login
ccn-i18n-header-nav-home=Home
ccn-i18n-header-nav-collection=Collection
ccn-i18n-header-nav-calendar=Calendar
ccn-i18n-header-nav-todo=Todo
ccn-i18n-header-nav-admin=Admin
ccn-i18n-header-user-login=Login
ccn-i18n-header-user-logout=Logout
ccn-i18n-header-language=Language
ccn-i18n-universal-text-year=Year
ccn-i18n-universal-text-month=Month
ccn-i18n-universal-text-day=Day
ccn-i18n-universal-text-hour=Hour
ccn-i18n-universal-text-minute=Minute
ccn-i18n-universal-week-1=Monday
ccn-i18n-universal-week-2=Tuesday
ccn-i18n-universal-week-3=Wednesday
ccn-i18n-universal-week-4=Thursday
ccn-i18n-universal-week-5=Friday
ccn-i18n-universal-week-6=Saturday
ccn-i18n-universal-week-7=Sunday
ccn-i18n-universal-month-1=January
ccn-i18n-universal-month-2=February
ccn-i18n-universal-month-3=March
ccn-i18n-universal-month-4=April
ccn-i18n-universal-month-5=May
ccn-i18n-universal-month-6=June
ccn-i18n-universal-month-7=July
ccn-i18n-universal-month-8=August
ccn-i18n-universal-month-9=September
ccn-i18n-universal-month-10=October
ccn-i18n-universal-month-11=November
ccn-i18n-universal-month-12=December
ccn-i18n-messagebox-confirm=OK
ccn-i18n-messagebox-title=Notification
ccn-i18n-datetimepicker-confirm=OK
ccn-i18n-datetimepicker-cancel=Cancel
ccn-i18n-js-fail-login=Fail to login. Please check your username or password.
ccn-i18n-js-fail-logout=Fail to logout due to unknow reason. Consider refreshing page to solve problem.
ccn-i18n-js-fail-get=A get operation failed. It may caused by server internal error or your limited permission. Refreshing page may fix system problem. Before refreshing page, please backup all your unsaved data.
ccn-i18n-js-fail-add=An add operation failed. It may caused by wrong arguments. Refreshing page may fix system problem. Before refreshing page, please backup all your unsaved data.
ccn-i18n-js-fail-update=An update operation failed. It may caused by wrong arguments or lost target. Refreshing page may fix system problem. Before refreshing page, please backup all your unsaved data.
ccn-i18n-js-fail-delete=A delete operation failed. It may caused by no matched item. Refreshing page may fix system problem. Before refreshing page, please backup all your unsaved data.
ccn-i18n-js-success=Operation OK.
ccn-i18n-js-fail-form=Your filled event form is not fufilled or have error. Please check it and try again.
ccn-i18n-home-desc=<h1 class="title">coconut-leaf</h1><p>A light, self-host calendar system.</p><p>Originally, this app is served for yyc12345 personal use.</p><br /><p>Pull request / issue / translation are welcomed.</p><p>Submit them in our <a href="https://github.com/yyc12345/coconut-leaf">GitHub project</a>.</p><p>This project source code is licensed <a href="https://www.gnu.org/licenses/agpl-3.0.html">AGPL v3</a>.</p>
ccn-i18n-login-form-username=Username
ccn-i18n-login-form-password=Password
ccn-i18n-login-form-login=Login
ccn-i18n-todo-todoList=Todo list
ccn-i18n-calendar-calendar-today=Today
ccn-i18n-calendar-calendar-add=Add...
ccn-i18n-calendar-calendar-stripedEvents={0} items
ccn-i18n-calendar-calendar-scheduleList=Schedule
ccn-i18n-calendar-tabcontrol-tabCalendar=Calendar
ccn-i18n-calendar-tabcontrol-tabCollection=Collection
ccn-i18n-calendar-tabcontrol-tabDisplay=Display
ccn-i18n-calendar-owned-list=My collections
ccn-i18n-calendar-shared-list=Shared collections
ccn-i18n-calendar-display-firstDayOfWeek=The first day of week
ccn-i18n-calendar-display-subcalendar=Sub-Calendar
ccn-i18n-calendar-display-subcalendar-chineseLunisolarCalendar=Chinese Lunisolar Calendar
ccn-i18n-collection-owned-list=Owned
ccn-i18n-collection-sharing-list=Sharing target
ccn-i18n-collection-sharing-editing=Editing:
ccn-i18n-event-header=Edit Event
ccn-i18n-event-title=Title
ccn-i18n-event-description=Description
ccn-i18n-event-color=Color
ccn-i18n-event-collection=Collection
ccn-i18n-event-startDateTime=Start Date Time
ccn-i18n-event-endDateTime=Stop Date Time
ccn-i18n-event-btnSpot=Spot
ccn-i18n-event-btnFullDay=Full day
ccn-i18n-event-loop=Event Loop
ccn-i18n-event-loop-never=Never
ccn-i18n-event-loop-day=Day
ccn-i18n-event-loop-week=Week
ccn-i18n-event-loop-month=Month
ccn-i18n-event-loop-year=Year
ccn-i18n-event-loopDay-span=Day span
ccn-i18n-event-loopWeek-span=Week span
ccn-i18n-event-loopWeek-option=Week options
ccn-i18n-event-loopMonth-span=Month span
ccn-i18n-event-loopWeek-option=Month mode
ccn-i18n-event-loopWeek-optionA=Day {0} in month
ccn-i18n-event-loopWeek-optionB=Day {0} from the end of the month
ccn-i18n-event-loopWeek-optionC=Day {1} in week {0}
ccn-i18n-event-loopWeek-optionD=Day {1} in week {0} from the end of the month
ccn-i18n-event-loopYear-span=Year span
ccn-i18n-event-loopStop=Event Loop Stop
ccn-i18n-event-loopStop-forever=Forever
ccn-i18n-event-loopStop-datetime=Date Time
ccn-i18n-event-loopStop-times=Times
ccn-i18n-event-timezone-title=Timezone
ccn-i18n-event-timezone-warning=The timezone of this event is not corresponding with your current timezone. All of date and time in this page are shown as the original timezone of this event. You can choose a timezone option in follwing content. If you are not familar with this, please pick keep timezone.
ccn-i18n-event-timezone-keep=Keep timezone
ccn-i18n-event-timezone-replace=Use my timezone
ccn-i18n-event-strictMode-title=Strict Mode in Event Loop
ccn-i18n-event-strictMode-warning=You can choose strict mode or rough mode in following content. This is only effect on looped event.
ccn-i18n-event-strictMode-strict=Strict Mode. If ordered day is not existing, skip it.
ccn-i18n-event-strictMode-rough=Rough mode. If ordered day is not existing, choose the day closing with original day to arrange event.
ccn-i18n-event-btnSubmit=Submit
ccn-i18n-event-btnCancel=Cancel
ccn-i18n-sharedItem-sharedBy=Shared by:
ccn-i18n-admin-tabcontrol-tabProfile=My Profile
ccn-i18n-admin-tabcontrol-tabToken=Manage Multi-login
ccn-i18n-admin-tabcontrol-tabUserList=Manager User
ccn-i18n-admin-changePassword=Change Password
ccn-i18n-admin-manageToken=Manage multi-login
ccn-i18n-admin-manageToken-desc=Manage the multi-login of the current account. You can forced logout some login in there.
ccn-i18n-admin-userList=User List
ccn-i18n-userItem-newPassword=New Password
ccn-i18n-userItem-isAdmin=Is Admin
ccn-i18n-tokenItem-ua=User Agent:
ccn-i18n-tokenItem-ip=IP:
ccn-i18n-tokenItem-expireOn=Expire On:
ccn-i18n-tokenItem-isMe=This is the login credentials you are currently using.

View File

@@ -1,153 +0,0 @@
ccn-i18n-pageName-home=coconut-leaf - 一个轻量的自建日历系统
ccn-i18n-pageName-collection=coconut-leaf - 集合
ccn-i18n-pageName-calendar=coconut-leaf - 日历
ccn-i18n-pageName-event=coconut-leaf - 事件
ccn-i18n-pageName-todo=coconut-leaf - 待办
ccn-i18n-pageName-admin=coconut-leaf - 管理
ccn-i18n-pageName-login=coconut-leaf - 登录
ccn-i18n-header-nav-home=主页
ccn-i18n-header-nav-collection=集合
ccn-i18n-header-nav-calendar=日历
ccn-i18n-header-nav-todo=待办
ccn-i18n-header-nav-admin=管理
ccn-i18n-header-user-login=登录
ccn-i18n-header-user-logout=登出
ccn-i18n-header-language=语言
ccn-i18n-universal-text-year=
ccn-i18n-universal-text-month=
ccn-i18n-universal-text-day=
ccn-i18n-universal-text-hour=
ccn-i18n-universal-text-minute=
ccn-i18n-universal-week-1=星期一
ccn-i18n-universal-week-2=星期二
ccn-i18n-universal-week-3=星期三
ccn-i18n-universal-week-4=星期四
ccn-i18n-universal-week-5=星期五
ccn-i18n-universal-week-6=星期六
ccn-i18n-universal-week-7=星期日
ccn-i18n-universal-month-1=1月
ccn-i18n-universal-month-2=2月
ccn-i18n-universal-month-3=3月
ccn-i18n-universal-month-4=4月
ccn-i18n-universal-month-5=5月
ccn-i18n-universal-month-6=6月
ccn-i18n-universal-month-7=7月
ccn-i18n-universal-month-8=8月
ccn-i18n-universal-month-9=9月
ccn-i18n-universal-month-10=10月
ccn-i18n-universal-month-11=11月
ccn-i18n-universal-month-12=12月
ccn-i18n-messagebox-confirm=确认
ccn-i18n-messagebox-title=通知
ccn-i18n-datetimepicker-confirm=确认
ccn-i18n-datetimepicker-cancel=取消
ccn-i18n-js-fail-login=登陆失败,请检查您的用户名和密码。
ccn-i18n-js-fail-logout=由于未知原因,登出失败,请考虑刷新页面解决问题。
ccn-i18n-js-fail-get=一个获取操作失败了,可能是系统错误或者您的权限不足。刷新页面可能会解决问题。请在刷新页面前备份好自己的数据。
ccn-i18n-js-fail-add=一个添加操作失败了,可能是您输入的参数有误。刷新页面可能会解决问题。请在刷新页面前备份好自己的数据。
ccn-i18n-js-fail-update=一个更新操作失败了,可能是没有找到匹配的条目或者您的参数输入错误。刷新页面可能会解决问题。请在刷新页面前备份好自己的数据。
ccn-i18n-js-fail-delete=一个删除操作失败了,可能是没有找到对应条目。刷新页面可能会解决问题。请在刷新页面前备份好自己的数据。
ccn-i18n-js-success=操作成功
ccn-i18n-js-fail-form=您所填写的事件内容存在缺漏或有错误字段,请检查后再提交。
ccn-i18n-home-desc=<h1 class="title">coconut-leaf</h1><p>一个轻量的自建日历系统</p><p>原本是出于yyc12345的个人使用而制作的。</p><br /><p>欢迎提出Pull request / issue / 翻译</p><p>将他们提交到我们的<a href="https://github.com/yyc12345/coconut-leaf">GitHub项目</a>.</p><p>本工程代码使用<a href="https://www.gnu.org/licenses/agpl-3.0.html">AGPL v3</a>授权。</p>
ccn-i18n-login-form-username=用户名
ccn-i18n-login-form-password=密码
ccn-i18n-login-form-login=登录
ccn-i18n-todo-todoList=待办列表
ccn-i18n-calendar-calendar-today=今天
ccn-i18n-calendar-calendar-add=添加...
ccn-i18n-calendar-calendar-stripedEvents=共{0}项
ccn-i18n-calendar-calendar-scheduleList=日程安排
ccn-i18n-calendar-tabcontrol-tabCalendar=日历
ccn-i18n-calendar-tabcontrol-tabCollection=集合
ccn-i18n-calendar-tabcontrol-tabDisplay=显示设置
ccn-i18n-calendar-owned-list=我的集合
ccn-i18n-calendar-shared-list=被共享的集合
ccn-i18n-calendar-display-firstDayOfWeek=每周开始星期
ccn-i18n-calendar-display-subcalendar=副日历
ccn-i18n-calendar-display-subcalendar-chineseLunisolarCalendar=中国农历
ccn-i18n-collection-owned-list=我的集合
ccn-i18n-collection-sharing-list=分享目标
ccn-i18n-collection-sharing-editing=正在编辑集合:
ccn-i18n-event-header=编辑事件
ccn-i18n-event-title=标题
ccn-i18n-event-description=描述
ccn-i18n-event-color=颜色
ccn-i18n-event-collection=集合
ccn-i18n-event-startDateTime=开始时间
ccn-i18n-event-endDateTime=结束时间
ccn-i18n-event-btnSpot=时间点
ccn-i18n-event-btnFullDay=全天
ccn-i18n-event-loop=事件循环
ccn-i18n-event-loop-never=从不
ccn-i18n-event-loop-day=按天
ccn-i18n-event-loop-week=按周
ccn-i18n-event-loop-month=按月
ccn-i18n-event-loop-year=按年
ccn-i18n-event-loopDay-span=间隔天数
ccn-i18n-event-loopWeek-span=间隔周数
ccn-i18n-event-loopWeek-option=在下列这些星期上循环
ccn-i18n-event-loopMonth-span=间隔月数
ccn-i18n-event-loopWeek-option=月份模式
ccn-i18n-event-loopWeek-optionA=第{0}天
ccn-i18n-event-loopWeek-optionB=倒数第{0}天
ccn-i18n-event-loopWeek-optionC=第{0}个星期{1}
ccn-i18n-event-loopWeek-optionD=倒数第{0}个星期{1}
ccn-i18n-event-loopYear-span=间隔年数
ccn-i18n-event-loopStop=事件循环停止方式
ccn-i18n-event-loopStop-forever=永不停止
ccn-i18n-event-loopStop-datetime=指定时间
ccn-i18n-event-loopStop-times=指定次数
ccn-i18n-event-timezone-title=时区设定
ccn-i18n-event-timezone-warning=您当前设置的事件的时区与您的时区不匹配,本页面以事件的原时区进行时间显示。您可以在下面修改您对于此事件的时区选择,如果您不熟悉时区,请选择保持原有时区。
ccn-i18n-event-timezone-keep=保持原有时区
ccn-i18n-event-timezone-replace=使用我现在的时区
ccn-i18n-event-strictMode-title=循环的严格与宽松
ccn-i18n-event-strictMode-warning=允许您在严格模式与宽松模式种进行选择,此选择只对循环事件有效。
ccn-i18n-event-strictMode-strict=严格模式,严格遵守日期要求,如果日期不存在,就不安排。
ccn-i18n-event-strictMode-rough=宽松模式,不在意日期要求的精确性,如果日期不存在,则找到最近的符合条件的日子安排。
ccn-i18n-event-btnSubmit=提交
ccn-i18n-event-btnCancel=取消
ccn-i18n-sharedItem-sharedBy=共享人:
ccn-i18n-admin-tabcontrol-tabProfile=我的资料
ccn-i18n-admin-tabcontrol-tabToken=管理多端登录
ccn-i18n-admin-tabcontrol-tabUserList=管理用户
ccn-i18n-admin-changePassword=更改密码
ccn-i18n-admin-manageToken=管理多端登录
ccn-i18n-admin-manageToken-desc=管理当前帐号的多端登录。您可以在这里强制下线某些地方的帐号。
ccn-i18n-admin-userList=用户列表
ccn-i18n-userItem-newPassword=新密码
ccn-i18n-userItem-isAdmin=是管理员
ccn-i18n-tokenItem-ua=UA
ccn-i18n-tokenItem-ip=IP
ccn-i18n-tokenItem-expireOn=过期时间:
ccn-i18n-tokenItem-isMe=这是你当前使用的登录凭据
ccn-i18n-datetime-loopStopRuleText-infinity=永远循环。
ccn-i18n-datetime-loopStopRuleText-datetime=到{0}停止循环。
ccn-i18n-datetime-loopStopRuleText-times=循环{0}次。
ccn-i18n-datetime-loopRuleText-modeStrict=严格模式。
ccn-i18n-datetime-loopRuleText-modeRough=宽松模式。
ccn-i18n-datetime-loopRuleText-year=每{0}年于{1}循环一次。
ccn-i18n-datetime-loopRuleText-monthA=每{0}月的第{1}日循环一次。
ccn-i18n-datetime-loopRuleText-monthB=每{0}月的倒数第{1}日循环一次。
ccn-i18n-datetime-loopRuleText-monthC=每{0}月的第{1}个星期{2}循环一次。
ccn-i18n-datetime-loopRuleText-monthD=每{0}月的倒数第{1}个星期{2}循环一次。
ccn-i18n-datetime-loopRuleText-week=每{0}周的{1}循环一次。
ccn-i18n-datetime-loopRuleText-day=每{0}天循环一次。

View File

@@ -1,483 +0,0 @@
// 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
}
);
}

View File

@@ -1,441 +0,0 @@
// 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;
}

View File

@@ -1,522 +0,0 @@
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('&nbsp;');
}
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('&nbsp;');
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);
}

View File

@@ -1,61 +0,0 @@
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");
});
}

View File

@@ -1,89 +0,0 @@
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));
}

View File

@@ -1,21 +0,0 @@
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);
}

View File

@@ -1,19 +0,0 @@
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');
}

View File

@@ -1,265 +0,0 @@
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);
}

View File

@@ -1,376 +0,0 @@
// 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('&nbsp;');
// 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();
}
}

View File

@@ -1,288 +0,0 @@
// 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;
}
}

View File

@@ -1,447 +0,0 @@
// 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';
}
}

View File

@@ -1,19 +0,0 @@
$(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();
});

View File

@@ -1,58 +0,0 @@
$(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");
}

View File

@@ -1,190 +0,0 @@
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);
}

View File

@@ -1,10 +0,0 @@
// 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();
}

View File

@@ -1,50 +0,0 @@
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;
}

View File

@@ -1,70 +0,0 @@
/*
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;
};

View File

@@ -1,16 +0,0 @@
{{for start=0 end=6 step=1 itemVar="~row"}}
<div>
{{for start=0 end=7 step=1 itemVar="~column"}}
<div id="ccn-calendarItem-{{:~row}}-{{:~column}}">
<p><b id="ccn-calendarItem-title-{{:~row}}-{{:~column}}">&nbsp;</b>
<span id="ccn-calendarItem-desc-{{:~row}}-{{:~column}}"></span>
</p>
<div id="ccn-calendarItem-eventBox1-{{:~row}}-{{:~column}}" class="calendarItem-eventBox" enableDisplay="false"></div>
<div id="ccn-calendarItem-eventBox2-{{:~row}}-{{:~column}}" class="calendarItem-eventBox" enableDisplay="false"></div>
<div id="ccn-calendarItem-eventBox3-{{:~row}}-{{:~column}}" class="calendarItem-eventBox" enableDisplay="false"></div>
<div id="ccn-calendarItem-eventBox4-{{:~row}}-{{:~column}}" class="calendarItem-eventBox" enableDisplay="false"></div>
<p id="ccn-calendarItem-task-{{:~row}}-{{:~column}}">&nbsp;</p>
</div>
{{/for}}
</div>
{{/for}}

View File

@@ -1,200 +0,0 @@
<div id="ccn-datetimepicker-modal" class="modal" style="float: left; position: fixed; top: 0; bottom: 0; left: 0; right: 0;">
<div class="modal-background"></div>
<div class="modal-card" style="height: 70%;">
<header class="modal-card-head pickerHeader">
<div type="year"><small i18n-name="ccn-i18n-universal-text-year"></small><span id="ccn-datetimepicker-datetime-year">&nbsp;</span></div>
<div type="month"><small i18n-name="ccn-i18n-universal-text-month"></small><span id="ccn-datetimepicker-datetime-month">&nbsp;</span></div>
<div type="day"><small i18n-name="ccn-i18n-universal-text-day"></small><span id="ccn-datetimepicker-datetime-day">&nbsp;</span></div>
<div type="hour"><small i18n-name="ccn-i18n-universal-text-hour"></small><span id="ccn-datetimepicker-datetime-hour">&nbsp;</span></div>
<div type="minute"><small i18n-name="ccn-i18n-universal-text-minute"></small><span id="ccn-datetimepicker-datetime-minute">&nbsp;</span></div>
</header>
<div class="modal-card-body pickerContainer">
<div id="ccn-datetimepicker-panelYear">
<nav class="level is-mobile">
<div class="level-left">
<div class="level-item control">
<a id="ccn-datetimepiacker-panelYear-prevBtn" class="button">
<span class="icon is-small"><i class="fas fa-chevron-circle-left"></i></span>
</a>
</div>
</div>
<div id="ccn-datetimepiacker-panelYear-title" class="level-item"></div>
<div class="level-right">
<div class="level-item control">
<a id="ccn-datetimepiacker-panelYear-nextBtn" class="button">
<span class="icon is-small"><i class="fas fa-chevron-circle-right"></i></span>
</a>
</div>
</div>
</nav>
<div id="ccn-datetimepiacker-panelYear-table" class="perfectTable">
<div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
<div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
<div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
</div>
</div>
<div id="ccn-datetimepicker-panelMonth">
<nav class="level is-mobile">
<div class="level-left">
<div class="level-item control">
<a id="ccn-datetimepiacker-panelMonth-prevBtn" class="button">
<span class="icon is-small"><i class="fas fa-chevron-circle-left"></i></span>
</a>
</div>
</div>
<div id="ccn-datetimepiacker-panelMonth-title" class="level-item"></div>
<div class="level-right">
<div class="level-item control">
<a id="ccn-datetimepiacker-panelMonth-nextBtn" class="button">
<span class="icon is-small"><i class="fas fa-chevron-circle-right"></i></span>
</a>
</div>
</div>
</nav>
<div id="ccn-datetimepiacker-panelMonth-table" class="perfectTable">
<div>
<div i18n-name="ccn-i18n-universal-month-1"></div>
<div i18n-name="ccn-i18n-universal-month-2"></div>
<div i18n-name="ccn-i18n-universal-month-3"></div>
<div i18n-name="ccn-i18n-universal-month-4"></div>
</div>
<div>
<div i18n-name="ccn-i18n-universal-month-5"></div>
<div i18n-name="ccn-i18n-universal-month-6"></div>
<div i18n-name="ccn-i18n-universal-month-7"></div>
<div i18n-name="ccn-i18n-universal-month-8"></div>
</div>
<div>
<div i18n-name="ccn-i18n-universal-month-9"></div>
<div i18n-name="ccn-i18n-universal-month-10"></div>
<div i18n-name="ccn-i18n-universal-month-11"></div>
<div i18n-name="ccn-i18n-universal-month-12"></div>
</div>
</div>
</div>
<div id="ccn-datetimepicker-panelDay">
<nav class="level is-mobile">
<div class="level-left">
<div class="level-item control">
<a id="ccn-datetimepiacker-panelDay-prevBtn" class="button">
<span class="icon is-small"><i class="fas fa-chevron-circle-left"></i></span>
</a>
</div>
</div>
<div id="ccn-datetimepiacker-panelDay-title" class="level-item"></div>
<div class="level-right">
<div class="level-item control">
<a id="ccn-datetimepiacker-panelDay-nextBtn" class="button">
<span class="icon is-small"><i class="fas fa-chevron-circle-right"></i></span>
</a>
</div>
</div>
</nav>
<div id="ccn-datetimepiacker-panelDay-table" class="perfectTable">
<div>
<div i18n-name="ccn-i18n-universal-week-1"></div>
<div i18n-name="ccn-i18n-universal-week-2"></div>
<div i18n-name="ccn-i18n-universal-week-3"></div>
<div i18n-name="ccn-i18n-universal-week-4"></div>
<div i18n-name="ccn-i18n-universal-week-5"></div>
<div i18n-name="ccn-i18n-universal-week-6"></div>
<div i18n-name="ccn-i18n-universal-week-7"></div>
</div>
<div>
<div></div><div></div><div></div><div></div><div></div><div></div><div></div>
</div>
<div>
<div></div><div></div><div></div><div></div><div></div><div></div><div></div>
</div>
<div>
<div></div><div></div><div></div><div></div><div></div><div></div><div></div>
</div>
<div>
<div></div><div></div><div></div><div></div><div></div><div></div><div></div>
</div>
<div>
<div></div><div></div><div></div><div></div><div></div><div></div><div></div>
</div>
<div>
<div></div><div></div><div></div><div></div><div></div><div></div><div></div>
</div>
</div>
</div>
<svg id="ccn-datetimepicker-panelHour" xmlns="http://www.w3.org/2000/svg" version="1.1" preserveAspectRatio="xMidYMid" viewBox="0 0 200 200">
<circle cx="100.000000" cy="100.000000" r="100.000000" type="background"></circle>
<line x1="100" y1="100" x2="100.000000" y2="20.000000"></line>
<circle cx="100.000000" cy="20.000000" r="1em" type="symbol"></circle>
<text x="100.000000" y="20.000000">0</text>
<text x="140.000000" y="30.717968">1</text>
<text x="169.282032" y="60.000000">2</text>
<text x="180.000000" y="100.000000">3</text>
<text x="169.282032" y="140.000000">4</text>
<text x="140.000000" y="169.282032">5</text>
<text x="100.000000" y="180.000000">6</text>
<text x="60.000000" y="169.282032">7</text>
<text x="30.717968" y="140.000000">8</text>
<text x="20.000000" y="100.000000">9</text>
<text x="30.717968" y="60.000000">10</text>
<text x="60.000000" y="30.717968">11</text>
<text x="100.000000" y="40.000000">12</text>
<text x="130.000000" y="48.038476">13</text>
<text x="151.961524" y="70.000000">14</text>
<text x="160.000000" y="100.000000">15</text>
<text x="151.961524" y="130.000000">16</text>
<text x="130.000000" y="151.961524">17</text>
<text x="100.000000" y="160.000000">18</text>
<text x="70.000000" y="151.961524">19</text>
<text x="48.038476" y="130.000000">20</text>
<text x="40.000000" y="100.000000">21</text>
<text x="48.038476" y="70.000000">22</text>
<text x="70.000000" y="48.038476">23</text>
</svg>
<svg id="ccn-datetimepicker-panelMinute" xmlns="http://www.w3.org/2000/svg" version="1.1" preserveAspectRatio="xMidYMid" viewBox="0 0 200 200">
<circle cx="100.000000" cy="100.000000" r="100.000000" type="background"></circle>
<line x1="100" y1="100" x2="100.000000" y2="20.000000"></line>
<circle cx="100.000000" cy="20.000000" r="1em" type="symbol"></circle>
<text x="100.000000" y="20.000000">0</text>
<text x="140.000000" y="30.717968">5</text>
<text x="169.282032" y="60.000000">10</text>
<text x="180.000000" y="100.000000">15</text>
<text x="169.282032" y="140.000000">20</text>
<text x="140.000000" y="169.282032">25</text>
<text x="100.000000" y="180.000000">30</text>
<text x="60.000000" y="169.282032">35</text>
<text x="30.717968" y="140.000000">40</text>
<text x="20.000000" y="100.000000">45</text>
<text x="30.717968" y="60.000000">50</text>
<text x="60.000000" y="30.717968">55</text>
</svg>
</div>
<footer class="modal-card-foot">
<a id="ccn-datetimepicker-btnConfirm" class="button is-success">
<span i18n-name="ccn-i18n-datetimepicker-confirm"></span>
</a>
<a id="ccn-datetimepicker-btnCancel" class="button">
<span i18n-name="ccn-i18n-datetimepicker-cancel"></span>
</a>
</footer>
</div>
</div>

View File

@@ -1,12 +0,0 @@
<div id="ccn-displayOwnedItem-{{:uuid}}" class="collection-item card">
<div class="collection-item-words">
<p>{{>name}}</p>
</div>
<div id="ccn-displayOwnedItem-btnHide-{{:uuid}}" uuid="{{:uuid}}" class="collection-item-icon control">
<a class="button"><span class="icon is-small"><i class="fas fa-eye"></i></span></a>
</div>
<div id="ccn-displayOwnedItem-btnShow-{{:uuid}}" uuid="{{:uuid}}" class="collection-item-icon control">
<a class="button"><span class="icon is-small"><i class="fas fa-eye-slash"></i></span></a>
</div>
</div>

View File

@@ -1,16 +0,0 @@
<div id="ccn-displaySharedItem-{{:uuid}}" class="collection-item card">
<div class="collection-item-words">
<b>{{>name}}</b>
<p>
<span i18n-name="ccn-i18n-sharedItem-sharedBy"></span>
<span>{{>username}}</span>
</p>
</div>
<div id="ccn-displaySharedItem-btnHide-{{:uuid}}" uuid="{{:uuid}}" class="collection-item-icon control">
<a class="button"><span class="icon is-small"><i class="fas fa-eye"></i></span></a>
</div>
<div id="ccn-displaySharedItem-btnShow-{{:uuid}}" uuid="{{:uuid}}" class="collection-item-icon control">
<a class="button"><span class="icon is-small"><i class="fas fa-eye-slash"></i></span></a>
</div>
</div>

View File

@@ -1,42 +0,0 @@
<nav class="navbar has-shadow is-spaced bd-navbar" role="navigation" aria-label="main navigation">
<div class="navbar-brand">
<a class="navbar-item" href="home">
<img src="/static/image/icon.png"><b style="margin:0 0 0 14px;">coconut-leaf</b>
</a>
<a role="button" class="navbar-burger burger" aria-label="menu" aria-expanded="false"
data-target="navbarBasicExample">
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
</a>
</div>
<div id="navbarBasicExample" class="navbar-menu">
<div class="navbar-start">
<a i18n-name="ccn-i18n-header-nav-home" id="ccn-header-nav-home" class="navbar-item" href="/web/home"></a>
<a i18n-name="ccn-i18n-header-nav-collection" id="ccn-header-nav-collection" class="navbar-item" href="/web/collection"></a>
<a i18n-name="ccn-i18n-header-nav-calendar" id="ccn-header-nav-calendar" class="navbar-item" href="/web/calendar"></a>
<a i18n-name="ccn-i18n-header-nav-todo" id="ccn-header-nav-todo" class="navbar-item" href="/web/todo"></a>
<a i18n-name="ccn-i18n-header-nav-admin" id="ccn-header-nav-admin" class="navbar-item" href="/web/admin"></a>
</div>
<div class="navbar-end">
<p id="ccn-header-user-login" class="navbar-item">
<a class="button is-primary" i18n-name="ccn-i18n-header-user-login" href="/web/login"></a>
</p>
<p id="ccn-header-user-logout" class="navbar-item">
<a class="button is-primary" i18n-name="ccn-i18n-header-user-logout"></a>
</p>
<div class="navbar-item has-dropdown is-hoverable">
<a class="navbar-link" i18n-name="ccn-i18n-header-language"></a>
<div id="ccn-header-language" class="navbar-dropdown">
<a language="en-US" class="navbar-item">English</a>
<a language="zh-CN" class="navbar-item">简体中文</a>
</div>
</div>
</div>
</div>
</nav>

View File

@@ -1,15 +0,0 @@
<div id="ccn-messagebox-modal" class="modal" style="float: left; position: fixed; top: 0; bottom: 0; left: 0; right: 0;">
<div class="modal-background"></div>
<div class="modal-card">
<header class="modal-card-head">
<p id="ccn-messagebox-title" class="modal-card-title" i18n-name="ccn-i18n-messagebox-title"></p>
<button id="ccn-messagebox-btnClose" class="delete" aria-label="close"></button>
</header>
<div class="modal-card-body">
<p id="ccn-messagebox-body"></p>
</div>
<footer class="modal-card-foot">
<button id="ccn-messagebox-btnConfirm" class="button is-success" i18n-name="ccn-i18n-messagebox-confirm"></button>
</footer>
</div>
</div>

View File

@@ -1 +0,0 @@
<option value="{{:val}}">{{>name}}</option>

View File

@@ -1,24 +0,0 @@
<div id="ccn-ownedItem-{{:uuid}}" class="collection-item card">
<div class="collection-item-words">
<p id="ccn-ownedItem-textName-{{:uuid}}">{{>name}}</p>
<div id="ccn-ownedItem-boxName-{{:uuid}}" class="control">
<input id="ccn-ownedItem-inputName-{{:uuid}}" class="input" type="text"></input>
</div>
</div>
<div id="ccn-ownedItem-btnEdit-{{:uuid}}" uuid="{{:uuid}}" class="collection-item-icon control">
<a class="button"><span class="icon is-small"><i class="fas fa-pen"></i></span></a>
</div>
<div id="ccn-ownedItem-btnShare-{{:uuid}}" uuid="{{:uuid}}" class="collection-item-icon control">
<a class="button"><span class="icon is-small"><i class="fas fa-share"></i></a>
</div>
<div id="ccn-ownedItem-btnDelete-{{:uuid}}" uuid="{{:uuid}}" class="collection-item-icon control">
<a class="button"><span class="icon is-small"><i class="fas fa-trash"></i></a>
</div>
<div id="ccn-ownedItem-btnUpdate-{{:uuid}}" uuid="{{:uuid}}" class="collection-item-icon control">
<button class="button"><span class="icon is-small"><i class="fas fa-check"></i></span></button>
</div>
<div id="ccn-ownedItem-btnCancelUpdate-{{:uuid}}" uuid="{{:uuid}}" class="collection-item-icon control">
<button class="button"><span class="icon is-small"><i class="fas fa-times"></i></button>
</div>
</div>

View File

@@ -1,36 +0,0 @@
{{for renderdata}}
<div class="schedule-day container">
<div class="schedule-day-words">
<b i18n-name="ccn-i18n-universal-month-{{:month}}"></b>
<b>{{>day}}</b>
<b i18n-name="ccn-i18n-universal-week-{{:dayOfWeek}}"></b>
</div>
<div class="schedule-event-list">
{{for events}}
{{if isVisible}}
<div class="schedule-event-outter card" uuid="{{:uuid}}">
<div class="schedule-event-color" style="background: {{:color}};"></div>
<div class="schedule-event-inner">
<div class="schedule-event-words">
<p class="level-item"><b>{{>title}}</b></p>
<p class="level-item">{{>description}}</p>
<p class="level-item"><span>{{>start}}</span>-<span>{{>end}}</span></p>
{{if loopText != ""}}
<p><span class="icon is-small"><i class="fas fa-retweet"></i></span><span>{{>loopText}}</span></p>
{{/if}}
</div>
<div class="schedule-event-icon">
{{if isLocked}}
<span class="icon is-small"><i class="fas fa-lock"></i></span>
{{/if}}
{{if timezoneWarning}}
<span class="icon is-small"><i class="fas fa-globe"></i></span>
{{/if}}
</div>
</div>
</div>
{{/if}}
{{/for}}
</div>
</div>
{{/for}}

View File

@@ -1,9 +0,0 @@
<div id="ccn-sharingItem-{{:uuid}}" class="collection-item card">
<div class="collection-item-words">
<p>{{>username}}</p>
</div>
<div id="ccn-sharingItem-btnDelete-{{:uuid}}" uuid="{{:uuid}}" class="collection-item-icon control">
<a class="button"><span class="icon is-small"><i class="fas fa-trash"></i></span></a>
</div>
</div>

View File

@@ -1,20 +0,0 @@
<div id="ccn-todoItem-{{:uuid}}" class="todo-item card">
<div class="todo-item-words">
<p id="ccn-todoItem-p-{{:uuid}}">{{:data}}</p>
<textarea id="ccn-todoItem-textarea-{{:uuid}}" class="textarea"></textarea>
</div>
<div id="ccn-todoItem-btnEdit-{{:uuid}}" uuid="{{:uuid}}" class="todo-item-icon control">
<button class="button"><span class="icon is-small"><i class="fas fa-pen"></i></span></button>
</div>
<div id="ccn-todoItem-btnDelete-{{:uuid}}" uuid="{{:uuid}}" class="todo-item-icon control">
<button class="button"><span class="icon is-small"><i class="fas fa-trash"></i></button>
</div>
<div id="ccn-todoItem-btnUpdate-{{:uuid}}" uuid="{{:uuid}}" class="todo-item-icon control">
<button class="button"><span class="icon is-small"><i class="fas fa-check"></i></span></button>
</div>
<div id="ccn-todoItem-btnCancelUpdate-{{:uuid}}" uuid="{{:uuid}}" class="todo-item-icon control">
<button class="button"><span class="icon is-small"><i class="fas fa-times"></i></button>
</div>
</div>

View File

@@ -1,27 +0,0 @@
<div id="ccn-tokenItem-{{:uuid}}" class="token-item card">
<div class="token-item-words">
<b>{{>uuid}}</b>
<p>
<span i18n-name="ccn-i18n-tokenItem-ua"></span>
<span>{{>ua}}</span>
</p>
<p>
<span i18n-name="ccn-i18n-tokenItem-ip"></span>
<span>{{>ip}}</span>
</p>
<p>
<span i18n-name="ccn-i18n-tokenItem-expireOn"></span>
<span>{{>expireOn}}</span>
</p>
{{if isMe}}
<p>
<span class="icon is-small"><i class="fas fa-exclamation-triangle"></i></span>
<span i18n-name="ccn-i18n-tokenItem-isMe"></span>
</p>
{{/if}}
</div>
<div id="ccn-tokenItem-btnLogout-{{:uuid}}" uuid="{{:uuid}}" class="token-item-icon control">
<a class="button"><span class="icon is-small"><i class="fas fa-sign-out-alt"></i></span></a>
</div>
</div>

View File

@@ -1,35 +0,0 @@
<div id="ccn-userItem-{{:uuid}}" class="user-item card">
<div class="user-item-words">
<div class="control" style="display: flex; flex-flow: row; align-items: center;">
<div id="ccn-userItem-iconIsAdmin-{{:uuid}}" class="icon is-small" style="margin-right: 1rem;">
<i class="fas fa-wrench"></i>
</div>
<div id="ccn-userItem-textName-{{:uuid}}">{{>username}}</div>
</div>
<div id="ccn-userItem-boxPassword-{{:uuid}}" class="field">
<label class="label" i18n-name="ccn-i18n-userItem-newPassword"></label>
<div class="control">
<input id="ccn-userItem-inputPassword-{{:uuid}}" class="input" type="password"></input>
</div>
</div>
<div id="ccn-userItem-boxIsAdmin-{{:uuid}}" class="field">
<label class="checkbox">
<input id="ccn-userItem-inputIsAdmin-{{:uuid}}" type="checkbox"><span i18n-name="ccn-i18n-userItem-isAdmin"></span>
</label>
</div>
</div>
<div id="ccn-userItem-btnEdit-{{:uuid}}" uuid="{{:uuid}}" class="user-item-icon control">
<a class="button"><span class="icon is-small"><i class="fas fa-pen"></i></span></a>
</div>
<div id="ccn-userItem-btnDelete-{{:uuid}}" uuid="{{:uuid}}" class="user-item-icon control">
<a class="button"><span class="icon is-small"><i class="fas fa-trash"></i></span></a>
</div>
<div id="ccn-userItem-btnUpdate-{{:uuid}}" uuid="{{:uuid}}" class="user-item-icon control">
<a class="button"><span class="icon is-small"><i class="fas fa-check"></i></span></a>
</div>
<div id="ccn-userItem-btnCancelUpdate-{{:uuid}}" uuid="{{:uuid}}" class="user-item-icon control">
<a class="button"><span class="icon is-small"><i class="fas fa-times"></i></span></a>
</div>
</div>

View File

@@ -1,100 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title id="ccn-pageName"></title>
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.9.1/css/bulma.min.css">
<script src="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@5.12.1/js/all.min.js"></script>
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/jquery@3.4.1/dist/jquery.js"></script>
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/jquery-i18n-properties@1.2.7/jquery.i18n.properties.js"></script>
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/jsrender@1.0.10/jsrender.min.js"></script>
<script type="text/x-jsrender" id="jsrender-tmpl-headerNav" src="/static/tmpl/headerNav.tmpl"></script>
<script type="text/x-jsrender" id="jsrender-tmpl-messagebox" src="/static/tmpl/messagebox.tmpl"></script>
<script type="text/x-jsrender" id="jsrender-tmpl-userItem" src="/static/tmpl/userItem.tmpl"></script>
<script type="text/x-jsrender" id="jsrender-tmpl-tokenItem" src="/static/tmpl/tokenItem.tmpl"></script>
<script type="text/javascript" src="/static/js/localStorageAssist.js"></script>
<script type="text/javascript" src="/static/js/i18n.js"></script>
<script type="text/javascript" src="/static/js/utils.js"></script>
<script type="text/javascript" src="/static/js/api.js"></script>
<script type="text/javascript" src="/static/js/template.js"></script>
<script type="text/javascript" src="/static/js/headerNav.js"></script>
<script type="text/javascript" src="/static/js/tabcontrol.js"></script>
<script type="text/javascript" src="/static/js/messagebox.js"></script>
<script type="text/javascript" src="/static/js/page/admin.js"></script>
<link rel="stylesheet" href="/static/css/admin.css">
</head>
<body>
<div class="container" style="margin-top: 20px;">
<div class="tabs">
<ul>
<li id="tabcontrol-tab-1-1" class="tabcontrol-tab-1"><a
i18n-name="ccn-i18n-admin-tabcontrol-tabProfile"></a></li>
<li id="tabcontrol-tab-1-2" class="tabcontrol-tab-1"><a
i18n-name="ccn-i18n-admin-tabcontrol-tabToken"></a></li>
<li id="tabcontrol-tab-1-3" class="tabcontrol-tab-1"><a
i18n-name="ccn-i18n-admin-tabcontrol-tabUserList"></a></li>
</ul>
</div>
</div>
<div id="tabcontrol-panel-1-1" class="container tabcontrol-panel-1" style="margin-top: 20px;">
<h1 class="title" i18n-name="ccn-i18n-admin-changePassword"></h1>
<div class="field has-addons">
<div class="control">
<input id="ccn-admin-profile-inputPassword" class="input" type="password">
</div>
<div class="control">
<a id="ccn-admin-profile-btnChangePassword" class="button is-primary">
<span class="icon is-small"><i class="fas fa-key"></i></span>
</a>
</div>
</div>
</div>
<div id="tabcontrol-panel-1-2" class="container tabcontrol-panel-1" style="margin-top: 20px;">
<h1 class="title" i18n-name="ccn-i18n-admin-manageToken"></h1>
<h2 class="subtitle" i18n-name="ccn-i18n-admin-manageToken-desc"></h2>
<div id="ccn-admin-tokenList-btnRefresh" class="control">
<a class="button is-primary">
<span class="icon is-small"><i class="fas fa-sync"></i></span>
</a>
</div>
<div id="ccn-admin-tokenList" style="display: flex; flex-flow: column; margin-top: 1.25rem;">
</div>
</div>
<div id="tabcontrol-panel-1-3" class="container tabcontrol-panel-1" style="margin-top: 20px;">
<h1 class="title" i18n-name="ccn-i18n-admin-userList"></h1>
<div class="control-list">
<div class="field has-addons">
<div class="control">
<input id="ccn-admin-userList-inputUsername" class="input" type="text">
</div>
<div id="ccn-admin-userList-btnAdd" class="control">
<a class="button is-primary">
<span class="icon is-small"><i class="fas fa-plus"></i></span>
</a>
</div>
</div>
<div id="ccn-admin-userList-btnRefresh" class="control">
<a class="button is-primary">
<span class="icon is-small"><i class="fas fa-sync"></i></span>
</a>
</div>
</div>
<div id="ccn-admin-userList" style="display: flex; flex-flow: column; margin-top: 1.25rem;">
</div>
</div>
</body>
</html>

View File

@@ -1,156 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title id="ccn-pageName"></title>
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.9.1/css/bulma.min.css">
<script src="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@5.12.1/js/all.min.js"></script>
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/jquery@3.4.1/dist/jquery.js"></script>
<script type="text/javascript"
src="https://cdn.jsdelivr.net/npm/jquery-i18n-properties@1.2.7/jquery.i18n.properties.js"></script>
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/jsrender@1.0.10/jsrender.min.js"></script>
<script type="text/x-jsrender" id="jsrender-tmpl-headerNav" src="/static/tmpl/headerNav.tmpl"></script>
<script type="text/x-jsrender" id="jsrender-tmpl-messagebox" src="/static/tmpl/messagebox.tmpl"></script>
<script type="text/x-jsrender" id="jsrender-tmpl-datetimepicker" src="/static/tmpl/datetimepicker.tmpl"></script>
<script type="text/x-jsrender" id="jsrender-tmpl-calendarItem" src="/static/tmpl/calendarItem.tmpl"></script>
<script type="text/x-jsrender" id="jsrender-tmpl-scheduleItem" src="/static/tmpl/scheduleItem.tmpl"></script>
<script type="text/x-jsrender" id="jsrender-tmpl-displayOwnedItem" src="/static/tmpl/displayOwnedItem.tmpl"></script>
<script type="text/x-jsrender" id="jsrender-tmpl-displaySharedItem" src="/static/tmpl/displaySharedItem.tmpl"></script>
<script type="text/javascript" src="/static/js/localStorageAssist.js"></script>
<script type="text/javascript" src="/static/js/datetime.js"></script>
<script type="text/javascript" src="/static/js/i18n.js"></script>
<script type="text/javascript" src="/static/js/utils.js"></script>
<script type="text/javascript" src="/static/js/api.js"></script>
<script type="text/javascript" src="/static/js/template.js"></script>
<script type="text/javascript" src="/static/js/headerNav.js"></script>
<script type="text/javascript" src="/static/js/tabcontrol.js"></script>
<script type="text/javascript" src="/static/js/messagebox.js"></script>
<script type="text/javascript" src="/static/js/datetimepicker.js"></script>
<script type="text/javascript" src="/static/js/page/calendar.js"></script>
<link rel="stylesheet" href="/static/css/calendar.css">
<link rel="stylesheet" href="/static/css/datetimepicker.css">
</head>
<body>
<div class="container" style="margin-top: 20px;">
<div class="tabs">
<ul>
<li id="tabcontrol-tab-1-1" class="tabcontrol-tab-1"><a
i18n-name="ccn-i18n-calendar-tabcontrol-tabCalendar"></a></li>
<li id="tabcontrol-tab-1-2" class="tabcontrol-tab-1"><a
i18n-name="ccn-i18n-calendar-tabcontrol-tabCollection"></a></li>
<li id="tabcontrol-tab-1-3" class="tabcontrol-tab-1"><a
i18n-name="ccn-i18n-calendar-tabcontrol-tabDisplay"></a></li>
</ul>
</div>
</div>
<div id="tabcontrol-panel-1-1" class="container tabcontrol-panel-1" style="margin-top: 20px;">
<nav class="level is-mobile">
<div class="level-left">
<div class="level-item control">
<a id="ccn-calendar-calendar-btnPrevMonth" class="button">
<span class="icon is-small"><i class="fas fa-chevron-circle-left"></i></span>
</a>
</div>
</div>
<div class="level-item control">
<a id="ccn-calendar-calendar-btnJump" class="button" datetimepicker="1">
<span id="ccn-calendar-calendar-textMonth"></span>
</a>
</div>
<div class="level-right">
<div class="level-item control">
<a id="ccn-calendar-calendar-btnNextMonth" class="button">
<span class="icon is-small"><i class="fas fa-chevron-circle-right"></i></span>
</a>
</div>
</div>
</nav>
<nav class="level is-mobile">
<div class="level-item control">
<a id="ccn-calendar-calendar-btnToday" i18n-name="ccn-i18n-calendar-calendar-today" class="button is-info"></a>
</div>
<div class="level-item control">
<a id="ccn-calendar-calendar-btnAdd" i18n-name="ccn-i18n-calendar-calendar-add" class="button is-primary"></a>
</div>
</nav>
<div id="ccn-calendar-calendarBody" class="card" style="padding: 1.25rem; display: flex; flex-flow: column;">
<div style="margin: 0 0 0.75em 0;">
<div><b i18n-name="ccn-i18n-universal-week-1"></b></div>
<div><b i18n-name="ccn-i18n-universal-week-2"></b></div>
<div><b i18n-name="ccn-i18n-universal-week-3"></b></div>
<div><b i18n-name="ccn-i18n-universal-week-4"></b></div>
<div><b i18n-name="ccn-i18n-universal-week-5"></b></div>
<div><b i18n-name="ccn-i18n-universal-week-6" style="color: red;"></b></div>
<div><b i18n-name="ccn-i18n-universal-week-7" style="color: red;"></b></div>
</div>
</div>
<div class="container" style="padding: 1.25rem; display: flex; flex-flow: column; margin-top: 1.25rem;">
<h1 i18n-name="ccn-i18n-calendar-calendar-scheduleList" class="title"></h1>
<div id="ccn-calendar-scheduleList">
</div>
</div>
</div>
<div id="tabcontrol-panel-1-2" class="container tabcontrol-panel-1" style="margin-top: 20px;">
<div id="ccn-calendar-collection-btnRefresh" class="control" style="margin: 0.75rem;">
<a class="button is-primary">
<span class="icon is-small"><i class="fas fa-sync"></i></span>
</a>
</div>
<h1 i18n-name="ccn-i18n-calendar-owned-list" class="title"></h1>
<div id="ccn-calendar-ownedList" style="display: flex; flex-flow: column; margin-top: 1.25rem; margin-bottom: 1.25rem;">
</div>
<h1 i18n-name="ccn-i18n-calendar-shared-list" class="title"></h1>
<div id="ccn-calendar-sharedList" style="display: flex; flex-flow: column; margin-top: 1.25rem; margin-bottom: 1.25rem;">
</div>
</div>
<div id="tabcontrol-panel-1-3" class="container tabcontrol-panel-1" style="margin-top: 20px;">
<div class="field">
<label class="label" i18n-name="ccn-i18n-calendar-display-firstDayOfWeek"></label>
<div class="control">
<div class="select">
<select id="ccn-calendar-display-firstDayOfWeek">
<option i18n-name="ccn-i18n-universal-week-1"></option>
<option i18n-name="ccn-i18n-universal-week-2"></option>
<option i18n-name="ccn-i18n-universal-week-3"></option>
<option i18n-name="ccn-i18n-universal-week-4"></option>
<option i18n-name="ccn-i18n-universal-week-5"></option>
<option i18n-name="ccn-i18n-universal-week-6"></option>
<option i18n-name="ccn-i18n-universal-week-7"></option>
</select>
</div>
</div>
</div>
<div class="field">
<label class="label" i18n-name="ccn-i18n-calendar-display-subcalendar"></label>
<div class="control">
<div class="select">
<select id="ccn-calendar-display-subcalendar">
<option i18n-name="ccn-i18n-calendar-display-subcalendar-chineseLunisolarCalendar"></option>
</select>
</div>
</div>
</div>
</div>
</body>
</html>

View File

@@ -1,94 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title id="ccn-pageName"></title>
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.9.1/css/bulma.min.css">
<script src="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@5.12.1/js/all.min.js"></script>
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/jquery@3.4.1/dist/jquery.js"></script>
<script type="text/javascript"
src="https://cdn.jsdelivr.net/npm/jquery-i18n-properties@1.2.7/jquery.i18n.properties.js"></script>
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/jsrender@1.0.10/jsrender.min.js"></script>
<script type="text/x-jsrender" id="jsrender-tmpl-headerNav" src="/static/tmpl/headerNav.tmpl"></script>
<script type="text/x-jsrender" id="jsrender-tmpl-messagebox" src="/static/tmpl/messagebox.tmpl"></script>
<script type="text/x-jsrender" id="jsrender-tmpl-ownedItem" src="/static/tmpl/ownedItem.tmpl"></script>
<script type="text/x-jsrender" id="jsrender-tmpl-sharingItem" src="/static/tmpl/sharingItem.tmpl"></script>
<script type="text/javascript" src="/static/js/localStorageAssist.js"></script>
<script type="text/javascript" src="/static/js/i18n.js"></script>
<script type="text/javascript" src="/static/js/utils.js"></script>
<script type="text/javascript" src="/static/js/api.js"></script>
<script type="text/javascript" src="/static/js/template.js"></script>
<script type="text/javascript" src="/static/js/headerNav.js"></script>
<script type="text/javascript" src="/static/js/tabcontrol.js"></script>
<script type="text/javascript" src="/static/js/messagebox.js"></script>
<script type="text/javascript" src="/static/js/page/collection.js"></script>
<link rel="stylesheet" href="/static/css/collection.css">
</head>
<body>
<div style="margin-top: 20px;">
<div class="container" style="display: flex; flex-flow: column;">
<h1 i18n-name="ccn-i18n-collection-owned-list" class="title"></h1>
<div class="control-list">
<div class="field has-addons">
<div class="control">
<input id="ccn-collection-owned-inputAdd" class="input" type="text">
</div>
<div id="ccn-collection-owned-btnAdd" class="control">
<a class="button is-primary">
<span class="icon is-small"><i class="fas fa-plus"></i></span>
</a>
</div>
</div>
<div id="ccn-collection-owned-btnRefresh" class="control">
<a class="button is-primary">
<span class="icon is-small"><i class="fas fa-sync"></i></span>
</a>
</div>
</div>
<div id="ccn-collection-ownedList" style="display: flex; flex-flow: column; margin-top: 1.25rem;">
</div>
</div>
<div id="ccn-collection-sharing-container" class="container" style="display: flex; flex-flow: column;">
<h1 i18n-name="ccn-i18n-collection-sharing-list" class="title"></h1>
<label class="label"><span i18n-name="ccn-i18n-collection-sharing-editing"></span>
<span id="ccn-collection-sharing-sharingEditing"></span>
</label>
<div class="control-list">
<div class="field has-addons">
<div class="control">
<input id="ccn-collection-sharing-inputAdd" class="input" type="text">
</div>
<div id="ccn-collection-sharing-btnAdd" class="control">
<a class="button is-primary">
<span class="icon is-small"><i class="fas fa-plus"></i></span>
</a>
</div>
</div>
<div id="ccn-collection-sharing-btnRefresh" class="control">
<a class="button is-primary">
<span class="icon is-small"><i class="fas fa-sync"></i></span>
</a>
</div>
</div>
<div id="ccn-collection-sharingList" style="display: flex; flex-flow: column; margin-top: 1.25rem;">
</div>
</div>
</div>
</body>
</html>

View File

@@ -1,277 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title id="ccn-pageName"></title>
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.9.1/css/bulma.min.css">
<script src="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@5.12.1/js/all.min.js"></script>
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/jquery@3.4.1/dist/jquery.js"></script>
<script type="text/javascript"
src="https://cdn.jsdelivr.net/npm/jquery-i18n-properties@1.2.7/jquery.i18n.properties.js"></script>
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/jsrender@1.0.10/jsrender.min.js"></script>
<!-- if is empty, mean add, otherwise, it is a uuid-->
<meta name="uuid" content="{{uuidPath}}">
<script type="text/x-jsrender" id="jsrender-tmpl-headerNav" src="/static/tmpl/headerNav.tmpl"></script>
<script type="text/x-jsrender" id="jsrender-tmpl-messagebox" src="/static/tmpl/messagebox.tmpl"></script>
<script type="text/x-jsrender" id="jsrender-tmpl-datetimepicker" src="/static/tmpl/datetimepicker.tmpl"></script>
<script type="text/x-jsrender" id="jsrender-tmpl-optionItem" src="/static/tmpl/optionItem.tmpl"></script>
<script type="text/javascript" src="/static/js/localStorageAssist.js"></script>
<script type="text/javascript" src="/static/js/datetime.js"></script>
<script type="text/javascript" src="/static/js/i18n.js"></script>
<script type="text/javascript" src="/static/js/utils.js"></script>
<script type="text/javascript" src="/static/js/api.js"></script>
<script type="text/javascript" src="/static/js/template.js"></script>
<script type="text/javascript" src="/static/js/headerNav.js"></script>
<script type="text/javascript" src="/static/js/messagebox.js"></script>
<script type="text/javascript" src="/static/js/datetimepicker.js"></script>
<script type="text/javascript" src="/static/js/page/event.js"></script>
<link rel="stylesheet" href="/static/css/event.css">
<link rel="stylesheet" href="/static/css/datetimepicker.css">
</head>
<body>
<!-- add is-active in class to show this-->
<div id="ccn-event-eventFormBody" class="container" style="margin-top: 20px;">
<h1 i18n-name="ccn-i18n-event-header" class="title"></h1>
<section class="section">
<div class="field">
<label class="label" i18n-name="ccn-i18n-event-title"></label>
<div class="control">
<input id="ccn-event-inputTitle" class="input" type="text">
</div>
</div>
<div class="field">
<label class="label" i18n-name="ccn-i18n-event-description"></label>
<div class="control">
<textarea id="ccn-event-inputDescription" class="textarea"></textarea>
</div>
</div>
<div class="field">
<label class="label" i18n-name="ccn-i18n-event-color"></label>
<div class="control">
<input id="ccn-event-inputColor" class="input" type="color">
</div>
</div>
<div class="field">
<label class="label" i18n-name="ccn-i18n-event-collection"></label>
<div class="control">
<div class="select">
<select id="ccn-event-inputCollection"></select>
</div>
</div>
</div>
</section>
<section class="section">
<h2 class="subtitle" i18n-name="ccn-i18n-event-startDateTime"></h2>
<a id="ccn-event-btnStartDateTime" class="button" datetimepicker="1">
<span id="ccn-event-btnStartDateTime-text"></span>
</a>
<h2 class="subtitle" i18n-name="ccn-i18n-event-endDateTime"></h2>
<div class="control-list">
<div class="control">
<a id="ccn-event-btnSpot" class="button is-link" i18n-name="ccn-i18n-event-btnSpot"></a>
</div>
<div class="control">
<a id="ccn-event-btnFullDay" class="button is-link" i18n-name="ccn-i18n-event-btnFullDay"></a>
</div>
</div>
<a id="ccn-event-btnEndDateTime" class="button" datetimepicker="2">
<span id="ccn-event-btnEndDateTime-text"></span>
</a>
</section>
<section class="section">
<h2 class="subtitle" i18n-name="ccn-i18n-event-loop"></h2>
<div class="control-list">
<label class="radio">
<input id="ccn-event-radioLoopNever" type="radio" name="loop-method">
<span i18n-name="ccn-i18n-event-loop-never"></span>
</label>
<label class="radio">
<input id="ccn-event-radioLoopDay" type="radio" name="loop-method">
<span i18n-name="ccn-i18n-event-loop-day"></span>
</label>
<label class="radio">
<input id="ccn-event-radioLoopWeek" type="radio" name="loop-method">
<span i18n-name="ccn-i18n-event-loop-week"></span>
</label>
<label class="radio">
<input id="ccn-event-radioLoopMonth" type="radio" name="loop-method">
<span i18n-name="ccn-i18n-event-loop-month"></span>
</label>
<label class="radio">
<input id="ccn-event-radioLoopYear" type="radio" name="loop-method">
<span i18n-name="ccn-i18n-event-loop-year"></span>
</label>
</div>
<div id="ccn-event-boxLoopDay">
<div class="field">
<label class="label" i18n-name="ccn-i18n-event-loopDay-span"></label>
<div class="control">
<input id="ccn-event-loopDay-inputSpan" class="input spanpicker" type="number">
</div>
</div>
</div>
<div id="ccn-event-boxLoopWeek">
<div class="field">
<label class="label" i18n-name="ccn-i18n-event-loopWeek-span"></label>
<div class="control">
<input id="ccn-event-loopWeek-inputSpan" class="input spanpicker" type="number">
</div>
</div>
<div class="field">
<label class="label" i18n-name="ccn-i18n-event-loopWeek-option"></label>
<div class="control-list">
<label class="checkbox">
<input id="ccn-event-loopWeek-check1" type="checkbox">
<span i18n-name="ccn-i18n-universal-week-1"></span>
</label>
<label class="checkbox">
<input id="ccn-event-loopWeek-check2" type="checkbox">
<span i18n-name="ccn-i18n-universal-week-2"></span>
</label>
<label class="checkbox">
<input id="ccn-event-loopWeek-check3" type="checkbox">
<span i18n-name="ccn-i18n-universal-week-3"></span>
</label>
<label class="checkbox">
<input id="ccn-event-loopWeek-check4" type="checkbox">
<span i18n-name="ccn-i18n-universal-week-4"></span>
</label>
<label class="checkbox">
<input id="ccn-event-loopWeek-check5" type="checkbox">
<span i18n-name="ccn-i18n-universal-week-5"></span>
</label>
<label class="checkbox">
<input id="ccn-event-loopWeek-check6" type="checkbox">
<span i18n-name="ccn-i18n-universal-week-6"></span>
</label>
<label class="checkbox">
<input id="ccn-event-loopWeek-check7" type="checkbox">
<span i18n-name="ccn-i18n-universal-week-7"></span>
</label>
</div>
</div>
</div>
<div id="ccn-event-boxLoopMonth">
<div class="field">
<label class="label" i18n-name="ccn-i18n-event-loopMonth-span"></label>
<div class="control">
<input id="ccn-event-loopMonth-inputSpan" class="input spanpicker" type="number">
</div>
</div>
<div class="field">
<label class="label" i18n-name="ccn-i18n-event-loopWeek-option"></label>
<div class="control-list">
<label class="radio">
<input id="ccn-event-loopMonth-radioA" type="radio" name="month-loop-method">
<span id="ccn-event-loopMonth-textA"></span>
</label>
<label class="radio">
<input id="ccn-event-loopMonth-radioB" type="radio" name="month-loop-method">
<span id="ccn-event-loopMonth-textB"></span>
</label>
<label class="radio">
<input id="ccn-event-loopMonth-radioC" type="radio" name="month-loop-method">
<span id="ccn-event-loopMonth-textC"></span>
</label>
<label class="radio">
<input id="ccn-event-loopMonth-radioD" type="radio" name="month-loop-method">
<span id="ccn-event-loopMonth-textD"></span>
</label>
</div>
</div>
</div>
<div id="ccn-event-boxLoopYear">
<div class="field">
<label class="label" i18n-name="ccn-i18n-event-loopYear-span"></label>
<div class="control">
<input id="ccn-event-loopYear-inputSpan" class="input spanpicker" type="number">
</div>
</div>
</div>
</section>
<section id="ccn-event-boxLoopStop" class="section">
<h2 class="subtitle" i18n-name="ccn-i18n-event-loopStop"></h2>
<div class="control-list">
<label class="radio">
<input id="ccn-event-loopStop-radioForever" type="radio" name="loop-end">
<span i18n-name="ccn-i18n-event-loopStop-forever"></span>
</label>
<label class="radio">
<input id="ccn-event-loopStop-radioDateTime" type="radio" name="loop-end">
<span i18n-name="ccn-i18n-event-loopStop-datetime"></span>
</label>
<label class="radio">
<input id="ccn-event-loopStop-radioTimes" type="radio" name="loop-end">
<span i18n-name="ccn-i18n-event-loopStop-times"></span>
</label>
</div>
<div id="ccn-event-boxLoopStopDateTime">
<a id="ccn-event-btnLoopStopDateTime" class="button" datetimepicker="3">
<span id="ccn-event-btnLoopStopDateTime-text"></span>
</a>
</div>
<div id="ccn-event-boxLoopStopTimes">
<div class="field">
<div class="control">
<input id="ccn-event-loopStop-inputTimes" class="input spanpicker" type="number">
</div>
</div>
</div>
</section>
<section id="ccn-event-boxStrictMode" class="section">
<h2 class="subtitle" i18n-name="ccn-i18n-event-strictMode-title"></h2>
<p i18n-name="ccn-i18n-event-strictMode-warning"></p>
<div class="control-list">
<label class="radio">
<input id="ccn-event-strictMode-radioStrict" type="radio" name="timezone">
<span i18n-name="ccn-i18n-event-strictMode-strict"></span>
</label>
<label class="radio">
<input id="ccn-event-strictMode-radioRough" type="radio" name="timezone">
<span i18n-name="ccn-i18n-event-strictMode-rough"></span>
</label>
</div>
</section>
<section id="ccn-event-boxTimezone" class="section">
<h2 class="subtitle" i18n-name="ccn-i18n-event-timezone-title"></h2>
<p i18n-name="ccn-i18n-event-timezone-warning"></p>
<div class="control-list">
<label class="radio">
<input id="ccn-event-timezone-radioKeep" type="radio" name="timezone">
<span i18n-name="ccn-i18n-event-timezone-keep"></span>
</label>
<label class="radio">
<input id="ccn-event-timezone-radioReplace" type="radio" name="timezone">
<span i18n-name="ccn-i18n-event-timezone-replace"></span>
</label>
</div>
</section>
<section class="section">
<div class="control-list">
<a id="ccn-event-btnSubmit" class="button is-success" i18n-name="ccn-i18n-event-btnSubmit"></a>
<a id="ccn-event-btnCancel" class="button" i18n-name="ccn-i18n-event-btnCancel"></a>
</div>
</section>
</div>
</body>
</html>

View File

@@ -1,35 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title id="ccn-pageName"></title>
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.9.1/css/bulma.min.css">
<script src="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@5.12.1/js/all.min.js"></script>
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/jquery@3.4.1/dist/jquery.js"></script>
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/jquery-i18n-properties@1.2.7/jquery.i18n.properties.js"></script>
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/jsrender@1.0.10/jsrender.min.js"></script>
<script type="text/x-jsrender" id="jsrender-tmpl-headerNav" src="/static/tmpl/headerNav.tmpl"></script>
<script type="text/x-jsrender" id="jsrender-tmpl-messagebox" src="/static/tmpl/messagebox.tmpl"></script>
<script type="text/javascript" src="/static/js/localStorageAssist.js"></script>
<script type="text/javascript" src="/static/js/i18n.js"></script>
<script type="text/javascript" src="/static/js/utils.js"></script>
<script type="text/javascript" src="/static/js/api.js"></script>
<script type="text/javascript" src="/static/js/template.js"></script>
<script type="text/javascript" src="/static/js/headerNav.js"></script>
<script type="text/javascript" src="/static/js/messagebox.js"></script>
<script type="text/javascript" src="/static/js/page/home.js"></script>
</head>
<body>
<div class="container" style="margin-top: 1.25rem;">
<article i18n-name="ccn-i18n-home-desc">
</article>
</div>
</body>
</html>

View File

@@ -1,60 +0,0 @@
<!DOCTYPE html>
<html style="height: 100%; overflow: hidden;">
<head>
<meta charset="utf-8">
<title id="ccn-pageName"></title>
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.9.1/css/bulma.min.css">
<script src="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@5.12.1/js/all.min.js"></script>
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/jquery@3.4.1/dist/jquery.js"></script>
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/jquery-i18n-properties@1.2.7/jquery.i18n.properties.js"></script>
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/jsrender@1.0.10/jsrender.min.js"></script>
<script type="text/x-jsrender" id="jsrender-tmpl-headerNav" src="/static/tmpl/headerNav.tmpl"></script>
<script type="text/x-jsrender" id="jsrender-tmpl-messagebox" src="/static/tmpl/messagebox.tmpl"></script>
<script type="text/javascript" src="/static/js/localStorageAssist.js"></script>
<script type="text/javascript" src="/static/js/i18n.js"></script>
<script type="text/javascript" src="/static/js/utils.js"></script>
<script type="text/javascript" src="/static/js/api.js"></script>
<script type="text/javascript" src="/static/js/template.js"></script>
<script type="text/javascript" src="/static/js/headerNav.js"></script>
<script type="text/javascript" src="/static/js/messagebox.js"></script>
<script type="text/javascript" src="/static/js/page/login.js"></script>
</head>
<body style="height: 100%; display: flex; flex-flow: column;">
<div style="height: 100%; width: 100%; display: flex; justify-content: center; align-items: center;">
<div class="card" style="padding: 1.25rem;">
<div class="field">
<label class="label" i18n-name="ccn-i18n-login-form-username"></label>
<div class="control has-icons-left has-icons-right">
<input id="ccn-login-form-username" class="input" type="text">
<span class="icon is-small is-left">
<i class="fas fa-user"></i>
</span>
</div>
</div>
<div class="field">
<label class="label" i18n-name="ccn-i18n-login-form-password"></label>
<p class="control has-icons-left">
<input id="ccn-login-form-password" class="input" type="password">
<span class="icon is-small is-left">
<i class="fas fa-lock"></i>
</span>
</p>
</div>
<div class="control">
<button id="ccn-login-form-login" class="button is-primary" i18n-name="ccn-i18n-login-form-login"></button>
</div>
</div>
</div>
</body>
</html>

View File

@@ -1,51 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title id="ccn-pageName"></title>
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.9.1/css/bulma.min.css">
<script src="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@5.12.1/js/all.min.js"></script>
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/jquery@3.4.1/dist/jquery.js"></script>
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/jquery-i18n-properties@1.2.7/jquery.i18n.properties.js"></script>
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/jsrender@1.0.10/jsrender.min.js"></script>
<script type="text/x-jsrender" id="jsrender-tmpl-headerNav" src="/static/tmpl/headerNav.tmpl"></script>
<script type="text/x-jsrender" id="jsrender-tmpl-messagebox" src="/static/tmpl/messagebox.tmpl"></script>
<script type="text/x-jsrender" id="jsrender-tmpl-todoItem" src="/static/tmpl/todoItem.tmpl"></script>
<script type="text/javascript" src="/static/js/localStorageAssist.js"></script>
<script type="text/javascript" src="/static/js/i18n.js"></script>
<script type="text/javascript" src="/static/js/utils.js"></script>
<script type="text/javascript" src="/static/js/api.js"></script>
<script type="text/javascript" src="/static/js/template.js"></script>
<script type="text/javascript" src="/static/js/headerNav.js"></script>
<script type="text/javascript" src="/static/js/messagebox.js"></script>
<script type="text/javascript" src="/static/js/page/todo.js"></script>
<link rel="stylesheet" href="/static/css/todo.css">
</head>
<body>
<div class="container" style="display: flex; flex-flow: column; margin-top: 1.25rem;">
<h1 i18n-name="ccn-i18n-todo-todoList" class="title"></h1>
<div class="control-list">
<div id="ccn-todo-btnAdd" class="control">
<a class="button is-primary"><span class="icon is-small"><i class="fas fa-plus"></i></span></a>
</div>
<div id="ccn-todo-btnRefresh" class="control">
<a class="button is-primary">
<span class="icon is-small"><i class="fas fa-sync"></i></span>
</a>
</div>
</div>
<div id="ccn-todo-todoList" style="display: flex; flex-flow: column; margin-top: 1.25rem;">
</div>
</div>
</body>
</html>

View File

@@ -0,0 +1,18 @@
{
"extends": "@vue/tsconfig/tsconfig.dom.json",
"include": ["env.d.ts", "src/**/*", "src/**/*.vue"],
"exclude": ["src/**/__tests__/*"],
"compilerOptions": {
// Extra safety for array and object lookups, but may have false positives.
"noUncheckedIndexedAccess": true,
// Path mapping for cleaner imports.
"paths": {
"@/*": ["./src/*"]
},
// `vue-tsc --build` produces a .tsbuildinfo file for incremental type-checking.
// Specified here to keep it out of the root directory.
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo"
}
}

11
frontend/tsconfig.json Normal file
View File

@@ -0,0 +1,11 @@
{
"files": [],
"references": [
{
"path": "./tsconfig.node.json"
},
{
"path": "./tsconfig.app.json"
}
]
}

View File

@@ -0,0 +1,27 @@
// TSConfig for modules that run in Node.js environment via either transpilation or type-stripping.
{
"extends": "@tsconfig/node24/tsconfig.json",
"include": [
"vite.config.*",
"vitest.config.*",
"cypress.config.*",
"playwright.config.*",
"eslint.config.*"
],
"compilerOptions": {
// Most tools use transpilation instead of Node.js's native type-stripping.
// Bundler mode provides a smoother developer experience.
"module": "preserve",
"moduleResolution": "bundler",
// Include Node.js types and avoid accidentally including other `@types/*` packages.
"types": ["node"],
// Disable emitting output during `vue-tsc --build`, which is used for type-checking only.
"noEmit": true,
// `vue-tsc --build` produces a .tsbuildinfo file for incremental type-checking.
// Specified here to keep it out of the root directory.
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo"
}
}

18
frontend/vite.config.ts Normal file
View File

@@ -0,0 +1,18 @@
import { fileURLToPath, URL } from 'node:url'
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import vueDevTools from 'vite-plugin-vue-devtools'
// https://vite.dev/config/
export default defineConfig({
plugins: [
vue(),
vueDevTools(),
],
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url))
},
},
})