feat: implement flexible editor gate system
- Replace automatic auth controls with developer-placed .insertr-gate elements - Add OAuth-ready authentication flow with mock implementation - Support any HTML element as gate with custom styling - Implement proper gate restoration after authentication - Move auth controls to bottom-right corner for better UX - Add editor gates to demo pages (footer link and styled button) - Maintain gates visible by default with hideGatesAfterAuth option - Prevent duplicate authentication attempts with loading states This enables small business owners to access editor via discrete footer links or custom-styled elements placed anywhere by developers.
This commit is contained in:
@@ -100,7 +100,7 @@
|
|||||||
<footer class="footer">
|
<footer class="footer">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<p class="insertr">© 2024 Acme Consulting Services. All rights reserved.</p>
|
<p class="insertr">© 2024 Acme Consulting Services. All rights reserved.</p>
|
||||||
<p class="insertr">📧 info@acmeconsulting.com | 📞 (555) 123-4567</p>
|
<p class="insertr">📧 info@acmeconsulting.com | 📞 (555) 123-4567 | <button class="insertr-gate" style="background: none; border: 1px solid #ccc; padding: 4px 8px; margin-left: 10px; border-radius: 3px; font-size: 11px;">🔧 Edit</button></p>
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
|
|||||||
@@ -76,7 +76,7 @@
|
|||||||
<footer class="footer">
|
<footer class="footer">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<p class="insertr">© 2024 Acme Consulting Services. All rights reserved.</p>
|
<p class="insertr">© 2024 Acme Consulting Services. All rights reserved.</p>
|
||||||
<p class="insertr">📧 info@acmeconsulting.com | 📞 (555) 123-4567</p>
|
<p class="insertr">📧 info@acmeconsulting.com | 📞 (555) 123-4567 | <a href="#" class="insertr-gate">Editor</a></p>
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
|
|||||||
@@ -639,7 +639,7 @@ var Insertr = (function () {
|
|||||||
constructor(options = {}) {
|
constructor(options = {}) {
|
||||||
this.options = {
|
this.options = {
|
||||||
mockAuth: options.mockAuth !== false, // Enable mock auth by default
|
mockAuth: options.mockAuth !== false, // Enable mock auth by default
|
||||||
autoCreateControls: options.autoCreateControls !== false,
|
hideGatesAfterAuth: options.hideGatesAfterAuth === true, // Keep gates visible by default
|
||||||
...options
|
...options
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -648,31 +648,191 @@ var Insertr = (function () {
|
|||||||
isAuthenticated: false,
|
isAuthenticated: false,
|
||||||
editMode: false,
|
editMode: false,
|
||||||
currentUser: null,
|
currentUser: null,
|
||||||
activeEditor: null
|
activeEditor: null,
|
||||||
|
isInitialized: false,
|
||||||
|
isAuthenticating: false
|
||||||
};
|
};
|
||||||
|
|
||||||
this.statusIndicator = null;
|
this.statusIndicator = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize authentication system
|
* Initialize gate system (called on page load)
|
||||||
*/
|
*/
|
||||||
init() {
|
init() {
|
||||||
console.log('🔐 Initializing Insertr Authentication');
|
console.log('🔧 Insertr: Scanning for editor gates');
|
||||||
|
|
||||||
if (this.options.autoCreateControls) {
|
this.setupEditorGates();
|
||||||
this.createAuthControls();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize full editing system (called after successful OAuth)
|
||||||
|
*/
|
||||||
|
initializeFullSystem() {
|
||||||
|
if (this.state.isInitialized) {
|
||||||
|
return; // Already initialized
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('🔐 Initializing Insertr Editing System');
|
||||||
|
|
||||||
|
this.createAuthControls();
|
||||||
this.setupAuthenticationControls();
|
this.setupAuthenticationControls();
|
||||||
this.createStatusIndicator();
|
this.createStatusIndicator();
|
||||||
this.updateBodyClasses();
|
this.updateBodyClasses();
|
||||||
|
|
||||||
console.log('📱 Auth controls ready - Look for buttons in top-right corner');
|
// Auto-enable edit mode after OAuth
|
||||||
|
this.state.editMode = true;
|
||||||
|
this.state.isInitialized = true;
|
||||||
|
|
||||||
|
// Start the editor system
|
||||||
|
if (window.Insertr && window.Insertr.startEditor) {
|
||||||
|
window.Insertr.startEditor();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.updateButtonStates();
|
||||||
|
this.updateStatusIndicator();
|
||||||
|
|
||||||
|
console.log('📱 Editing system active - Controls in bottom-right corner');
|
||||||
|
console.log('✏️ Edit mode enabled - Click elements to edit');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create authentication control buttons if they don't exist
|
* Setup editor gate click handlers for any .insertr-gate elements
|
||||||
|
*/
|
||||||
|
setupEditorGates() {
|
||||||
|
const gates = document.querySelectorAll('.insertr-gate');
|
||||||
|
|
||||||
|
if (gates.length === 0) {
|
||||||
|
console.log('ℹ️ No .insertr-gate elements found - editor access disabled');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`🚪 Found ${gates.length} editor gate(s)`);
|
||||||
|
|
||||||
|
// Add gate styles
|
||||||
|
this.addGateStyles();
|
||||||
|
|
||||||
|
gates.forEach((gate, index) => {
|
||||||
|
// Store original text for later restoration
|
||||||
|
if (!gate.hasAttribute('data-original-text')) {
|
||||||
|
gate.setAttribute('data-original-text', gate.textContent);
|
||||||
|
}
|
||||||
|
|
||||||
|
gate.addEventListener('click', (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
this.handleGateClick(gate, index);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add subtle styling to indicate it's clickable
|
||||||
|
gate.style.cursor = 'pointer';
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle click on an editor gate element
|
||||||
|
*/
|
||||||
|
async handleGateClick(gateElement, gateIndex) {
|
||||||
|
// Prevent multiple simultaneous authentication attempts
|
||||||
|
if (this.state.isAuthenticating) {
|
||||||
|
console.log('⏳ Authentication already in progress...');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`🚀 Editor gate activated (gate ${gateIndex + 1})`);
|
||||||
|
this.state.isAuthenticating = true;
|
||||||
|
|
||||||
|
// Store original text and show loading state
|
||||||
|
const originalText = gateElement.textContent;
|
||||||
|
gateElement.setAttribute('data-original-text', originalText);
|
||||||
|
gateElement.textContent = '⏳ Signing in...';
|
||||||
|
gateElement.style.pointerEvents = 'none';
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Perform OAuth authentication
|
||||||
|
await this.performOAuthFlow();
|
||||||
|
|
||||||
|
// Initialize full editing system
|
||||||
|
this.initializeFullSystem();
|
||||||
|
|
||||||
|
// Conditionally hide gates based on options
|
||||||
|
if (this.options.hideGatesAfterAuth) {
|
||||||
|
this.hideAllGates();
|
||||||
|
} else {
|
||||||
|
this.updateGateState();
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('❌ Authentication failed:', error);
|
||||||
|
|
||||||
|
// Restore clicked gate to original state
|
||||||
|
const originalText = gateElement.getAttribute('data-original-text');
|
||||||
|
if (originalText) {
|
||||||
|
gateElement.textContent = originalText;
|
||||||
|
}
|
||||||
|
gateElement.style.pointerEvents = '';
|
||||||
|
} finally {
|
||||||
|
this.state.isAuthenticating = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform OAuth authentication flow
|
||||||
|
*/
|
||||||
|
async performOAuthFlow() {
|
||||||
|
// In development, simulate OAuth flow
|
||||||
|
if (this.options.mockAuth) {
|
||||||
|
console.log('🔐 Mock OAuth: Simulating authentication...');
|
||||||
|
|
||||||
|
// Simulate network delay
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||||
|
|
||||||
|
// Set authenticated state
|
||||||
|
this.state.isAuthenticated = true;
|
||||||
|
this.state.currentUser = {
|
||||||
|
name: 'Site Owner',
|
||||||
|
email: 'owner@example.com',
|
||||||
|
role: 'admin'
|
||||||
|
};
|
||||||
|
|
||||||
|
console.log('✅ Mock OAuth: Authentication successful');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: In production, implement real OAuth flow
|
||||||
|
// This would redirect to OAuth provider, handle callback, etc.
|
||||||
|
throw new Error('Production OAuth not implemented yet');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hide all editor gates after successful authentication (optional)
|
||||||
|
*/
|
||||||
|
hideAllGates() {
|
||||||
|
document.body.classList.add('insertr-hide-gates');
|
||||||
|
console.log('🚪 Editor gates hidden (hideGatesAfterAuth enabled)');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update gate state after authentication (restore normal appearance)
|
||||||
|
*/
|
||||||
|
updateGateState() {
|
||||||
|
const gates = document.querySelectorAll('.insertr-gate');
|
||||||
|
gates.forEach(gate => {
|
||||||
|
// Restore original text if it was saved
|
||||||
|
const originalText = gate.getAttribute('data-original-text');
|
||||||
|
if (originalText) {
|
||||||
|
gate.textContent = originalText;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Restore interactive state
|
||||||
|
gate.style.pointerEvents = '';
|
||||||
|
gate.style.opacity = '';
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log('🚪 Editor gates restored to original state');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create authentication control buttons (bottom-right positioned)
|
||||||
*/
|
*/
|
||||||
createAuthControls() {
|
createAuthControls() {
|
||||||
// Check if controls already exist
|
// Check if controls already exist
|
||||||
@@ -853,6 +1013,32 @@ var Insertr = (function () {
|
|||||||
return this.state.currentUser;
|
return this.state.currentUser;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add minimal styles for editor gates
|
||||||
|
*/
|
||||||
|
addGateStyles() {
|
||||||
|
const styles = `
|
||||||
|
.insertr-gate {
|
||||||
|
transition: opacity 0.2s ease;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.insertr-gate:hover {
|
||||||
|
opacity: 0.7;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Optional: Hide gates when authenticated (only if hideGatesAfterAuth option is true) */
|
||||||
|
body.insertr-hide-gates .insertr-gate {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const styleSheet = document.createElement('style');
|
||||||
|
styleSheet.type = 'text/css';
|
||||||
|
styleSheet.innerHTML = styles;
|
||||||
|
document.head.appendChild(styleSheet);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add styles for authentication controls
|
* Add styles for authentication controls
|
||||||
*/
|
*/
|
||||||
@@ -860,11 +1046,12 @@ var Insertr = (function () {
|
|||||||
const styles = `
|
const styles = `
|
||||||
.insertr-auth-controls {
|
.insertr-auth-controls {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 20px;
|
bottom: 20px;
|
||||||
right: 20px;
|
right: 20px;
|
||||||
z-index: 9999;
|
z-index: 9999;
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 10px;
|
flex-direction: column;
|
||||||
|
gap: 8px;
|
||||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -914,6 +1101,7 @@ var Insertr = (function () {
|
|||||||
padding: 8px 12px;
|
padding: 8px 12px;
|
||||||
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
|
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
|
||||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||||
|
max-width: 200px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.insertr-status-content {
|
.insertr-status-content {
|
||||||
@@ -1034,12 +1222,17 @@ var Insertr = (function () {
|
|||||||
return this;
|
return this;
|
||||||
},
|
},
|
||||||
|
|
||||||
// Start the editor and authentication
|
// Start the system - only creates the minimal trigger
|
||||||
start() {
|
start() {
|
||||||
if (this.auth) {
|
if (this.auth) {
|
||||||
this.auth.init();
|
this.auth.init(); // Creates footer trigger only
|
||||||
}
|
}
|
||||||
if (this.editor) {
|
// Note: Editor is NOT started here, only when trigger is clicked
|
||||||
|
},
|
||||||
|
|
||||||
|
// Start the full editor system (called when trigger is activated)
|
||||||
|
startEditor() {
|
||||||
|
if (this.editor && !this.editor.isActive) {
|
||||||
this.editor.start();
|
this.editor.start();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -1071,10 +1264,20 @@ var Insertr = (function () {
|
|||||||
version: '1.0.0'
|
version: '1.0.0'
|
||||||
};
|
};
|
||||||
|
|
||||||
// Auto-initialize in development mode
|
// Auto-initialize in development mode with proper DOM ready handling
|
||||||
if (document.querySelector('[data-insertr-enhanced]')) {
|
function autoInitialize() {
|
||||||
|
if (document.querySelector('[data-insertr-enhanced="true"]')) {
|
||||||
window.Insertr.init();
|
window.Insertr.init();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run auto-initialization when DOM is ready
|
||||||
|
if (document.readyState === 'loading') {
|
||||||
|
document.addEventListener('DOMContentLoaded', autoInitialize);
|
||||||
|
} else {
|
||||||
|
// DOM is already ready
|
||||||
|
autoInitialize();
|
||||||
|
}
|
||||||
|
|
||||||
var index = window.Insertr;
|
var index = window.Insertr;
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -69,7 +69,7 @@ func (e *Enhancer) EnhanceFile(inputPath, outputPath string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Inject editor assets for development
|
// Inject editor assets for development
|
||||||
libraryScript := GetLibraryScript(true) // Use minified for better performance
|
libraryScript := GetLibraryScript(false) // Use non-minified for development debugging
|
||||||
e.injector.InjectEditorAssets(doc, true, libraryScript)
|
e.injector.InjectEditorAssets(doc, true, libraryScript)
|
||||||
|
|
||||||
// Write enhanced HTML
|
// Write enhanced HTML
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package content
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"golang.org/x/net/html"
|
"golang.org/x/net/html"
|
||||||
)
|
)
|
||||||
@@ -145,21 +146,19 @@ func (i *Injector) InjectEditorAssets(doc *html.Node, isDevelopment bool, librar
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Add inline script with embedded library
|
// Add inline script with embedded library
|
||||||
script := &html.Node{
|
// Note: Using html.TextNode for scripts can cause issues with HTML entity encoding
|
||||||
Type: html.ElementNode,
|
// Instead, we'll insert the script tag as raw HTML
|
||||||
Data: "script",
|
scriptHTML := fmt.Sprintf(`<script type="text/javascript">
|
||||||
Attr: []html.Attribute{
|
%s
|
||||||
{Key: "type", Val: "text/javascript"},
|
</script>`, libraryScript)
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add the library content as text node
|
// Parse the script HTML and append to head
|
||||||
textNode := &html.Node{
|
scriptNodes, err := html.ParseFragment(strings.NewReader(scriptHTML), head)
|
||||||
Type: html.TextNode,
|
if err == nil && len(scriptNodes) > 0 {
|
||||||
Data: libraryScript,
|
for _, node := range scriptNodes {
|
||||||
|
head.AppendChild(node)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
script.AppendChild(textNode)
|
|
||||||
head.AppendChild(script)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// findHeadElement finds the <head> element in the document
|
// findHeadElement finds the <head> element in the document
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ export class InsertrAuth {
|
|||||||
constructor(options = {}) {
|
constructor(options = {}) {
|
||||||
this.options = {
|
this.options = {
|
||||||
mockAuth: options.mockAuth !== false, // Enable mock auth by default
|
mockAuth: options.mockAuth !== false, // Enable mock auth by default
|
||||||
autoCreateControls: options.autoCreateControls !== false,
|
hideGatesAfterAuth: options.hideGatesAfterAuth === true, // Keep gates visible by default
|
||||||
...options
|
...options
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -15,31 +15,191 @@ export class InsertrAuth {
|
|||||||
isAuthenticated: false,
|
isAuthenticated: false,
|
||||||
editMode: false,
|
editMode: false,
|
||||||
currentUser: null,
|
currentUser: null,
|
||||||
activeEditor: null
|
activeEditor: null,
|
||||||
|
isInitialized: false,
|
||||||
|
isAuthenticating: false
|
||||||
};
|
};
|
||||||
|
|
||||||
this.statusIndicator = null;
|
this.statusIndicator = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize authentication system
|
* Initialize gate system (called on page load)
|
||||||
*/
|
*/
|
||||||
init() {
|
init() {
|
||||||
console.log('🔐 Initializing Insertr Authentication');
|
console.log('🔧 Insertr: Scanning for editor gates');
|
||||||
|
|
||||||
if (this.options.autoCreateControls) {
|
this.setupEditorGates();
|
||||||
this.createAuthControls();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize full editing system (called after successful OAuth)
|
||||||
|
*/
|
||||||
|
initializeFullSystem() {
|
||||||
|
if (this.state.isInitialized) {
|
||||||
|
return; // Already initialized
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('🔐 Initializing Insertr Editing System');
|
||||||
|
|
||||||
|
this.createAuthControls();
|
||||||
this.setupAuthenticationControls();
|
this.setupAuthenticationControls();
|
||||||
this.createStatusIndicator();
|
this.createStatusIndicator();
|
||||||
this.updateBodyClasses();
|
this.updateBodyClasses();
|
||||||
|
|
||||||
console.log('📱 Auth controls ready - Look for buttons in top-right corner');
|
// Auto-enable edit mode after OAuth
|
||||||
|
this.state.editMode = true;
|
||||||
|
this.state.isInitialized = true;
|
||||||
|
|
||||||
|
// Start the editor system
|
||||||
|
if (window.Insertr && window.Insertr.startEditor) {
|
||||||
|
window.Insertr.startEditor();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.updateButtonStates();
|
||||||
|
this.updateStatusIndicator();
|
||||||
|
|
||||||
|
console.log('📱 Editing system active - Controls in bottom-right corner');
|
||||||
|
console.log('✏️ Edit mode enabled - Click elements to edit');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create authentication control buttons if they don't exist
|
* Setup editor gate click handlers for any .insertr-gate elements
|
||||||
|
*/
|
||||||
|
setupEditorGates() {
|
||||||
|
const gates = document.querySelectorAll('.insertr-gate');
|
||||||
|
|
||||||
|
if (gates.length === 0) {
|
||||||
|
console.log('ℹ️ No .insertr-gate elements found - editor access disabled');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`🚪 Found ${gates.length} editor gate(s)`);
|
||||||
|
|
||||||
|
// Add gate styles
|
||||||
|
this.addGateStyles();
|
||||||
|
|
||||||
|
gates.forEach((gate, index) => {
|
||||||
|
// Store original text for later restoration
|
||||||
|
if (!gate.hasAttribute('data-original-text')) {
|
||||||
|
gate.setAttribute('data-original-text', gate.textContent);
|
||||||
|
}
|
||||||
|
|
||||||
|
gate.addEventListener('click', (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
this.handleGateClick(gate, index);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add subtle styling to indicate it's clickable
|
||||||
|
gate.style.cursor = 'pointer';
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle click on an editor gate element
|
||||||
|
*/
|
||||||
|
async handleGateClick(gateElement, gateIndex) {
|
||||||
|
// Prevent multiple simultaneous authentication attempts
|
||||||
|
if (this.state.isAuthenticating) {
|
||||||
|
console.log('⏳ Authentication already in progress...');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`🚀 Editor gate activated (gate ${gateIndex + 1})`);
|
||||||
|
this.state.isAuthenticating = true;
|
||||||
|
|
||||||
|
// Store original text and show loading state
|
||||||
|
const originalText = gateElement.textContent;
|
||||||
|
gateElement.setAttribute('data-original-text', originalText);
|
||||||
|
gateElement.textContent = '⏳ Signing in...';
|
||||||
|
gateElement.style.pointerEvents = 'none';
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Perform OAuth authentication
|
||||||
|
await this.performOAuthFlow();
|
||||||
|
|
||||||
|
// Initialize full editing system
|
||||||
|
this.initializeFullSystem();
|
||||||
|
|
||||||
|
// Conditionally hide gates based on options
|
||||||
|
if (this.options.hideGatesAfterAuth) {
|
||||||
|
this.hideAllGates();
|
||||||
|
} else {
|
||||||
|
this.updateGateState();
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('❌ Authentication failed:', error);
|
||||||
|
|
||||||
|
// Restore clicked gate to original state
|
||||||
|
const originalText = gateElement.getAttribute('data-original-text');
|
||||||
|
if (originalText) {
|
||||||
|
gateElement.textContent = originalText;
|
||||||
|
}
|
||||||
|
gateElement.style.pointerEvents = '';
|
||||||
|
} finally {
|
||||||
|
this.state.isAuthenticating = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform OAuth authentication flow
|
||||||
|
*/
|
||||||
|
async performOAuthFlow() {
|
||||||
|
// In development, simulate OAuth flow
|
||||||
|
if (this.options.mockAuth) {
|
||||||
|
console.log('🔐 Mock OAuth: Simulating authentication...');
|
||||||
|
|
||||||
|
// Simulate network delay
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||||
|
|
||||||
|
// Set authenticated state
|
||||||
|
this.state.isAuthenticated = true;
|
||||||
|
this.state.currentUser = {
|
||||||
|
name: 'Site Owner',
|
||||||
|
email: 'owner@example.com',
|
||||||
|
role: 'admin'
|
||||||
|
};
|
||||||
|
|
||||||
|
console.log('✅ Mock OAuth: Authentication successful');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: In production, implement real OAuth flow
|
||||||
|
// This would redirect to OAuth provider, handle callback, etc.
|
||||||
|
throw new Error('Production OAuth not implemented yet');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hide all editor gates after successful authentication (optional)
|
||||||
|
*/
|
||||||
|
hideAllGates() {
|
||||||
|
document.body.classList.add('insertr-hide-gates');
|
||||||
|
console.log('🚪 Editor gates hidden (hideGatesAfterAuth enabled)');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update gate state after authentication (restore normal appearance)
|
||||||
|
*/
|
||||||
|
updateGateState() {
|
||||||
|
const gates = document.querySelectorAll('.insertr-gate');
|
||||||
|
gates.forEach(gate => {
|
||||||
|
// Restore original text if it was saved
|
||||||
|
const originalText = gate.getAttribute('data-original-text');
|
||||||
|
if (originalText) {
|
||||||
|
gate.textContent = originalText;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Restore interactive state
|
||||||
|
gate.style.pointerEvents = '';
|
||||||
|
gate.style.opacity = '';
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log('🚪 Editor gates restored to original state');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create authentication control buttons (bottom-right positioned)
|
||||||
*/
|
*/
|
||||||
createAuthControls() {
|
createAuthControls() {
|
||||||
// Check if controls already exist
|
// Check if controls already exist
|
||||||
@@ -220,6 +380,32 @@ export class InsertrAuth {
|
|||||||
return this.state.currentUser;
|
return this.state.currentUser;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add minimal styles for editor gates
|
||||||
|
*/
|
||||||
|
addGateStyles() {
|
||||||
|
const styles = `
|
||||||
|
.insertr-gate {
|
||||||
|
transition: opacity 0.2s ease;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.insertr-gate:hover {
|
||||||
|
opacity: 0.7;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Optional: Hide gates when authenticated (only if hideGatesAfterAuth option is true) */
|
||||||
|
body.insertr-hide-gates .insertr-gate {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const styleSheet = document.createElement('style');
|
||||||
|
styleSheet.type = 'text/css';
|
||||||
|
styleSheet.innerHTML = styles;
|
||||||
|
document.head.appendChild(styleSheet);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add styles for authentication controls
|
* Add styles for authentication controls
|
||||||
*/
|
*/
|
||||||
@@ -227,11 +413,12 @@ export class InsertrAuth {
|
|||||||
const styles = `
|
const styles = `
|
||||||
.insertr-auth-controls {
|
.insertr-auth-controls {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 20px;
|
bottom: 20px;
|
||||||
right: 20px;
|
right: 20px;
|
||||||
z-index: 9999;
|
z-index: 9999;
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 10px;
|
flex-direction: column;
|
||||||
|
gap: 8px;
|
||||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -281,6 +468,7 @@ export class InsertrAuth {
|
|||||||
padding: 8px 12px;
|
padding: 8px 12px;
|
||||||
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
|
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
|
||||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||||
|
max-width: 200px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.insertr-status-content {
|
.insertr-status-content {
|
||||||
|
|||||||
@@ -33,12 +33,17 @@ window.Insertr = {
|
|||||||
return this;
|
return this;
|
||||||
},
|
},
|
||||||
|
|
||||||
// Start the editor and authentication
|
// Start the system - only creates the minimal trigger
|
||||||
start() {
|
start() {
|
||||||
if (this.auth) {
|
if (this.auth) {
|
||||||
this.auth.init();
|
this.auth.init(); // Creates footer trigger only
|
||||||
}
|
}
|
||||||
if (this.editor) {
|
// Note: Editor is NOT started here, only when trigger is clicked
|
||||||
|
},
|
||||||
|
|
||||||
|
// Start the full editor system (called when trigger is activated)
|
||||||
|
startEditor() {
|
||||||
|
if (this.editor && !this.editor.isActive) {
|
||||||
this.editor.start();
|
this.editor.start();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -70,9 +75,19 @@ window.Insertr = {
|
|||||||
version: '1.0.0'
|
version: '1.0.0'
|
||||||
};
|
};
|
||||||
|
|
||||||
// Auto-initialize in development mode
|
// Auto-initialize in development mode with proper DOM ready handling
|
||||||
if (document.querySelector('[data-insertr-enhanced]')) {
|
function autoInitialize() {
|
||||||
|
if (document.querySelector('[data-insertr-enhanced="true"]')) {
|
||||||
window.Insertr.init();
|
window.Insertr.init();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run auto-initialization when DOM is ready
|
||||||
|
if (document.readyState === 'loading') {
|
||||||
|
document.addEventListener('DOMContentLoaded', autoInitialize);
|
||||||
|
} else {
|
||||||
|
// DOM is already ready
|
||||||
|
autoInitialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
export default window.Insertr;
|
export default window.Insertr;
|
||||||
Reference in New Issue
Block a user