Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
128 changes: 49 additions & 79 deletions lib/document.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,9 @@ export const onCreateNew = async (ext: string): Promise<void> => {
// Note: Loading is now shown in the menu button click handler
// This function should not show loading again to avoid double loading indicators
try {
// Hide control panel if it's visible
// Always hide control panel and ensure FAB is visible when creating new document
if (hideControlPanelFn) {
const container = document.querySelector('#control-panel-container') as HTMLElement;
if (container && container.style.display !== 'none') {
hideControlPanelFn();
}
hideControlPanelFn();
}
setDocmentObj({
fileName: 'New_Document' + ext,
Expand All @@ -62,88 +59,61 @@ export const onCreateNew = async (ext: string): Promise<void> => {
}
};

export const onOpenDocument = async (): Promise<boolean> => {
return new Promise((resolve) => {
let resolved = false;
let cancelTimeout: NodeJS.Timeout | null = null;
export const onOpenDocument = (): void => {
// Clear previous event handler and value
fileInput.onchange = null;
fileInput.value = '';

// Clear previous event handler and value
fileInput.onchange = null;
fileInput.value = '';

// Set up a longer timeout to detect if user cancelled (no change event)
// This handles the case where user cancels without triggering onchange
// Use a longer timeout (5 seconds) to avoid false positives
cancelTimeout = setTimeout(() => {
if (!resolved) {
resolved = true;
fileInput.value = '';
fileInput.onchange = null;
resolve(false);
}
}, 5000);

// Define the change handler
const handleChange = async (event: Event) => {
if (cancelTimeout) {
clearTimeout(cancelTimeout);
cancelTimeout = null;
}
// Define the change handler
const handleChange = async (event: Event) => {
const file = (event.target as HTMLInputElement).files?.[0];

const file = (event.target as HTMLInputElement).files?.[0];

// Clear the handler to prevent multiple triggers
fileInput.onchange = null;
// Clear the handler to prevent multiple triggers
fileInput.onchange = null;

if (file && !resolved) {
resolved = true;
const { removeLoading } = showLoading();
try {
if (hideControlPanelFn) {
hideControlPanelFn();
}
setDocmentObj({
fileName: file.name,
file: file,
url: await createObjectURL(file),
});
await initX2T();
const { fileName, file: fileBlob } = getDocmentObj();
await handleDocumentOperation({ file: fileBlob, fileName, isNew: !fileBlob });
// Clear file selection so the same file can be selected again
fileInput.value = '';
// Show menu guide after document is loaded
if (showMenuGuideFn) {
setTimeout(() => {
showMenuGuideFn!();
}, 1000);
}
resolve(true);
} catch (error) {
console.error('Error opening document:', error);
// Ensure control panel is shown on error
if (showControlPanelFn) {
showControlPanelFn();
}
resolve(false);
} finally {
// Always remove loading, even if there's an error
removeLoading();
// Only process if a file was actually selected
// If user cancelled, onchange won't fire, nothing happens
if (file) {
const { removeLoading } = showLoading();
try {
if (hideControlPanelFn) {
hideControlPanelFn();
}
} else if (!resolved) {
// onchange fired but no file selected (user cancelled or cleared selection)
resolved = true;
setDocmentObj({
fileName: file.name,
file: file,
url: await createObjectURL(file),
});
await initX2T();
const { fileName, file: fileBlob } = getDocmentObj();
await handleDocumentOperation({ file: fileBlob, fileName, isNew: !fileBlob });
// Clear file selection so the same file can be selected again
fileInput.value = '';
resolve(false);
// Show menu guide after document is loaded
if (showMenuGuideFn) {
setTimeout(() => {
showMenuGuideFn!();
}, 1000);
}
} catch (error) {
console.error('Error opening document:', error);
// Ensure control panel is shown on error
if (showControlPanelFn) {
showControlPanelFn();
}
} finally {
// Always remove loading, even if there's an error
removeLoading();
}
};
}
// If no file selected, nothing happens (user cancelled)
};

// Set the change handler
fileInput.onchange = handleChange;
// Set the change handler
fileInput.onchange = handleChange;

// Trigger file picker click event
fileInput.click();
});
// Trigger file picker click event
fileInput.click();
};

export const openDocumentFromUrl = async (url: string, fileName?: string): Promise<void> => {
Expand Down
64 changes: 34 additions & 30 deletions lib/ui.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,20 @@ import { onCreateNew, onOpenDocument } from './document';
// Hide control panel and show top floating bar
export const hideControlPanel = (): void => {
const container = document.querySelector('#control-panel-container') as HTMLElement;
const fabContainer = document.querySelector('#fab-container') as HTMLElement;

// Always ensure FAB is visible when hiding control panel
if (fabContainer) {
fabContainer.style.display = 'block';
}

if (container) {
// Immediately disable pointer events to prevent blocking
container.style.pointerEvents = 'none';
container.style.opacity = '0';
// Hide after transition for smooth animation
setTimeout(() => {
container.style.display = 'none';
showTopFloatingBar();
}, 300);
}
};
Expand All @@ -28,19 +34,13 @@ export const showControlPanel = (): void => {
container.style.opacity = '1';
}, 10);
}
if (fabContainer) {
// Only hide FAB if editor is not open
// If editor is already open, keep FAB visible so user can access menu
if (fabContainer && !window.editor) {
fabContainer.style.display = 'none';
}
};

// Show fixed action button
const showTopFloatingBar = (): void => {
const fabContainer = document.querySelector('#fab-container') as HTMLElement;
if (fabContainer) {
fabContainer.style.display = 'block';
}
};

// Create fixed action button in bottom right corner
export const createFixedActionButton = (): HTMLElement => {
const fabContainer = document.createElement('div');
Expand All @@ -58,7 +58,7 @@ export const createFixedActionButton = (): HTMLElement => {
menuPanel.id = 'fab-menu';
menuPanel.className = 'fab-menu';

const createMenuButton = (text: string, onClick: () => void | Promise<void>) => {
const createMenuButton = (text: string, onClick: () => void | Promise<void>, showLoadingImmediately = true) => {
// Create wrapper for the entire menu item
const menuItem = document.createElement('div');
menuItem.className = 'fab-menu-item';
Expand All @@ -77,8 +77,12 @@ export const createFixedActionButton = (): HTMLElement => {

button.addEventListener('click', async () => {
hideMenu();
// Show loading immediately before any async operations
const { removeLoading } = showLoading();
// Only show loading immediately if specified (for operations that don't require user interaction)
let removeLoading: (() => void) | null = null;
if (showLoadingImmediately) {
const loadingResult = showLoading();
removeLoading = loadingResult.removeLoading;
}
try {
// Small delay to ensure menu hide animation completes
await new Promise((resolve) => setTimeout(resolve, 100));
Expand All @@ -88,8 +92,10 @@ export const createFixedActionButton = (): HTMLElement => {
// Show control panel on error
showControlPanel();
} finally {
// Always remove loading
removeLoading();
// Only remove loading if it was shown
if (removeLoading) {
removeLoading();
}
}
});

Expand All @@ -98,14 +104,15 @@ export const createFixedActionButton = (): HTMLElement => {
};

menuPanel.appendChild(
createMenuButton(t('uploadDocument'), async () => {
const result = await onOpenDocument();
// If user cancelled file selection, show control panel again
// (FAB menu will be hidden by hideMenu() call in createMenuButton)
if (!result) {
showControlPanel();
}
}),
createMenuButton(
t('uploadDocument'),
() => {
onOpenDocument();
// If user cancelled, nothing happens (onchange won't fire)
// If user selected file, document will be opened in handleChange
},
false, // Don't show loading immediately - wait for file selection
),
);
menuPanel.appendChild(
createMenuButton(t('newWord'), async () => {
Expand Down Expand Up @@ -310,13 +317,10 @@ export const createControlPanel = (): void => {
};

// Create four buttons
const uploadButton = createTextButton('upload-button', t('uploadDocument'), async () => {
const result = await onOpenDocument();
// Only hide control panel if file was successfully selected
// If user cancelled, control panel remains visible
if (result) {
hideControlPanel();
}
const uploadButton = createTextButton('upload-button', t('uploadDocument'), () => {
onOpenDocument();
// If user cancelled, nothing happens (onchange won't fire, control panel remains visible)
// If user selected file, document will be opened and control panel will be hidden in handleChange
});
buttonGroup.appendChild(uploadButton);

Expand Down
4 changes: 1 addition & 3 deletions public/sdkjs/cell/sdk-all-min.js
Original file line number Diff line number Diff line change
Expand Up @@ -20659,9 +20659,7 @@ function mg(t, e) {
(t.AscCommon.sHh = function (e, s) {
t.NATIVE_EDITOR_ENJINE ||
d(
('chrome-extension:' == t.location?.protocol
? 'https://bangong.360.cn/office/SmartArts/'
: '../../../../sdkjs/common/SmartArts/') + 'SmartArts.bin',
(false ? '' : '../../../../sdkjs/common/SmartArts/') + 'SmartArts.bin',
function (t) {
if (t && t.response) {
((t = AscCommon.a$d(t)),
Expand Down
30 changes: 10 additions & 20 deletions public/sdkjs/cell/sdk-all.js
Original file line number Diff line number Diff line change
Expand Up @@ -128328,8 +128328,8 @@
var t = new XMLHttpRequest();
t.sRa = this;
let w;
const z = n.includes('bangong.360.cn');
'chrome-extension:' != a.location?.protocol || z ? ((n += r[this.jb]), (w = !0)) : (n = this.jb);
const z = false;
z ? ((n += r[this.jb]), (w = !0)) : (n = this.jb);
t.open('GET', n, !0);
'undefined' === typeof ArrayBuffer || a.opera || (t.responseType = 'arraybuffer');
t.overrideMimeType
Expand All @@ -128350,12 +128350,11 @@
this.sRa.externalCallback && this.sRa.externalCallback();
};
t.onerror = function () {
z
? (this.sRa.GFe++,
3 > this.sRa.GFe
? (this.sRa.vE = 0)
: ((this.sRa.vE = 2), a.Asc.editor.Pe('asc_onError', Asc.Qe.Yb.HFe, Asc.Qe.ee.y4)))
: this.sRa.yFe('https://bangong.360.cn/office/fonts/');
// Use local error handling only
this.sRa.GFe++;
3 > this.sRa.GFe
? (this.sRa.vE = 0)
: ((this.sRa.vE = 2), a.Asc.editor.Pe('asc_onError', Asc.Qe.Yb.HFe, Asc.Qe.ee.y4));
};
t.send(null);
};
Expand Down Expand Up @@ -128541,13 +128540,8 @@
})(window, window.document);
(function (a) {
function b() {
'chrome-extension:' == a.location?.protocol
? ((this.xZc = '../../../../fonts/'),
fetch('file:///C:').catch(() => {
AscFonts.Opi = !1;
this.xZc = 'https://bangong.360.cn/office/fonts/';
}))
: (this.xZc = '../../../../fonts/');
// Always use local fonts path
this.xZc = '../../../../fonts/';
this.EZb = AscFonts.odf;
this.fPd = AscFonts.MZb;
this.Uvc = AscFonts.OZb;
Expand Down Expand Up @@ -407691,11 +407685,7 @@
Rch: function (p, k) {
let r = a.origin;
b === r && (r = a.location.origin);
return k.origin === r || (k.origin && 0 === k.origin.indexOf('chrome-extension://'))
? !0
: (p = this.FRa(p)) && 0 === p.DT.indexOf(k.origin)
? !0
: !1;
return k.origin === r ? !0 : (p = this.FRa(p)) && 0 === p.DT.indexOf(k.origin) ? !0 : !1;
},
Kzc: function (p) {
if (0 !== this.sTa.length) {
Expand Down
4 changes: 1 addition & 3 deletions public/sdkjs/slide/sdk-all-min.js
Original file line number Diff line number Diff line change
Expand Up @@ -20368,9 +20368,7 @@ function Ff(t, e) {
(t.AscCommon.C_g = function (e, o) {
t.NATIVE_EDITOR_ENJINE ||
p(
('chrome-extension:' == t.location?.protocol
? 'https://bangong.360.cn/office/SmartArts/'
: '../../../../sdkjs/common/SmartArts/') + 'SmartArts.bin',
(false ? '' : '../../../../sdkjs/common/SmartArts/') + 'SmartArts.bin',
function (t) {
if (t && t.response) {
((t = AscCommon.bXe(t)),
Expand Down
Loading
Loading