4d19d7e814
- 支付宝新窗口跳转,轮询与手动刷新增加加载反馈 - 支付回跳先校验订单状态,避免未付款误报成功 - 门户登录回调统一,云文件打开加载与版本冲突同步 - 精简本地 start.bat 与 README 说明 Co-authored-by: Cursor <cursoragent@cursor.com>
730 lines
29 KiB
JavaScript
730 lines
29 KiB
JavaScript
(function () {
|
|
'use strict';
|
|
|
|
var HISTORY_KEY = 'soondesign_history';
|
|
var VERSION = typeof __APP_VERSION__ !== 'undefined' ? __APP_VERSION__ : '3.2.101';
|
|
|
|
function getAppBasePathname() {
|
|
var p = (typeof window !== 'undefined' && window.location && window.location.pathname) ? window.location.pathname : '/';
|
|
while (p.length > 1 && p.endsWith('/')) {
|
|
p = p.slice(0, -1);
|
|
}
|
|
if (/\.web\.html$/i.test(p) || /\.html$/i.test(p)) {
|
|
p = p.replace(/[^/]+$/, '');
|
|
}
|
|
if (!p.endsWith('/')) p += '/';
|
|
return p;
|
|
}
|
|
|
|
var SERVER_API_BASE = (function () {
|
|
var cfg = (typeof window !== 'undefined' && window.SOON_DEPLOY_CONFIG && window.SOON_DEPLOY_CONFIG.api_v1_base);
|
|
if (cfg) return String(cfg).replace(/\/+$/, '') + '/';
|
|
if (typeof window === 'undefined' || !window.location) return '/api/v1/';
|
|
return window.location.origin + getAppBasePathname() + 'api/v1/';
|
|
})();
|
|
|
|
function getAccessToken() {
|
|
if (typeof window.soonGetAccessToken === 'function') return window.soonGetAccessToken();
|
|
try { return localStorage.getItem('soon_access') || ''; } catch (e) { return ''; }
|
|
}
|
|
|
|
function authedFetch(path, opts) {
|
|
var url = SERVER_API_BASE + String(path).replace(/^\/+/, '');
|
|
if (typeof window.soonAuthedFetch === 'function') {
|
|
return window.soonAuthedFetch(url, opts);
|
|
}
|
|
opts = opts || {};
|
|
opts.headers = Object.assign({}, opts.headers || {});
|
|
if (!opts.headers['Authorization'] && !opts.headers['authorization']) {
|
|
var t = getAccessToken();
|
|
if (t) opts.headers['Authorization'] = 'Bearer ' + t;
|
|
}
|
|
return fetch(url, opts);
|
|
}
|
|
|
|
var JSON_HEADERS = {
|
|
'Content-Type': 'application/json; charset=utf-8',
|
|
'Accept': 'application/json'
|
|
};
|
|
|
|
function parseCloudRef(p) {
|
|
return typeof window.soonParseFileKey === 'function' ? window.soonParseFileKey(p) : null;
|
|
}
|
|
|
|
function normalizeSoonName(p) {
|
|
return typeof window.soonNormalizeSoonName === 'function'
|
|
? window.soonNormalizeSoonName(p)
|
|
: String(p || 'design.soon');
|
|
}
|
|
|
|
function packCloudResult(j) {
|
|
if (!j || !j.ok || !j.data) {
|
|
return Promise.reject(new Error('cloud_empty_response'));
|
|
}
|
|
var fileKey = typeof window.soonApplyCloudMeta === 'function'
|
|
? window.soonApplyCloudMeta(j.data)
|
|
: null;
|
|
if (!fileKey) {
|
|
var d = j.data;
|
|
window._soonFileMeta = { id: d.id, version: d.version, name: d.name };
|
|
fileKey = 'soondesign_file:' + d.id + ':v' + d.version;
|
|
}
|
|
return { fileId: j.data.id, version: j.data.version, fileKey: fileKey, name: j.data.name };
|
|
}
|
|
|
|
function handleCloudResponse(response, bodyText) {
|
|
if (response.ok) {
|
|
try { return Promise.resolve(JSON.parse(bodyText)); } catch (e) { return Promise.resolve(null); }
|
|
}
|
|
var info = typeof window.soonParseApiError === 'function'
|
|
? window.soonParseApiError(response, bodyText)
|
|
: { status: response.status, message: '操作失败' };
|
|
if (typeof window.soonShowApiError === 'function') window.soonShowApiError(info);
|
|
var err = new Error(info.message || 'cloud_error');
|
|
err.status = info.status;
|
|
err.code = info.code;
|
|
return Promise.reject(err);
|
|
}
|
|
|
|
function requireCloudAuth(actionLabel) {
|
|
if (getAccessToken()) return true;
|
|
if (typeof window.soonRequireLogin === 'function') return window.soonRequireLogin(actionLabel);
|
|
return false;
|
|
}
|
|
|
|
function navigateToPage(pathWithQuery) {
|
|
try {
|
|
location.href = new URL(pathWithQuery, window.location.href).href;
|
|
} catch (e) {
|
|
location.href = pathWithQuery;
|
|
}
|
|
}
|
|
|
|
function getLocale() {
|
|
var lang = typeof navigator !== 'undefined' ? (navigator.language || navigator.browserLanguage || '') : '';
|
|
if (lang.indexOf('zh') === 0) return lang.indexOf('TW') >= 0 ? 'ozh' : 'zh';
|
|
return 'en';
|
|
}
|
|
|
|
function getSystemFonts() {
|
|
var list = [
|
|
'Arial', 'Arial Black', 'Comic Sans MS', 'Courier New', 'Georgia',
|
|
'Impact', 'Microsoft YaHei', 'SimHei', 'SimSun', 'KaiTi', 'FangSong',
|
|
'Times New Roman', 'Trebuchet MS', 'Verdana', 'PingFang SC', 'Hiragino Sans GB'
|
|
];
|
|
if (typeof document !== 'undefined' && document.fonts && document.fonts.forEach) {
|
|
var set = {};
|
|
document.fonts.forEach(function (f) {
|
|
var name = (f.family || '').replace(/^["']|["']$/g, '');
|
|
if (name) set[name] = 1;
|
|
});
|
|
list = Object.keys(set).length ? Object.keys(set).sort() : list;
|
|
}
|
|
return Promise.resolve(list);
|
|
}
|
|
|
|
function listCloudFiles(pageOrLimit, sizeOrOffset) {
|
|
if (!getAccessToken()) {
|
|
var empty = { items: [], total: 0 };
|
|
if (typeof pageOrLimit === 'object' && pageOrLimit) {
|
|
empty.page = pageOrLimit.page || 1;
|
|
empty.size = pageOrLimit.size || 12;
|
|
}
|
|
return Promise.resolve(empty);
|
|
}
|
|
var url;
|
|
var fallback = { items: [], total: 0 };
|
|
if (typeof pageOrLimit === 'object' && pageOrLimit) {
|
|
var page = pageOrLimit.page || 1;
|
|
var size = pageOrLimit.size || 12;
|
|
url = 'files?page=' + page + '&size=' + size;
|
|
fallback = { items: [], total: 0, page: page, size: size };
|
|
} else {
|
|
var lim = pageOrLimit || 50;
|
|
var off = sizeOrOffset || 0;
|
|
url = 'files?limit=' + lim + '&offset=' + off;
|
|
fallback = { items: [], limit: lim, offset: off, total: 0 };
|
|
}
|
|
return authedFetch(url, { headers: { Accept: 'application/json' } })
|
|
.then(function (r) { return r.text().then(function (t) { return handleCloudResponse(r, t); }); })
|
|
.then(function (j) { return (j && j.ok && j.data) ? j.data : fallback; });
|
|
}
|
|
|
|
function createCloudFile(name, jsonStr) {
|
|
if (!requireCloudAuth('保存')) return Promise.reject(new Error('unauthorized'));
|
|
return authedFetch('files', {
|
|
method: 'POST',
|
|
headers: JSON_HEADERS,
|
|
body: JSON.stringify({ name: normalizeSoonName(name), json: jsonStr })
|
|
})
|
|
.then(function (r) { return r.text().then(function (t) { return handleCloudResponse(r, t); }); })
|
|
.then(packCloudResult);
|
|
}
|
|
|
|
function syncCloudFileAfterConflict(id) {
|
|
var oldKey = (typeof window !== 'undefined' && window.openAs && window.openAs.name) ? window.openAs.name : '';
|
|
return authedFetch('files/' + id, { headers: { Accept: 'application/json' } })
|
|
.then(function (response) {
|
|
if (!response.ok) return null;
|
|
return response.json();
|
|
})
|
|
.then(function (payload) {
|
|
if (!payload || !payload.ok || !payload.data) return null;
|
|
var d = payload.data;
|
|
var newKey = typeof window.soonApplyCloudMeta === 'function'
|
|
? window.soonApplyCloudMeta(d)
|
|
: ('soondesign_file:' + d.id + ':v' + d.version);
|
|
if (oldKey && oldKey !== newKey && typeof window.soonLocalRemove === 'function') {
|
|
window.soonLocalRemove(oldKey);
|
|
}
|
|
if (typeof window.soonRecentOnCloudSave === 'function') {
|
|
window.soonRecentOnCloudSave({
|
|
fileKey: newKey,
|
|
fileId: d.id,
|
|
name: d.name,
|
|
version: d.version
|
|
}, oldKey, null);
|
|
}
|
|
if (typeof window !== 'undefined' && window.openAs && newKey) {
|
|
window.openAs.name = newKey;
|
|
}
|
|
if (typeof window.soonToast === 'function') {
|
|
window.soonToast('文件已在其他端更新,已同步版本,请再次保存', 'warn');
|
|
}
|
|
return newKey;
|
|
});
|
|
}
|
|
|
|
function updateCloudFile(id, name, jsonStr, version) {
|
|
if (!requireCloudAuth('保存')) return Promise.reject(new Error('unauthorized'));
|
|
var body = { name: normalizeSoonName(name), json: jsonStr };
|
|
if (version != null) body.version = version;
|
|
return authedFetch('files/' + id, {
|
|
method: 'PUT',
|
|
headers: JSON_HEADERS,
|
|
body: JSON.stringify(body)
|
|
})
|
|
.then(function (r) {
|
|
return r.text().then(function (t) {
|
|
if (r.status === 409) {
|
|
return syncCloudFileAfterConflict(id).then(function () {
|
|
var err = new Error('version_conflict');
|
|
err.status = 409;
|
|
err.conflictSynced = true;
|
|
return Promise.reject(err);
|
|
});
|
|
}
|
|
return handleCloudResponse(r, t);
|
|
});
|
|
})
|
|
.then(packCloudResult);
|
|
}
|
|
|
|
function deleteCloudFile(id) {
|
|
if (!requireCloudAuth('删除')) return Promise.reject(new Error('unauthorized'));
|
|
return authedFetch('files/' + id, { method: 'DELETE', headers: { Accept: 'application/json' } })
|
|
.then(function (r) { return r.text().then(function (t) { return handleCloudResponse(r, t); }); });
|
|
}
|
|
|
|
function importSoonFile(name, jsonObj) {
|
|
var jsonStr = typeof jsonObj === 'string' ? jsonObj : JSON.stringify(jsonObj);
|
|
return createCloudFile(name, jsonStr);
|
|
}
|
|
|
|
function downloadCloudFile(id, fileName) {
|
|
if (!getAccessToken()) {
|
|
return Promise.reject(new Error('unauthorized'));
|
|
}
|
|
return authedFetch('files/' + id + '/download', { headers: { Accept: 'application/octet-stream' } })
|
|
.then(function (response) {
|
|
if (!response.ok) {
|
|
return response.text().then(function (t) { return handleCloudResponse(response, t); });
|
|
}
|
|
return response.blob().then(function (blob) {
|
|
var a = document.createElement('a');
|
|
a.download = normalizeSoonName(fileName || 'design.soon');
|
|
a.href = URL.createObjectURL(blob);
|
|
a.click();
|
|
URL.revokeObjectURL(a.href);
|
|
});
|
|
});
|
|
}
|
|
|
|
function isSoonSaveDialog(options) {
|
|
if (options && options.soonFile === true) return true;
|
|
if (options && options.soonFile === false) return false;
|
|
var raw = (options && options.defaultPath) ? String(options.defaultPath) : '';
|
|
if (!raw) return true;
|
|
if (typeof window.soonIsTemplateKey === 'function' && window.soonIsTemplateKey(raw)) return true;
|
|
if (raw.indexOf('soondesign_file:') === 0 || raw.indexOf('soondesign_session:') === 0) return true;
|
|
var filters = options && options.filters;
|
|
if (filters && Array.isArray(filters)) {
|
|
for (var i = 0; i < filters.length; i++) {
|
|
var exts = filters[i].extensions;
|
|
if (exts && exts.indexOf('soon') >= 0) return true;
|
|
}
|
|
return false;
|
|
}
|
|
return /\.soon$/i.test(raw.split(/[/\\]/).pop() || '');
|
|
}
|
|
|
|
function genericSaveDialogName(raw) {
|
|
var n = String(raw || 'file').trim();
|
|
return n.split(/[/\\]/).pop() || n || 'file';
|
|
}
|
|
|
|
function resolveSaveDialogName(name, options, isSoon) {
|
|
var n = String(name || '').trim();
|
|
if (!n) n = isSoon ? 'design.soon' : 'file';
|
|
if (isSoon) {
|
|
return typeof window.soonEnsureSoonExt === 'function'
|
|
? window.soonEnsureSoonExt(n)
|
|
: normalizeSoonName(n);
|
|
}
|
|
return genericSaveDialogName(n);
|
|
}
|
|
|
|
function defaultSoonSaveDialogName(raw) {
|
|
if (!raw || (typeof window.soonIsTemplateKey === 'function' && window.soonIsTemplateKey(raw))) {
|
|
return typeof window.soonDefaultNewSoonName === 'function'
|
|
? window.soonDefaultNewSoonName()
|
|
: normalizeSoonName('design.soon');
|
|
}
|
|
if (raw.indexOf('soondesign_file:') === 0 && typeof window.soonDisplayFileName === 'function') {
|
|
return window.soonDisplayFileName(raw);
|
|
}
|
|
return normalizeSoonName(raw);
|
|
}
|
|
|
|
var bridge = {
|
|
readHistory: function () {
|
|
try {
|
|
var raw = localStorage.getItem(HISTORY_KEY);
|
|
return Promise.resolve(raw ? JSON.parse(raw) : { history: [] });
|
|
} catch (e) {
|
|
return Promise.resolve({ history: [] });
|
|
}
|
|
},
|
|
writeHistory: function (data) {
|
|
try {
|
|
localStorage.setItem(HISTORY_KEY, JSON.stringify(data));
|
|
return Promise.resolve({ success: true });
|
|
} catch (e) {
|
|
return Promise.resolve({ success: false, error: e.message });
|
|
}
|
|
},
|
|
listCloudFiles: listCloudFiles,
|
|
createCloudFile: createCloudFile,
|
|
updateCloudFile: updateCloudFile,
|
|
deleteCloudFile: deleteCloudFile,
|
|
importSoonFile: importSoonFile,
|
|
downloadCloudFile: downloadCloudFile,
|
|
requireCloudAuth: requireCloudAuth,
|
|
readJsonFile: function (pathOrHandle) {
|
|
if (!pathOrHandle) return Promise.resolve(null);
|
|
if (typeof pathOrHandle === 'object' && pathOrHandle.text) {
|
|
return pathOrHandle.text().then(function (t) {
|
|
try { return JSON.parse(t); } catch (e) { return null; }
|
|
});
|
|
}
|
|
var key = typeof pathOrHandle === 'string' ? pathOrHandle : '';
|
|
var cacheKey = key;
|
|
|
|
function cacheHitThen(hit) {
|
|
if (!hit || !hit.json) return null;
|
|
if (typeof window.soonLocalIsTemplateStale === 'function' &&
|
|
window.soonLocalIsTemplateStale(cacheKey, hit.meta)) {
|
|
if (typeof window.soonLocalRemove === 'function') {
|
|
return window.soonLocalRemove(cacheKey).then(function () { return null; });
|
|
}
|
|
return Promise.resolve(null);
|
|
}
|
|
if (cacheKey.indexOf('soondesign_file:') === 0 && hit.meta && hit.meta.name &&
|
|
typeof window.soonBindFileMeta === 'function') {
|
|
window.soonBindFileMeta(cacheKey, { name: hit.meta.name });
|
|
}
|
|
return Promise.resolve(hit.json);
|
|
}
|
|
|
|
function afterNetworkJson(json, meta) {
|
|
if (!json) return null;
|
|
if (typeof window.soonLocalCacheAndThumb === 'function') {
|
|
return window.soonLocalCacheAndThumb(cacheKey, json, meta || {}).then(function () { return json; });
|
|
}
|
|
return json;
|
|
}
|
|
|
|
if (key && typeof window.soonLocalGet === 'function') {
|
|
return window.soonLocalGet(cacheKey).then(function (hit) {
|
|
return cacheHitThen(hit).then(function (cached) {
|
|
if (cached) return cached;
|
|
return fetchFromNetwork(key, cacheKey);
|
|
});
|
|
}).catch(function () { return fetchFromNetwork(key, cacheKey); });
|
|
}
|
|
return fetchFromNetwork(key, cacheKey);
|
|
|
|
function fetchFromNetwork(key, cacheKey) {
|
|
if (key.indexOf('soondesign_session:') === 0) {
|
|
if (typeof window.soonLocalGet === 'function') {
|
|
return window.soonLocalGet(cacheKey).then(function (hit) {
|
|
if (hit && hit.json) return hit.json;
|
|
try {
|
|
var j = sessionStorage.getItem(key);
|
|
if (!j && typeof localStorage !== 'undefined') j = localStorage.getItem(key);
|
|
if (!j || j === 'idb') return null;
|
|
var parsed = JSON.parse(j);
|
|
return afterNetworkJson(parsed, { source: 'session', name: key });
|
|
} catch (e) { return null; }
|
|
});
|
|
}
|
|
try {
|
|
var j = sessionStorage.getItem(key);
|
|
if (!j && typeof localStorage !== 'undefined') j = localStorage.getItem(key);
|
|
if (!j || j === 'idb') return Promise.resolve(null);
|
|
return Promise.resolve(JSON.parse(j));
|
|
} catch (e) { return Promise.resolve(null); }
|
|
}
|
|
if (key && key.indexOf('soondesign_file:') === 0 && typeof fetch !== 'undefined') {
|
|
var fileMatch = key.match(/^soondesign_file:(\d+)/);
|
|
if (fileMatch && getAccessToken()) {
|
|
return authedFetch('files/' + fileMatch[1], { headers: { Accept: 'application/json' } })
|
|
.then(function (response) {
|
|
if (!response.ok) return null;
|
|
return response.json();
|
|
})
|
|
.then(function (payload) {
|
|
if (!payload || !payload.ok || !payload.data) return null;
|
|
var raw = payload.data.json;
|
|
var parsed;
|
|
if (typeof raw === 'string') {
|
|
try { parsed = JSON.parse(raw); } catch (e) { return null; }
|
|
} else {
|
|
parsed = raw && typeof raw === 'object' ? raw : null;
|
|
}
|
|
if (!parsed) return null;
|
|
if (typeof window.soonApplyCloudMeta === 'function') {
|
|
window.soonApplyCloudMeta(payload.data);
|
|
}
|
|
return afterNetworkJson(parsed, {
|
|
source: 'cloud',
|
|
name: payload.data.name || '',
|
|
type: parsed.soonType || 1,
|
|
updatedAt: payload.data.updated_at || ''
|
|
});
|
|
})
|
|
.catch(function () { return null; });
|
|
}
|
|
}
|
|
if (key && key.indexOf('soondesign_template:') === 0 && typeof fetch !== 'undefined') {
|
|
var tplMatch = key.match(/^soondesign_template:(\d+)/);
|
|
if (tplMatch) {
|
|
var apiBase = (window.SOON_DEPLOY_CONFIG && window.SOON_DEPLOY_CONFIG.api_v1_base) || '';
|
|
if (!apiBase) return Promise.resolve(null);
|
|
return fetch(apiBase + '/templates/' + tplMatch[1] + '/file', { headers: { Accept: 'application/json' } })
|
|
.then(function (response) {
|
|
if (!response.ok) return null;
|
|
return response.text();
|
|
})
|
|
.then(function (text) {
|
|
if (!text) return null;
|
|
var parsed;
|
|
try { parsed = JSON.parse(text); } catch (e) { return null; }
|
|
var tplMeta = window._soonTemplateMeta || {};
|
|
return afterNetworkJson(parsed, {
|
|
source: 'template',
|
|
name: tplMeta.name || '',
|
|
type: tplMeta.type || (parsed.soonType || 1),
|
|
updatedAt: tplMeta.updated_at || ''
|
|
});
|
|
})
|
|
.catch(function () { return null; });
|
|
}
|
|
}
|
|
return Promise.resolve(null);
|
|
}
|
|
},
|
|
showOpenDialog: function (options) {
|
|
return new Promise(function (resolve) {
|
|
var input = document.createElement('input');
|
|
input.type = 'file';
|
|
if (options && options.filters && Array.isArray(options.filters) && options.filters.length > 0) {
|
|
var acceptList = [];
|
|
options.filters.forEach(function (filter) {
|
|
if (filter.extensions && Array.isArray(filter.extensions)) {
|
|
filter.extensions.forEach(function (ext) {
|
|
var cleanExt = ext.replace(/^\./, '');
|
|
if (['png', 'jpg', 'jpeg', 'gif', 'bmp', 'webp', 'svg'].indexOf(cleanExt.toLowerCase()) >= 0) {
|
|
var mimeType = 'image/' + (cleanExt.toLowerCase() === 'jpg' ? 'jpeg' : cleanExt.toLowerCase());
|
|
if (acceptList.indexOf(mimeType) < 0) acceptList.push(mimeType);
|
|
} else {
|
|
var extWithDot = '.' + cleanExt;
|
|
if (acceptList.indexOf(extWithDot) < 0) acceptList.push(extWithDot);
|
|
}
|
|
});
|
|
}
|
|
});
|
|
input.accept = acceptList.length > 0 ? acceptList.join(',') : '';
|
|
} else {
|
|
input.accept = '.soon,application/json';
|
|
}
|
|
input.style.display = 'none';
|
|
input.onchange = function () {
|
|
var f = input.files && input.files[0];
|
|
document.body.removeChild(input);
|
|
if (!f) resolve({ canceled: true });
|
|
else resolve({ canceled: false, filePaths: [], files: [f], file: f });
|
|
};
|
|
document.body.appendChild(input);
|
|
input.click();
|
|
});
|
|
},
|
|
showSaveDialog: function (options) {
|
|
var raw = (options && options.defaultPath) ? options.defaultPath : '';
|
|
var isSoon = isSoonSaveDialog(options);
|
|
var defaultName = isSoon ? defaultSoonSaveDialogName(raw) : genericSaveDialogName(raw);
|
|
var title = (options && options.title) ? options.title : (isSoon ? '保存到云端' : '保存文件');
|
|
return new Promise(function (resolve) {
|
|
if (typeof layer === 'undefined' || !layer.open) {
|
|
resolve({ canceled: false, filePath: defaultName, useCloud: !!isSoon });
|
|
return;
|
|
}
|
|
var esc = function (s) {
|
|
return String(s || '').replace(/&/g, '&').replace(/</g, '<').replace(/"/g, '"');
|
|
};
|
|
var html = '<div class="soon-dialog-body" style="padding:16px 20px;">' +
|
|
'<label style="display:block;margin-bottom:8px;color:#b8c0c8;font-size:13px;">文件名</label>' +
|
|
'<input type="text" id="soonSaveDialogInput" class="layui-input" value="' + esc(defaultName) + '" ' +
|
|
'style="background:#2b3036;border-color:rgba(255,255,255,0.08);color:#eef1f4;">' +
|
|
'</div>';
|
|
layer.open({
|
|
type: 1,
|
|
skin: 'soon-layer',
|
|
title: title,
|
|
area: ['360px', 'auto'],
|
|
shadeClose: false,
|
|
content: html,
|
|
btn: ['确定', '取消'],
|
|
btnAlign: 'r',
|
|
yes: function (index) {
|
|
var input = document.getElementById('soonSaveDialogInput');
|
|
var name = input && input.value ? String(input.value).trim() : defaultName;
|
|
name = resolveSaveDialogName(name, options, isSoon);
|
|
layer.close(index);
|
|
resolve({ canceled: false, filePath: name, useCloud: !!isSoon });
|
|
},
|
|
btn2: function (index) {
|
|
layer.close(index);
|
|
resolve({ canceled: true });
|
|
},
|
|
cancel: function (index) {
|
|
layer.close(index);
|
|
resolve({ canceled: true });
|
|
}
|
|
});
|
|
});
|
|
},
|
|
writeFile: function (pathOrHandle, content) {
|
|
var isBlob = content instanceof Blob;
|
|
var str = typeof content === 'string' ? content : (isBlob ? null : (content && content.toString ? content.toString() : ''));
|
|
|
|
if (isBlob) {
|
|
var blobName = typeof pathOrHandle === 'string' ? pathOrHandle : 'output.bin';
|
|
var a = document.createElement('a');
|
|
a.download = blobName;
|
|
a.href = URL.createObjectURL(content);
|
|
a.click();
|
|
URL.revokeObjectURL(a.href);
|
|
return Promise.resolve();
|
|
}
|
|
|
|
if (pathOrHandle && pathOrHandle.createWritable) {
|
|
pathOrHandle = typeof pathOrHandle.name === 'string' ? pathOrHandle.name : 'design.soon';
|
|
}
|
|
|
|
var name = typeof pathOrHandle === 'string' ? pathOrHandle : 'design.soon';
|
|
var cloudRef = parseCloudRef(name);
|
|
var fileName = normalizeSoonName(name);
|
|
|
|
var parsedJson;
|
|
try { parsedJson = JSON.parse(str); } catch (e) { parsedJson = null; }
|
|
|
|
function cacheWriteForKey(targetKey, meta) {
|
|
if (!parsedJson || typeof window.soonLocalCacheAndThumb !== 'function') return Promise.resolve();
|
|
return window.soonLocalCacheAndThumb(targetKey, parsedJson, meta || {});
|
|
}
|
|
|
|
function afterCloudSave(res, prevKey) {
|
|
if (!res || !res.fileKey || !parsedJson) return res;
|
|
var meta = { source: 'cloud', name: res.name || fileName, type: parsedJson.soonType || 1 };
|
|
if (prevKey && prevKey !== res.fileKey && typeof window.soonLocalRenameKey === 'function') {
|
|
return window.soonLocalRenameKey(prevKey, res.fileKey, meta).then(function () { return res; });
|
|
}
|
|
return cacheWriteForKey(res.fileKey, meta).then(function () { return res; });
|
|
}
|
|
|
|
if (!getAccessToken()) {
|
|
if (cloudRef && cloudRef.id) {
|
|
requireCloudAuth('保存');
|
|
return Promise.reject(new Error('unauthorized'));
|
|
}
|
|
var sessionKey = typeof window.soonMakeSessionKey === 'function'
|
|
? window.soonMakeSessionKey(name)
|
|
: (name.indexOf('soondesign_session:') === 0
|
|
? name
|
|
: 'soondesign_session:' + fileName.replace(/\.soon$/i, ''));
|
|
var prevSessionKey = name.indexOf('soondesign_session:') === 0 ? name : '';
|
|
function finishSessionSave() {
|
|
try { sessionStorage.setItem(sessionKey, 'idb'); } catch (e) { /* ignore */ }
|
|
return { fileKey: sessionKey, name: fileName, version: 0 };
|
|
}
|
|
if (prevSessionKey && prevSessionKey !== sessionKey &&
|
|
typeof window.soonLocalRenameKey === 'function') {
|
|
return cacheWriteForKey(sessionKey, { source: 'session', name: fileName }).then(function () {
|
|
return window.soonLocalRenameKey(prevSessionKey, sessionKey, { source: 'session', name: fileName })
|
|
.then(finishSessionSave);
|
|
}).catch(function () {
|
|
return Promise.reject(new Error('save_failed'));
|
|
});
|
|
}
|
|
return cacheWriteForKey(sessionKey, { source: 'session', name: fileName }).then(function () {
|
|
return finishSessionSave();
|
|
}).catch(function () {
|
|
return Promise.reject(new Error('save_failed'));
|
|
});
|
|
}
|
|
|
|
if (!requireCloudAuth('保存')) {
|
|
return Promise.reject(new Error('unauthorized'));
|
|
}
|
|
|
|
if (cloudRef && cloudRef.id) {
|
|
var ver = cloudRef.version;
|
|
if (ver == null && window._soonFileMeta && window._soonFileMeta.id === cloudRef.id) {
|
|
ver = window._soonFileMeta.version;
|
|
}
|
|
if (typeof window.soonResolveCloudFileName === 'function') {
|
|
var cloudSaveName = window.soonResolveCloudFileName(name);
|
|
if (cloudSaveName) fileName = cloudSaveName;
|
|
}
|
|
var prevCloudKey = name;
|
|
return updateCloudFile(cloudRef.id, fileName, str, ver).then(function (res) {
|
|
return afterCloudSave(res, prevCloudKey);
|
|
});
|
|
}
|
|
|
|
var prevKey = name.indexOf('soondesign_session:') === 0 ? name : '';
|
|
return createCloudFile(fileName, str).then(function (res) {
|
|
return afterCloudSave(res, prevKey);
|
|
});
|
|
},
|
|
readFile: function (pathOrHandle) {
|
|
if (pathOrHandle && pathOrHandle.getFile) {
|
|
return pathOrHandle.getFile().then(function (f) {
|
|
return new Promise(function (res, rej) {
|
|
var r = new FileReader();
|
|
r.onload = function () { res(r.result); };
|
|
r.onerror = rej;
|
|
r.readAsArrayBuffer(f);
|
|
});
|
|
});
|
|
}
|
|
if (pathOrHandle && pathOrHandle.arrayBuffer) {
|
|
return pathOrHandle.arrayBuffer();
|
|
}
|
|
return Promise.reject(new Error('No file'));
|
|
},
|
|
getAppVersion: function () { return Promise.resolve(VERSION); },
|
|
getLocale: getLocale,
|
|
getUserDataPath: function () { return ''; },
|
|
getSystemFonts: getSystemFonts,
|
|
openDesignPage: function (file, type) {
|
|
var t = type || 1;
|
|
var key = file || '';
|
|
if (typeof window.soonSyncOpenNavigation === 'function') {
|
|
window.soonSyncOpenNavigation(key, t);
|
|
}
|
|
var fileParam = key ? encodeURIComponent(key) : '';
|
|
navigateToPage('design' + t + '.web.html?file=' + fileParam + '&type=' + t);
|
|
},
|
|
openFirstPage: function () {
|
|
navigateToPage('index.web.html');
|
|
},
|
|
onClose: function (callback) {
|
|
if (typeof window !== 'undefined') {
|
|
window.addEventListener('beforeunload', callback);
|
|
}
|
|
},
|
|
runClose: function () {
|
|
if (typeof window !== 'undefined' && window.close) window.close();
|
|
},
|
|
openHelp: function () {
|
|
try {
|
|
window.open(new URL('../assets/help/User Manual.pdf', window.location.href).href, '_blank');
|
|
} catch (e) {
|
|
window.open('../assets/help/User Manual.pdf', '_blank');
|
|
}
|
|
},
|
|
printPdf: function (urlOrBlob) {
|
|
var url = urlOrBlob;
|
|
if (urlOrBlob && typeof urlOrBlob === 'object' && !(urlOrBlob instanceof String)) {
|
|
url = URL.createObjectURL(urlOrBlob);
|
|
}
|
|
var w = window.open(url, '_blank');
|
|
if (w) w.onload = function () { w.print(); };
|
|
},
|
|
getScaleRate: function () {
|
|
return typeof window !== 'undefined' && window.devicePixelRatio ? window.devicePixelRatio : 1;
|
|
},
|
|
clipboard: {
|
|
readText: function () {
|
|
return navigator.clipboard && navigator.clipboard.readText ? navigator.clipboard.readText() : Promise.resolve('');
|
|
},
|
|
writeText: function (text) {
|
|
if (navigator.clipboard && navigator.clipboard.writeText) {
|
|
return navigator.clipboard.writeText(text);
|
|
}
|
|
return Promise.resolve();
|
|
}
|
|
}
|
|
};
|
|
|
|
window.platformBridge = bridge;
|
|
|
|
var pathStub = {
|
|
join: function () { return [].slice.call(arguments).join('/').replace(/\/+/g, '/'); }
|
|
};
|
|
|
|
window.sysAPI = {
|
|
readHistory: bridge.readHistory,
|
|
writeHistory: bridge.writeHistory,
|
|
readJsonFile: bridge.readJsonFile,
|
|
getAppVersion: bridge.getAppVersion
|
|
};
|
|
window.dialog = {
|
|
showOpenDialog: bridge.showOpenDialog,
|
|
showSaveDialog: bridge.showSaveDialog
|
|
};
|
|
window.soonShowSaveDialog = bridge.showSaveDialog;
|
|
window.path = pathStub;
|
|
window.fs = null;
|
|
window.remote = null;
|
|
var loc = getLocale();
|
|
window.ipcRenderer = {
|
|
send: function (ch, a1, a2) {
|
|
if (ch === 'get-sys-language') { window._sysLanPending = true; setTimeout(function () { if (window._sysLanCb && window._sysLanPending) { window._sysLanCb(null, loc); window._sysLanPending = false; } }, 0); }
|
|
if (ch === 'open-first-page' && bridge.openFirstPage) { bridge.openFirstPage(); }
|
|
if (ch === 'open-design-page' && bridge.openDesignPage && (a1 !== undefined || a2 !== undefined)) { bridge.openDesignPage(a1 || '', a2 || 1); }
|
|
if (ch === 'open-help-file' && bridge.openHelp) { bridge.openHelp(); }
|
|
if (ch === 'run-close' && bridge.runClose) { bridge.runClose(); }
|
|
},
|
|
on: function (ch, cb) {
|
|
if (ch === 'sys-lan') { window._sysLanCb = cb; if (window._sysLanPending) setTimeout(function () { if (window._sysLanCb) { window._sysLanCb(null, loc); window._sysLanPending = false; } }, 0); }
|
|
if (ch === 'close') window._closeCb = cb;
|
|
}
|
|
};
|
|
window.clipboard = bridge.clipboard;
|
|
window.exePath = '';
|
|
window.fullPath = '';
|
|
})();
|