Merge branch 'fun-with-browsers' of https://github.com/hearmeneigh/fchat-rising into fun-with-browsers

This commit is contained in:
Mr. Stallion 2023-12-01 17:41:12 -08:00
commit fb5cec06ba
6 changed files with 151 additions and 30 deletions

View File

@ -127,7 +127,10 @@ export class BBCodeParser {
isAllowed = (name) => self.isAllowed(name) && parentAllowed(name);
currentTag = this._currentTag = {tag: self.tag, line: this._line, column: this._column};
}
let tagStart = -1, paramStart = -1, mark = start;
let tagStart = -1,
paramStart = -1,
mark = start,
isInCollapseParam = false;
for(let i = start; i < input.length; ++i) {
const c = input[i];
++this._column;
@ -135,12 +138,22 @@ export class BBCodeParser {
++this._line;
this._column = 1;
}
if(c === '[') {
if(c === '[' && !isInCollapseParam) {
tagStart = i;
paramStart = -1;
} else if(c === '=' && paramStart === -1)
paramStart = i;
} else if(c === '=' && paramStart === -1) {
paramStart = i;
const paramIndex = paramStart === -1 ? i : paramStart;
let tagKey = input
.substring(tagStart + 1, paramIndex)
.trim()
.toLowerCase();
if (tagKey == "collapse") isInCollapseParam = true;
}
else if(c === ']') {
const paramIndex = paramStart === -1 ? i : paramStart;
let tagKey = input.substring(tagStart + 1, paramIndex).trim().toLowerCase();
if(tagKey.length === 0) {
@ -154,6 +167,17 @@ export class BBCodeParser {
tagStart = -1;
continue;
}
if (isInCollapseParam) {
let fullTagKey = input
.substring(tagStart + 1, i + 1)
.trim()
.toLowerCase();
if (fullTagKey.endsWith("[hr]")) {
continue;
}
}
isInCollapseParam = false;
if(!close) {
const tag = this._tags[tagKey]!;
const allowed = isAllowed(tagKey);

View File

@ -72,8 +72,15 @@ export class StandardBBCodeParser extends CoreBBCodeParser {
const icon = parser.createElement('i');
icon.className = 'fas fa-chevron-down';
icon.style.marginRight = '10px';
headerText.appendChild(icon);
headerText.appendChild(document.createTextNode(param));
// HACK: to allow [hr] in header part
if (param.startsWith('[hr]')) { headerText.appendChild(parser.createElement('hr')); param = param.slice(4) }
headerText.appendChild(icon);
const splitParam = param.split('[hr]')
for (let iii = 0; iii < splitParam.length; iii++) {
const element = splitParam[iii];
headerText.appendChild(document.createTextNode(element));
if (iii < splitParam.length-1) headerText.appendChild(parser.createElement('hr'))
}
outer.appendChild(headerText);
const body = parser.createElement('div');
body.className = 'bbcode-collapse-body';

View File

@ -197,6 +197,7 @@ Current log location: {1}`,
'settings.browserOptionArgumentsHelp': 'Arguments are separated by spaces. Use %s to insert the URL.',
'settings.browserOptionBrowse': 'Browse',
'settings.browserOptionSave': 'Save',
'settings.browserOptionReset': 'Reset to default',
'fixLogs.action': 'Fix corrupted logs',
'fixLogs.text': `There are a few reason log files can become corrupted - log files from old versions with bugs that have since been fixed or incomplete file operations caused by computer crashes are the most common.
If one of your log files is corrupted, you may get an "Unknown Type" error when you log in or when you open a specific tab. You may also experience other issues.

View File

@ -16,6 +16,21 @@
<div class="card bg-light" style="height:100%;width:100%;">
<div class="card-body row" style="height:100%;width:100%;">
<h4 class="card-title">{{l('settings.browserOptionTitle')}}</h4>
<div class="form-group col-12">
<div class="row">
<div class="col-12">
<div class="warning">
<h5>Danger Zone!</h5>
<div>This is an advanced setting. By changing this setting to an unsupported program (i.e. not a browser), you might not be able to open links from F-Chat anymore.</div>
<div v-if="isMac"><hr/>
<p>Mac User: As of writing, MacOS has a bug in how it handles opening links.</p>
<p>When your default browser is something other than Safari and you select Safari in this settings window, links might be opened twice.</p>
<p>Once in Safari and a second time in your default browser. This tends to happen when Safari is not running when clicking a link.</p></div>
</div>
</div>
</div>
</div>
<div class="form-group col-12">
<label class="control-label" for="browserPath">{{l('settings.browserOptionPath')}}</label>
<div class="row">
@ -41,9 +56,13 @@
</div>
</div>
<div class="form-group col-12">
<div class="row">
<div class="row no-gutters">
<div class="col-2">
<button class="btn btn-primary" @click.prevent.stop="submit()">{{l('settings.browserOptionSave')}}</button>
<button class="btn btn-primary" @click.prevent.stop="submit()">{{l('settings.browserOptionSave')}}</button>
</div>
<div class="col"></div>
<div class="col-4">
<button class="btn btn-danger" style="float: right;" @click.prevent.stop="resetToDefault()">{{l('settings.browserOptionReset')}}</button>
</div>
</div>
</div>
@ -83,6 +102,7 @@ export default class BrowserOption extends Vue {
hasCompletedUpgrades = false;
browserPath = '';
browserArgs = '';
isMac = process.platform === 'darwin';
get styling(): string {
try {
@ -144,6 +164,11 @@ export default class BrowserOption extends Vue {
this.close();
}
resetToDefault(): void {
this.browserPath = '';
this.browserArgs = '';
}
browseForPath(): void {
ipcRenderer.invoke('browser-option-browse').then((result) => {
this.browserPath = result;
@ -197,6 +222,16 @@ export default class BrowserOption extends Vue {
}
}
.warning {
border: 1px solid var(--warning);
padding: 10px;
margin-bottom: 20px;
border-radius: 3px;
div {
margin-top: 10px;
}
}
.disableWindowsHighContrast, .disableWindowsHighContrast * {
forced-color-adjust: none;

View File

@ -173,26 +173,53 @@ async function addSpellcheckerItems(menu: electron.Menu): Promise<void> {
}
function openURLExternally(linkUrl: string): void {
// check if user set a path, whether it exists and if it is a file
if(settings.browserPath !== '' &&
fs.existsSync(settings.browserPath) &&
fs.lstatSync(settings.browserPath).isFile()) {
// encode URL so if it contains spaces, it remains a single argument for the browser
linkUrl = encodeURI(linkUrl);
if(!settings.browserArgs.includes('%s')) {
// append %s to params if it is not already there
settings.browserArgs += ' %s';
// check if user set a path and whether it exists
const pathIsValid = (settings.browserPath !== '' && fs.existsSync(settings.browserPath));
if(pathIsValid) {
// also check if the user can execute whatever is located at the selected path
let fileIsExecutable = false;
try {
fs.accessSync(settings.browserPath, fs.constants.X_OK);
fileIsExecutable = true;
} catch (err) {
log.error(`Selected browser is not executable by user. Path: "${settings.browserPath}"`);
}
// replace %s in arguments with URL and encapsulate in quotes to prevent issues with spaces and special characters in the path
let link = settings.browserArgs.replace('%s', '\"'+linkUrl+'\"');
if (fileIsExecutable) {
// check if URL is already encoded
// (this should work almost all the time, but there might be edge-cases with very unusual URLs)
let isEncoded = (linkUrl !== decodeURI(linkUrl));
// only encode URL if it isn't encoded yet
if (!isEncoded) {
// encode URL so if it contains spaces, it remains a single argument for the browser
linkUrl = encodeURI(linkUrl);
}
const execFile = require('child_process').exec;
execFile(`"${settings.browserPath}" ${link}`);
} else {
electron.shell.openExternal(linkUrl);
if (!settings.browserArgs.includes('%s')) {
// append %s to params if it is not already there
settings.browserArgs += ' %s';
}
// replace %s in arguments with URL and encapsulate in quotes to prevent issues with spaces and special characters in the path
let link = settings.browserArgs.replace('%s', '\"' + linkUrl + '\"');
const execFile = require('child_process').exec;
if (process.platform === "darwin") {
// NOTE: This is seemingly bugged on MacOS when setting Safari as the external browser while using a different default browser.
// In that case, this will open the URL in both the selected application AND the default browser.
// Other browsers work fine. (Tested with Chrome with Firefox as the default browser.)
// https://developer.apple.com/forums/thread/685385
execFile(`open -a "${settings.browserPath}" ${link}`);
} else {
execFile(`"${settings.browserPath}" ${link}`);
}
return;
}
}
electron.shell.openExternal(linkUrl);
}
function setUpWebContents(webContents: electron.WebContents): void {
@ -315,17 +342,22 @@ function showPatchNotes(): void {
}
function openBrowserSettings(): electron.BrowserWindow | undefined {
let desiredHeight = 520;
if(process.platform === 'darwin') {
desiredHeight = 750;
}
const windowProperties: electron.BrowserWindowConstructorOptions = {
center: true,
show: false,
icon: process.platform === 'win32' ? winIcon : pngIcon,
frame: false,
width: 500,
height: 350,
minWidth: 500,
minHeight: 368,
maxWidth: 500,
maxHeight: 368,
width: 650,
height: desiredHeight,
minWidth: 650,
minHeight: desiredHeight,
maxWidth: 650,
maxHeight: desiredHeight,
maximizable: false,
webPreferences: {
webviewTag: true, nodeIntegration: true, nodeIntegrationInWorker: true, spellcheck: true,
@ -736,11 +768,23 @@ function onReady(): void {
electron.ipcMain.handle('browser-option-browse', async () => {
log.debug('settings.browserOption.browse');
console.log('settings.browserOption.browse', JSON.stringify(settings));
let filters;
if(process.platform === "win32") {
filters = [{ name: 'Executables', extensions: ['exe'] }];
} else if (process.platform === "darwin") {
filters = [{ name: 'Executables', extensions: ['app'] }];
} else {
// linux and anything else that might be supported
// no specific extension for executables
filters = [{ name: 'Executables', extensions: ['*'] }];
}
const dir = electron.dialog.showOpenDialogSync(
{
defaultPath: settings.browserPath,
properties: ['openFile'],
filters: [{ name: 'Executables', extensions: ['exe'] }]
filters: filters
});
if(dir !== undefined) {
return dir[0];

View File

@ -82,3 +82,13 @@ export function init(s: Settings, c: SimpleCharacter[]): void {
settings = s;
characters = c;
}
function escapeRegExp(string: string):
string {
return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); // $& means the whole matched string
}
export function replaceAll(str: string, find: string, replace: string):
string {
return str.replace(new RegExp(escapeRegExp(find), "g"), replace);
}