upload, string extensions, lgres

This commit is contained in:
Tsanie Lily 2023-03-30 12:39:26 +08:00
parent 1d636cdc79
commit f5bc42fa20
11 changed files with 323 additions and 33 deletions

View File

@ -5,12 +5,15 @@
<!-- <link rel="icon" type="image/svg+xml" href="/vite.svg" /> -->
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>UI Lib</title>
<script src="jquery-3.6.4.min.js"></script>
<script type="module" src="/main.js"></script>
</head>
<body>
<div id="app">
<div>
<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript" target="_blank">
<a
href="https://developer.mozilla.org/en-US/docs/Web/JavaScript"
target="_blank"
>
<img id="js-logo" class="logo vanilla" alt="JavaScript logo" />
</a>
<div class="card">
@ -23,12 +26,17 @@
<label data-checkbox data-label="Case 1"></label>
</div>
<div id="buttons" class="app-module">
<button title="Edit Contact">Edit</button>
<button
data-title-lgid="editContacts"
data-lgid="editContacts"
title="Edit Contact"
>
Edit
</button>
<button id="button-fetch" title="Fetch">Fetch</button>
</div>
</div>
</div>
</div>
<script type="module" src="/main.js"></script>
</div>
</body>
</html>

2
jquery-3.6.4.min.js vendored

File diff suppressed because one or more lines are too long

View File

@ -1,10 +1,20 @@
import { getCookie, setCookie, deleteCookie } from "./utility/cookie";
import { get, post } from "./utility/request";
import { init, r, lang } from "./utility/lgres";
import { get, post, upload } from "./utility/request";
import { nullOrEmpty, contains, endsWith, padStart } from "./utility/strings";
export {
getCookie,
setCookie,
deleteCookie,
init,
r,
lang,
get,
post
post,
upload,
nullOrEmpty,
contains,
endsWith,
padStart
}

7
lib/utility/lgres.d.ts vendored Normal file
View File

@ -0,0 +1,7 @@
export function init(dom?: HTMLElement, ahead?: | { callback?: (result: any) => void }): Promise<any>
export function r(key: string, defaultValue?: any): any
export const lang: {
get current(): string,
get unknownError(): string,
get savedSuccessfully(): string
}

167
lib/utility/lgres.js Normal file
View File

@ -0,0 +1,167 @@
import { getCookie } from "./cookie";
import { get } from "./request";
import { nullOrEmpty } from "./strings";
let cache;
function getCurrentLgId() {
let lgid;
if (typeof consts !== 'undefined') {
lgid = consts.cookie != null && getCookie(consts.cookie.lang);
if (nullOrEmpty(lgid)) {
lgid = consts.user && consts.user.language;
}
}
if (nullOrEmpty(lgid)) {
lgid = getCookie('lgid');
}
if (nullOrEmpty(lgid)) {
lgid = navigator.language || 'en-us';
}
lgid = lgid.toLowerCase().replace(/-/g, '_');
if (nullOrEmpty(lgid)) {
lgid = 'en';
}
switch (lgid) {
case 'en':
case 'en_au':
case 'fr':
case 'zh_cn':
return lgid;
}
const lang = lgid.split('_')[0];
switch (lang) {
case 'en':
case 'fr':
return lang;
}
return 'en';
}
function getStorageKey(lgid) {
if (typeof consts !== 'undefined') {
return (consts.prefix || '') + `res_${lgid}`;
}
return `res_${lgid}`;
}
async function doRefreshLgres() {
const lgid = getCurrentLgId();
const r = await get(`language/${lgid}/res.json`);
const dict = await r.json();
localStorage.setItem(getStorageKey(lgid), JSON.stringify(dict));
cache = dict;
return dict;
}
async function refreshLgres(lgres) {
if (lgres == null || typeof consts === 'undefined') {
return await doRefreshLgres();
}
const ver = Number(consts.resver);
if (isNaN(lgres.ver) || isNaN(ver) || ver > lgres.ver) {
console.log(`found new language res version: ${lgres.ver} => ${ver}`);
return await doRefreshLgres();
}
cache = lgres;
return lgres;
}
function getLanguage(lgres, key, defaultValue) {
let value = lgres[key];
if (value == null) {
value = defaultValue;
}
return value;
}
function applyLanguage(dom, result) {
if (dom == null) {
dom = document.body;
}
for (let text of dom.querySelectorAll('[data-lgid]')) {
const key = text.getAttribute('data-lgid');
if (text.tagName === 'INPUT') {
text.value = getLanguage(result, key, text.value);
} else {
text.innerText = getLanguage(result, key, text.innerText);
}
}
for (let title of dom.querySelectorAll('[data-title-lgid]')) {
const key = title.getAttribute('data-title-lgid');
title.setAttribute('title', getLanguage(result, key, title.getAttribute('title')));
}
for (let holder of dom.querySelectorAll('[data-placeholder-lgid]')) {
const key = holder.getAttribute('data-placeholder-lgid');
holder.setAttribute('placeholder', getLanguage(result, key, holder.getAttribute('placeholder')));
}
}
async function init(dom, ahead) {
const lgid = getCurrentLgId();
let lgres = localStorage.getItem(getStorageKey(lgid));
let result;
if (lgres != null) {
try {
lgres = JSON.parse(lgres);
result = await refreshLgres(lgres);
} catch (e) {
console.error('error while parsing lgres, try refresh ...', e);
result = await refreshLgres();
}
} else {
result = await refreshLgres();
}
try {
if (ahead != null) {
// not in defer mode
if (document.readyState === 'loading') {
return await new Promise((resolve, reject) => {
let tid = setTimeout(() => reject('timeout'), 30000);
document.addEventListener('DOMContentLoaded', () => {
clearTimeout(tid);
tid = void 0;
if (typeof ahead.callback === 'function') {
ahead.callback(result);
}
applyLanguage(dom, result);
resolve(result);
});
});
}
if (typeof ahead.callback === 'function') {
ahead.callback(result);
}
}
applyLanguage(dom, result);
return result;
} catch (err) {
console.error('error while loading language res ...', err);
}
}
function r(key, defaultValue) {
if (cache != null) {
return getLanguage(cache, key, defaultValue);
}
return defaultValue;
}
const lang = {
get current() {
return getCurrentLgId();
},
get unknownError() {
return r('unknownError', 'An unknown error occurred, please contact the administrator.');
},
get savedSuccessfully() {
return r('savedSuccessfully', 'Saved successfully.');
}
}
export {
init,
r,
lang
}

View File

@ -1,9 +1,12 @@
interface RequestOptions {
method?: string;
accept?: string;
contentType?: string;
customerHeaders?: { [key: string]: string };
signal?: AbortSignal | null;
progress?: (this: XMLHttpRequestUpload, ev: ProgressEvent<XMLHttpRequestEventTarget>) => any
}
export function get(url: string, options?: RequestOptions): Promise<Response>
export function post(url: string, data?: BodyInit | null, options?: RequestOptions): Promise<Response>
export function post(url: string, data?: BodyInit | null, options?: RequestOptions): Promise<Response>
export function upload(url: string, data: FormData, options?: RequestOptions): Promise<Response>

View File

@ -1,4 +1,7 @@
function combineUrl(url) {
if (/^(https?|wss?|ftp):/.test(url)) {
return url;
}
if (typeof consts === 'undefined') {
return url;
}
@ -11,7 +14,7 @@ function get(url, options) {
method: options.method || 'GET',
headers: {
...options.customerHeaders,
'Content-Type': options.contentType || 'application/json'
'Accept': options.accept || 'application/json'
},
signal: options.signal,
cache: 'default'
@ -20,19 +23,62 @@ function get(url, options) {
function post(url, data, options) {
options ??= {};
// let contentType;
if (data instanceof FormData) {
// contentType = 'multipart/form-data';
} else {
if (typeof data !== 'string') {
data = JSON.stringify(data);
}
// contentType = 'application/json';
if (options.customerHeaders == null) {
options.customerHeaders = {};
}
if (options.customerHeaders['Content-Type'] == null) {
options.customerHeaders['Content-Type'] = 'application/json';
}
}
return fetch(combineUrl(url), {
method: options.method || 'POST',
headers: {
...options.customerHeaders,
'Content-Type': options.contentType || 'application/json'
},
headers: options.customerHeaders,
body: data,
signal: options.signal,
cache: 'no-cache'
});
}
function upload(url, data, options) {
return new Promise((resolve, reject) => {
const request = new XMLHttpRequest();
request.onreadystatechange = function () {
if (this.readyState === XMLHttpRequest.DONE) {
if (this.status === 200) {
resolve(this);
} else {
reject(`${this.status} ${this.statusText}: ${this.responseText}`);
}
}
};
options ??= {};
if (typeof options.progress === 'function') {
request.upload.addEventListener('progress', function (ev) {
if (ev.lengthComputable) {
options.progress.call(this, ev);
}
}, false);
}
request.open('POST', combineUrl(url));
if (options.customerHeaders != null) {
for (let header of Object.entries(options.customerHeaders)) {
request.setRequestHeader(header[0], header[1]);
}
}
request.send(data);
});
}
export {
get,
post
post,
upload
}

4
lib/utility/strings.d.ts vendored Normal file
View File

@ -0,0 +1,4 @@
export function nullOrEmpty(s?: string | any | null): boolean
export function contains(s: string, key: string | any, ignoreCase?: boolean): boolean
export function endsWith(s: string, suffix: string): boolean
export function padStart(s: string, num: Number, char: string): boolean

40
lib/utility/strings.js Normal file
View File

@ -0,0 +1,40 @@
function nullOrEmpty(s) {
return s == null || typeof s !== 'string' || s.length === 0;
}
function contains(s, key, ignoreCase) {
if (nullOrEmpty(s) || key == null) {
return false;
}
if (typeof key !== 'string') {
key = String(key);
}
if (ignoreCase) {
return s.toLowerCase().indexOf(key.toLowerCase()) >= 0;
}
return s.indexOf(key) >= 0;
}
function endsWith(s, suffix) {
if (nullOrEmpty(s) || nullOrEmpty(suffix)) {
return false;
}
return s.indexOf(suffix) === s.length - suffix.length;
}
function padStart(s, num, char) {
if (nullOrEmpty(s) || isNaN(num) || num <= s.length) {
return s;
}
if (char == null) {
char = ' ';
}
return char.repeat(num - s.length);
}
export {
nullOrEmpty,
contains,
endsWith,
padStart
}

38
main.js
View File

@ -2,7 +2,7 @@ import './css/ui.min.css'
import './style.css'
// import javascriptLogo from './javascript.svg'
import { resolveCheckbox, resolveIcon, resolveTooltip } from './lib/ui'
import { get, post } from './lib/utility'
import { init, r, lang, get, post, upload } from './lib/utility'
// document.querySelector('#js-logo').src = javascriptLogo
@ -11,21 +11,27 @@ window.consts = {
resver: 20230329
}
// document.querySelector('#create-icon').appendChild(createIcon('fa-solid', 'user-edit'))
resolveIcon(document.querySelector('#create-icon'))
init(null, {
callback: (result) => console.log(result)
}).then(() => {
// document.querySelector('#create-icon').appendChild(createIcon('fa-solid', 'user-edit'))
resolveIcon(document.querySelector('#create-icon'))
// document.querySelector('#create-checkbox').appendChild(createCheckbox({
// label: 'Switch 1'
// }))
resolveCheckbox(document.querySelector('#create-checkbox'))
// document.querySelector('#create-checkbox').appendChild(createCheckbox({
// label: 'Switch 1'
// }))
resolveCheckbox(document.querySelector('#create-checkbox'))
resolveTooltip(document.querySelector('#buttons'))
resolveTooltip(document.querySelector('#buttons'))
document.querySelector('#button-fetch').addEventListener('click', () => {
// get('./javascript.svg')
// .then(r => r.blob())
// .then(blob => document.querySelector('#js-logo').src = URL.createObjectURL(blob));
post('./', JSON.stringify({ a: 1, b: 'test' }))
.then(r => console.log(r))
.catch(e => console.warn(e));
});
document.querySelector('#button-fetch').addEventListener('click', () => {
get('javascript.svg', {
// contentType: '',
customerHeaders: {
'X-Auth': 'test/authentication'
}
})
.then(r => r.blob())
.then(blob => document.querySelector('#js-logo').src = URL.createObjectURL(blob));
});
});

View File

@ -18,7 +18,8 @@ libraries.forEach(async (lib) => {
...lib,
formats: ['umd'],
fileName: (_format, name) => `${name}.min.js`
}
},
sourcemap: true
}
})
})