diff --git a/src/components/app.jsx b/src/components/app.jsx
index 968ae8f..77484a2 100644
--- a/src/components/app.jsx
+++ b/src/components/app.jsx
@@ -90,6 +90,7 @@ const version = '6.4.0';
window.forcedSettings = {};
window.codeHtml = '';
window.codeCss = '';
+window.codeLayout = null;
if (location.search) {
let match = location.search.replace(/^\?/, '').match(/settings=([^=]*)/);
if (match) {
@@ -105,6 +106,18 @@ if (location.search) {
const params = new URLSearchParams(location.search);
window.codeHtml = params.get('html') || '';
window.codeCss = params.get('css') || '';
+ window.codeLayout = (() => {
+ const layout = params.get('layout');
+ if (!layout) return null;
+ if (layout === 'full') {
+ return 5;
+ }
+ const _val = parseInt(layout, 10);
+ if (_val >= 1 && _val <= 5) {
+ return _val;
+ }
+ return null;
+ })();
}
function customRoute(path) {
@@ -291,6 +304,9 @@ export default class App extends Component {
code: ''
},
result => {
+ if (window.codeLayout) {
+ result.layoutMode = window.codeLayout;
+ }
this.toggleLayout(result.layoutMode);
this.state.prefs.layoutMode = result.layoutMode;
if (result.code) {
@@ -411,8 +427,11 @@ export default class App extends Component {
}
refreshEditor() {
+ // if window.codeLayout is set, use it, otherwise use the current item's layout mode
this.toggleLayout(
- this.state.currentItem.layoutMode || this.state.prefs.layoutMode
+ window.codeLayout
+ ? window.codeLayout
+ : this.state.currentItem.layoutMode || this.state.prefs.layoutMode
);
this.updateExternalLibCount();
this.contentWrap.refreshEditor();
diff --git a/tests/layout-parameter.test.js b/tests/layout-parameter.test.js
new file mode 100644
index 0000000..431a635
--- /dev/null
+++ b/tests/layout-parameter.test.js
@@ -0,0 +1,148 @@
+import { h, Component } from 'preact';
+
+// Mock the global objects and functions that are used in the app
+global.window = {
+ location: {
+ search: ''
+ },
+ localStorage: {
+ getItem: jest.fn(),
+ setItem: jest.fn()
+ },
+ user: null,
+ IS_EXTENSION: false
+};
+
+global.location = global.window.location;
+
+// Mock the database functions
+global.db = {
+ local: {
+ get: jest.fn(),
+ set: jest.fn()
+ },
+ getSettings: jest.fn(),
+ getUserLastSeenVersion: jest.fn(),
+ setUserLastSeenVersion: jest.fn()
+};
+
+// Mock other global functions
+global.log = jest.fn();
+global.trackEvent = jest.fn();
+global.alertsService = {
+ add: jest.fn()
+};
+
+describe('Layout Parameter Tests', () => {
+ beforeEach(() => {
+ // Reset all mocks before each test
+ jest.clearAllMocks();
+
+ // Reset global variables
+ global.window.forcedSettings = {};
+ global.window.codeHtml = '';
+ global.window.codeCss = '';
+ global.window.codeLayout = null;
+ });
+
+ test('should parse layout parameter from URL correctly', () => {
+ // Set up URL with layout parameter
+ global.window.location.search = '?layout=3&html=
test
';
+
+ // Simulate the URL parsing logic from app.jsx
+ if (global.window.location.search) {
+ const params = new URLSearchParams(global.window.location.search);
+ global.window.codeHtml = params.get('html') || '';
+ global.window.codeCss = params.get('css') || '';
+ global.window.codeLayout = params.get('layout')
+ ? parseInt(params.get('layout'), 10)
+ : null;
+ }
+
+ expect(global.window.codeLayout).toBe(3);
+ expect(global.window.codeHtml).toBe('test
');
+ });
+
+ test('should handle invalid layout parameter gracefully', () => {
+ // Set up URL with invalid layout parameter
+ global.window.location.search = '?layout=invalid&html=test
';
+
+ // Simulate the URL parsing logic
+ if (global.window.location.search) {
+ const params = new URLSearchParams(global.window.location.search);
+ global.window.codeLayout = params.get('layout')
+ ? parseInt(params.get('layout'), 10)
+ : null;
+ }
+
+ expect(global.window.codeLayout).toBe(NaN);
+ });
+
+ test('should handle layout parameter out of range', () => {
+ // Test layout values outside the valid range (1-5)
+ const testCases = [0, 6, 10, -1];
+
+ testCases.forEach(layoutValue => {
+ global.window.location.search = `?layout=${layoutValue}`;
+
+ if (global.window.location.search) {
+ const params = new URLSearchParams(global.window.location.search);
+ global.window.codeLayout = params.get('layout')
+ ? parseInt(params.get('layout'), 10)
+ : null;
+ }
+
+ // The layout should be parsed but may be outside valid range
+ expect(global.window.codeLayout).toBe(layoutValue);
+ });
+ });
+
+ test('should handle multiple query parameters correctly', () => {
+ // Set up URL with multiple parameters
+ global.window.location.search =
+ '?layout=2&html=test
&css=body{color:red}&settings=autoPreview:true';
+
+ // Simulate the URL parsing logic
+ if (global.window.location.search) {
+ let match = global.window.location.search
+ .replace(/^\?/, '')
+ .match(/settings=([^=]*)/);
+ if (match) {
+ match = match[1];
+ match.split(',').map(pair => {
+ pair = pair.split(':');
+ if (pair[1] === 'true') pair[1] = true;
+ else if (pair[1] === 'false') pair[1] = false;
+ global.window.forcedSettings[pair[0]] = pair[1];
+ });
+ }
+
+ const params = new URLSearchParams(global.window.location.search);
+ global.window.codeHtml = params.get('html') || '';
+ global.window.codeCss = params.get('css') || '';
+ global.window.codeLayout = params.get('layout')
+ ? parseInt(params.get('layout'), 10)
+ : null;
+ }
+
+ expect(global.window.codeLayout).toBe(2);
+ expect(global.window.codeHtml).toBe('test
');
+ expect(global.window.codeCss).toBe('body{color:red}');
+ expect(global.window.forcedSettings.autoPreview).toBe(true);
+ });
+
+ test('should handle empty search string', () => {
+ // Set up URL with no parameters
+ global.window.location.search = '';
+
+ // Simulate the URL parsing logic
+ if (global.window.location.search) {
+ const params = new URLSearchParams(global.window.location.search);
+ global.window.codeLayout = params.get('layout')
+ ? parseInt(params.get('layout'), 10)
+ : null;
+ }
+
+ expect(global.window.codeLayout).toBe(null);
+ });
+});