upload, string extensions, lgres

This commit is contained in:
tsanie committed 2023-03-30 12:39:26 +08:00
1 parent 1d636cdc79
commit f5bc42fa20
11 files changed
+312 -22

No files matched your search

+12 -4
View File
@@ -5,12 +5,15 @@
<!-- <link rel="icon" type="image/svg+xml" href="/vite.svg" /> --> <!-- <link rel="icon" type="image/svg+xml" href="/vite.svg" /> -->
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>UI Lib</title> <title>UI Lib</title>
<script src="jquery-3.6.4.min.js"></script> <script type="module" src="/main.js"></script>
</head> </head>
<body> <body>
<div id="app"> <div id="app">
<div> <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" /> <img id="js-logo" class="logo vanilla" alt="JavaScript logo" />
</a> </a>
<div class="card"> <div class="card">
@@ -23,12 +26,17 @@
<label data-checkbox data-label="Case 1"></label> <label data-checkbox data-label="Case 1"></label>
</div> </div>
<div id="buttons" class="app-module"> <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> <button id="button-fetch" title="Fetch">Fetch</button>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<script type="module" src="/main.js"></script>
</body> </body>
</html> </html>
-2
View File
@@ -1,2 +0,0 @@
/*! jQuery v3.6.4 | (c) OpenJS Foundation and other contributors | jquery.org/license */
!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(C,e){"use strict";var t=[],r=Object.getPrototypeOf,s=t.slice,g=t.flat?function(e){return t.flat.call(e)}:function(e){return t.concat.apply([],e)},u=t.push,i=t.indexOf,n={},o=n.toString,y=n.hasOwnProperty,a=y.toString,l=a.call(Object),v={},m=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType&&"function"!=typeof e.item},x=function(e){return null!=e&&e===e.window},E=C.document,c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.6.4",S=function(e,t){return new S.fn.init(e,t)};function p(e){var t=!!e&&"length"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0<t&&t-1 in e)}S.fn=S.prototype={jquery:f,constructor:S,length:0,toArray:function(){return s.call(this)},get:function(e){return null==e?s.call(this):e<0?this[e+this.length]:this[e]},pushStack:function(e){var t=S.merge(this.constructor(),e);return t.prevObject=this,t},each:function(e){return S.each(this,e)},map:function(n){return this.pushStack(S.map(this,function(e,t){return n.call(e,t,e)}))},slice:function(){return this.pushStack(s.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},even:function(){return this.pushStack(S.grep(this,function(e,t){return(t+1)%2}))},odd:function(){return this.pushStack(S.grep(this,function(e,t){return t%2}))},eq:function(e){var t=this.length,n=+e+(e<0?t:0);return this.pushStack(0<=n&&n<t?[this[n]]:[])},end:function(){return this.prevObject||this.constructor()},push:u,sort:t.sort,splice:t.splice},S.extend=S.fn.extend=function(){var e,t,n,r,i,o,a=arguments[0]||{},s=1,u=arguments.length,l=!1;for("boolean"==typeof a&&(l=a,a=arguments[s]||{},s++),"object"==typeof a||m(a)||(a={}),s===u&&(a=this,s--);s<u;s++)if(null!=(e=arguments[s]))for(t in e)r=e[t],"__proto__"!==t&&a!==r&&(l&&r&&(S.isPlainObject(r)||(i=Array.isArray(r)))?(n=a[t],o=i&&!Array.isArray(n)?[]:i||S.isPlainObject(n)?n:{},i=!1,a[t]=S.extend(l,o,r)):void 0!==r&&(a[t]=r));return a},S.extend({expando:"jQuery"+(f+Math.random()).replace(/\D/g,""),isReady:!0,error:function(e){throw new Error(e)},noop:function(){},isPlainObject:function(e){var t,n;return!(!e||"[object Object]"!==o.call(e))&&(!(t=r(e))||"function"==typeof(n=y.call(t,"constructor")&&t.constructor)&&a.call(n)===l)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},globalEval:function(e,t,n){b(e,{nonce:t&&t.nonce},n)},each:function(e,t){var n,r=0;if(p(e)){for(n=e.length;r<n;r++)if(!1===t.call(e[r],r,e[r]))break}else for(r in e)if(!1===t.call(e[r],r,e[r]))break;return e},makeArray:function(e,t){var n=t||[];return null!=e&&(p(Object(e))?S.merge(n,"string"==typeof e?[e]:e):u.call(n,e)),n},inArray:function(e,t,n){return null==t?-1:i.call(t,e,n)},merge:function(e,t){for(var n=+t.length,r=0,i=e.length;r<n;r++)e[i++]=t[r];return e.length=i,e},grep:function(e,t,n){for(var r=[],i=0,o=e.length,a=!n;i<o;i++)!t(e[i],i)!==a&&r.push(e[i]);return r},map:function(e,t,n){var r,i,o=0,a=[];if(p(e))for(r=e.length;o<r;o++)null!=(i=t(e[o],o,n))&&a.push(i);else for(o in e)null!=(i=t(e[o],o,n))&&a.push(i);return g(a)},guid:1,support:v}),"function"==typeof Symbol&&(S.fn[Symbol.iterator]=t[Symbol.iterator]),S.each("Boolean Number String Function Array Date RegExp Object Error Symbol".split(" "),function(e,t){n["[object "+t+"]"]=t.toLowerCase()});var d=function(n){var e,d,b,o,i,h,f,g,w,u,l,T,C,a,E,y,s,c,v,S="sizzle"+1*new Date,p=n.document,k=0,r=0,m=ue(),x=ue(),A=ue(),N=ue(),j=function(e,t){return e===t&&(l=!0),0},D={}.hasOwnProperty,t=[],q=t.pop,L=t.push,H=t.push,O=t.slice,P=function(e,t){for(var n=0,r=e.length;n<r;n++)if(e[n]===t)return n;return-1},R="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",M="[\\x20\\t\\r\\n\\f]",I="(?:\\\\[\\da-fA-F]{1,6}"+M+"?|\\\\[^\\r\\n\\f]|[\\w-]|[^\0-\\x7f])+",W="\\["+M+"*("+I+")(?:"+M+"*([*^$|!~]?=)"+M+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+I+"))|)"+M+"*\\]",F=":("+I+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+W+")*)|.*)\\)|)",$=new RegExp(M+"+","g"),B=new RegExp("^"+M+"+|((?:^|[^\\\\])(?:\\\\.)*)"+M+"+$","g"),_=new RegExp("^"+M+"*,"+M+"*"),z=new RegExp("^"+M+"*([>+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp(F),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+F),CHILD:new RegExp("^Line truncated
+12 -2
View File
@@ -1,10 +1,20 @@
import { getCookie, setCookie, deleteCookie } from "./utility/cookie"; 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 { export {
getCookie, getCookie,
setCookie, setCookie,
deleteCookie, deleteCookie,
init,
r,
lang,
get, get,
post post,
upload,
nullOrEmpty,
contains,
endsWith,
padStart
} }
+7
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
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
}
+3
View File
@@ -1,9 +1,12 @@
interface RequestOptions { interface RequestOptions {
method?: string; method?: string;
accept?: string;
contentType?: string; contentType?: string;
customerHeaders?: { [key: string]: string }; customerHeaders?: { [key: string]: string };
signal?: AbortSignal | null; signal?: AbortSignal | null;
progress?: (this: XMLHttpRequestUpload, ev: ProgressEvent<XMLHttpRequestEventTarget>) => any
} }
export function get(url: string, options?: RequestOptions): Promise<Response> 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>
+52 -6
View File
@@ -1,4 +1,7 @@
function combineUrl(url) { function combineUrl(url) {
if (/^(https?|wss?|ftp):/.test(url)) {
return url;
}
if (typeof consts === 'undefined') { if (typeof consts === 'undefined') {
return url; return url;
} }
@@ -11,7 +14,7 @@ function get(url, options) {
method: options.method || 'GET', method: options.method || 'GET',
headers: { headers: {
...options.customerHeaders, ...options.customerHeaders,
'Content-Type': options.contentType || 'application/json' 'Accept': options.accept || 'application/json'
}, },
signal: options.signal, signal: options.signal,
cache: 'default' cache: 'default'
@@ -20,19 +23,62 @@ function get(url, options) {
function post(url, data, options) { function post(url, data, options) {
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), { return fetch(combineUrl(url), {
method: options.method || 'POST', method: options.method || 'POST',
headers: { headers: options.customerHeaders,
...options.customerHeaders,
'Content-Type': options.contentType || 'application/json'
},
body: data, body: data,
signal: options.signal, signal: options.signal,
cache: 'no-cache' 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 { export {
get, get,
post post,
upload
} }
+4
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
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
}
+13 -7
View File
@@ -2,7 +2,7 @@ import './css/ui.min.css'
import './style.css' import './style.css'
// import javascriptLogo from './javascript.svg' // import javascriptLogo from './javascript.svg'
import { resolveCheckbox, resolveIcon, resolveTooltip } from './lib/ui' 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 // document.querySelector('#js-logo').src = javascriptLogo
@@ -11,6 +11,9 @@ window.consts = {
resver: 20230329 resver: 20230329
} }
init(null, {
callback: (result) => console.log(result)
}).then(() => {
// document.querySelector('#create-icon').appendChild(createIcon('fa-solid', 'user-edit')) // document.querySelector('#create-icon').appendChild(createIcon('fa-solid', 'user-edit'))
resolveIcon(document.querySelector('#create-icon')) resolveIcon(document.querySelector('#create-icon'))
@@ -22,10 +25,13 @@ resolveCheckbox(document.querySelector('#create-checkbox'))
resolveTooltip(document.querySelector('#buttons')) resolveTooltip(document.querySelector('#buttons'))
document.querySelector('#button-fetch').addEventListener('click', () => { document.querySelector('#button-fetch').addEventListener('click', () => {
// get('./javascript.svg') get('javascript.svg', {
// .then(r => r.blob()) // contentType: '',
// .then(blob => document.querySelector('#js-logo').src = URL.createObjectURL(blob)); customerHeaders: {
post('./', JSON.stringify({ a: 1, b: 'test' })) 'X-Auth': 'test/authentication'
.then(r => console.log(r)) }
.catch(e => console.warn(e)); })
.then(r => r.blob())
.then(blob => document.querySelector('#js-logo').src = URL.createObjectURL(blob));
});
}); });
+2 -1
View File
@@ -18,7 +18,8 @@ libraries.forEach(async (lib) => {
...lib, ...lib,
formats: ['umd'], formats: ['umd'],
fileName: (_format, name) => `${name}.min.js` fileName: (_format, name) => `${name}.min.js`
} },
sourcemap: true
} }
}) })
}) })