<!DOCTYPE html>
<html lang="en" ng-app="htmlEditorApp">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>AngularJS HTML Editor</title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.8.2/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.8.2/angular-sanitize.min.js"></script>
<script type="module" src="https://unpkg.com/ionicons@7.1.0/dist/ionicons/ionicons.esm.js"></script>
<script nomodule src="https://unpkg.com/ionicons@7.1.0/dist/ionicons/ionicons.js"></script>
</head>
<body ng-controller="HtmlEditorController">
<div class="container">
<div class="header">
<h1>HTML Editor</h1>
<p>Live HTML editor with real-time preview built with AngularJS</p>
</div>
<div class="editor-layout">
<!-- Toolbar -->
<div class="toolbar">
<h2>
<ion-icon name="construct-outline"></ion-icon>
Tools
</h2>
<div class="tool-section">
<h3>Quick Insert</h3>
<button class="tool-btn" ng-click="insertTag('heading')">
<ion-icon name="text-outline"></ion-icon>
Heading
</button>
<button class="tool-btn" ng-click="insertTag('paragraph')">
<ion-icon name="document-text-outline"></ion-icon>
Paragraph
</button>
<button class="tool-btn" ng-click="insertTag('link')">
<ion-icon name="link-outline"></ion-icon>
Link
</button>
<button class="tool-btn" ng-click="insertTag('image')">
<ion-icon name="image-outline"></ion-icon>
Image
</button>
<button class="tool-btn" ng-click="insertTag('button')">
<ion-icon name="square-outline"></ion-icon>
Button
</button>
<button class="tool-btn" ng-click="insertTag('list')">
<ion-icon name="list-outline"></ion-icon>
List
</button>
<button class="tool-btn" ng-click="insertTag('table')">
<ion-icon name="grid-outline"></ion-icon>
Table
</button>
<button class="tool-btn" ng-click="insertTag('div')">
<ion-icon name="apps-outline"></ion-icon>
Div
</button>
</div>
<div class="tool-section">
<h3>Templates</h3>
<div class="select-group">
<select ng-model="selectedTemplate" ng-change="loadTemplate()">
<option value="">-- Select Template --</option>
<option value="blank">Blank Page</option>
<option value="basic">Basic Page</option>
<option value="card">Card Layout</option>
<option value="form">Contact Form</option>
<option value="landing">Landing Page</option>
</select>
</div>
</div>
<div class="tool-section">
<h3>Actions</h3>
<button class="tool-btn" ng-click="formatCode()">
<ion-icon name="code-working-outline"></ion-icon>
Format Code
</button>
<button class="tool-btn" ng-click="clearEditor()">
<ion-icon name="trash-outline"></ion-icon>
Clear All
</button>
<button class="tool-btn" ng-click="downloadHTML()">
<ion-icon name="download-outline"></ion-icon>
Download HTML
</button>
</div>
</div>
<!-- Main Editor -->
<div class="editor-main">
<div class="editor-tabs">
<button class="tab-btn" ng-class="{active: viewMode === 'split'}" ng-click="viewMode = 'split'">
<ion-icon name="grid-outline"></ion-icon>
Split View
</button>
<button class="tab-btn" ng-class="{active: viewMode === 'code'}" ng-click="viewMode = 'code'">
<ion-icon name="code-outline"></ion-icon>
Code Only
</button>
<button class="tab-btn" ng-class="{active: viewMode === 'preview'}" ng-click="viewMode = 'preview'">
<ion-icon name="eye-outline"></ion-icon>
Preview Only
</button>
</div>
<div class="editor-content">
<div class="editor-actions">
<button class="btn btn-primary" ng-click="updatePreview()">
<ion-icon name="refresh-outline"></ion-icon>
Update Preview
</button>
<button class="btn btn-secondary" ng-click="copyCode()">
<ion-icon name="copy-outline"></ion-icon>
Copy Code
</button>
</div>
<div class="editor-area" ng-class="{'single-view': viewMode !== 'split'}">
<div class="code-editor" ng-show="viewMode === 'split' || viewMode === 'code'">
<textarea class="code-textarea"
ng-model="htmlCode"
placeholder="Enter your HTML code here..."
id="codeTextarea"></textarea>
</div>
<div class="preview-area" ng-show="viewMode === 'split' || viewMode === 'preview'">
<div class="preview-content" ng-bind-html="previewContent"></div>
</div>
</div>
<div class="stats-bar">
<div class="stat-item">
<span>Lines:</span>
<span class="stat-value">{{stats.lines}}</span>
</div>
<div class="stat-item">
<span>Characters:</span>
<span class="stat-value">{{stats.characters}}</span>
</div>
<div class="stat-item">
<span>Words:</span>
<span class="stat-value">{{stats.words}}</span>
</div>
<div class="stat-item">
<span>Last Updated:</span>
<span class="stat-value">{{stats.lastUpdated}}</span>
</div>
</div>
</div>
</div>
</div>
</div>
<script>
angular.module('htmlEditorApp', ['ngSanitize'])
.controller('HtmlEditorController', function($scope, $sce, $timeout) {
$scope.htmlCode = '<h1>Welcome to HTML Editor</h1>\n<p>Start editing your HTML code here!</p>';
$scope.previewContent = $sce.trustAsHtml($scope.htmlCode);
$scope.viewMode = 'split';
$scope.selectedTemplate = '';
$scope.stats = {
lines: 0,
characters: 0,
words: 0,
lastUpdated: 'Never'
};
$scope.templates = {
blank: '',
basic: '<!DOCTYPE html>\n<html>\n<head>\n <title>My Page</title>\n</head>\n<body>\n <h1>Hello World</h1>\n <p>This is a basic HTML page.</p>\n</body>\n</html>',
card: '<div style="max-width: 400px; margin: 20px auto; padding: 20px; border: 1px solid #ddd; border-radius: 8px; box-shadow: 0 2px 8px rgba(0,0,0,0.1);">\n <h2 style="margin-top: 0;">Card Title</h2>\n <p>This is a card component with some content inside.</p>\n <button style="padding: 10px 20px; background: #0d1b2a; color: white; border: none; border-radius: 5px; cursor: pointer;">Click Me</button>\n</div>',
form: '<form style="max-width: 500px; margin: 20px auto; padding: 20px; border: 1px solid #ddd; border-radius: 8px;">\n <h2>Contact Form</h2>\n <div style="margin-bottom: 15px;">\n <label style="display: block; margin-bottom: 5px;">Name:</label>\n <input type="text" style="width: 100%; padding: 8px; border: 1px solid #ddd; border-radius: 4px;">\n </div>\n <div style="margin-bottom: 15px;">\n <label style="display: block; margin-bottom: 5px;">Email:</label>\n <input type="email" style="width: 100%; padding: 8px; border: 1px solid #ddd; border-radius: 4px;">\n </div>\n <div style="margin-bottom: 15px;">\n <label style="display: block; margin-bottom: 5px;">Message:</label>\n <textarea style="width: 100%; padding: 8px; border: 1px solid #ddd; border-radius: 4px;" rows="4"></textarea>\n </div>\n <button type="submit" style="padding: 10px 20px; background: #0d1b2a; color: white; border: none; border-radius: 5px; cursor: pointer;">Submit</button>\n</form>',
landing: '<div style="text-align: center; padding: 50px 20px; background: linear-gradient(135deg, #0d1b2a 0%, #1b263b 100%); color: white;">\n <h1 style="font-size: 48px; margin-bottom: 20px;">Welcome to Our Site</h1>\n <p style="font-size: 20px; margin-bottom: 30px;">Build amazing things with our platform</p>\n <button style="padding: 15px 40px; background: white; color: #0d1b2a; border: none; border-radius: 8px; font-size: 18px; font-weight: bold; cursor: pointer;">Get Started</button>\n</div>\n<div style="max-width: 800px; margin: 40px auto; padding: 0 20px;">\n <h2 style="text-align: center; margin-bottom: 30px;">Features</h2>\n <div style="display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px;">\n <div style="padding: 20px; border: 1px solid #ddd; border-radius: 8px; text-align: center;">\n <h3>Feature 1</h3>\n <p>Description of feature 1</p>\n </div>\n <div style="padding: 20px; border: 1px solid #ddd; border-radius: 8px; text-align: center;">\n <h3>Feature 2</h3>\n <p>Description of feature 2</p>\n </div>\n <div style="padding: 20px; border: 1px solid #ddd; border-radius: 8px; text-align: center;">\n <h3>Feature 3</h3>\n <p>Description of feature 3</p>\n </div>\n </div>\n</div>'
};
$scope.tagTemplates = {
heading: '<h1>Your Heading Here</h1>',
paragraph: '<p>Your paragraph text here.</p>',
link: '<a href="https://example.com">Link Text</a>',
image: '<img src="https://via.placeholder.com/300x200" alt="Description">',
button: '<button>Click Me</button>',
list: '<ul>\n <li>Item 1</li>\n <li>Item 2</li>\n <li>Item 3</li>\n</ul>',
table: '<table border="1">\n <tr>\n <th>Header 1</th>\n <th>Header 2</th>\n </tr>\n <tr>\n <td>Data 1</td>\n <td>Data 2</td>\n </tr>\n</table>',
div: '<div>\n <p>Content inside div</p>\n</div>'
};
$scope.updateStats = function() {
$scope.stats.lines = ($scope.htmlCode.match(/\n/g) || []).length + 1;
$scope.stats.characters = $scope.htmlCode.length;
$scope.stats.words = $scope.htmlCode.trim().split(/\s+/).filter(Boolean).length;
$scope.stats.lastUpdated = new Date().toLocaleTimeString();
};
$scope.updatePreview = function() {
$scope.previewContent = $sce.trustAsHtml($scope.htmlCode);
$scope.updateStats();
};
$scope.insertTag = function(tagType) {
var template = $scope.tagTemplates[tagType];
var textarea = document.getElementById('codeTextarea');
var start = textarea.selectionStart;
var end = textarea.selectionEnd;
$scope.htmlCode = $scope.htmlCode.substring(0, start) +
'\n' + template + '\n' +
$scope.htmlCode.substring(end);
$timeout(function() {
textarea.focus();
textarea.setSelectionRange(start + template.length + 2, start + template.length + 2);
});
};
$scope.loadTemplate = function() {
if ($scope.selectedTemplate && $scope.templates[$scope.selectedTemplate] !== undefined) {
$scope.htmlCode = $scope.templates[$scope.selectedTemplate];
$scope.updatePreview();
}
};
$scope.formatCode = function() {
// Basic code formatting
var formatted = $scope.htmlCode
.replace(/>\s*</g, '>\n<')
.replace(/\n\s*\n/g, '\n');
$scope.htmlCode = formatted;
$scope.updatePreview();
};
$scope.clearEditor = function() {
if (confirm('Are you sure you want to clear all content?')) {
$scope.htmlCode = '';
$scope.updatePreview();
}
};
$scope.copyCode = function() {
var textarea = document.getElementById('codeTextarea');
textarea.select();
document.execCommand('copy');
alert('Code copied to clipboard!');
};
$scope.downloadHTML = function() {
var blob = new Blob([$scope.htmlCode], { type: 'text/html' });
var link = document.createElement('a');
link.href = URL.createObjectURL(blob);
link.download = 'index.html';
link.click();
};
// Initialize
$scope.updatePreview();
// Auto-update preview on typing (debounced)
var typingTimer;
$scope.$watch('htmlCode', function() {
clearTimeout(typingTimer);
typingTimer = setTimeout(function() {
$scope.$apply(function() {
$scope.updatePreview();
});
}, 1000);
});
});
</script>
</body>
</html>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
background: linear-gradient(135deg, #0d1b2a 0%, #1b263b 100%);
min-height: 100vh;
padding: 20px;
}
.container {
max-width: 1600px;
margin: 0 auto;
}
.header {
text-align: center;
color: white;
margin-bottom: 30px;
}
.header h1 {
font-size: 36px;
margin-bottom: 10px;
font-weight: 600;
}
.header p {
font-size: 16px;
opacity: 0.9;
}
.editor-layout {
display: grid;
grid-template-columns: 250px 1fr;
gap: 20px;
}
.toolbar {
background: white;
border-radius: 16px;
padding: 20px;
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.3);
height: fit-content;
position: sticky;
top: 20px;
}
.toolbar h2 {
font-size: 18px;
color: #0d1b2a;
margin-bottom: 15px;
display: flex;
align-items: center;
gap: 8px;
}
.tool-section {
margin-bottom: 20px;
padding-bottom: 20px;
border-bottom: 1px solid #e0e0e0;
}
.tool-section:last-child {
border-bottom: none;
margin-bottom: 0;
padding-bottom: 0;
}
.tool-section h3 {
font-size: 13px;
color: #666;
margin-bottom: 10px;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.tool-btn {
width: 100%;
padding: 10px;
border: 2px solid #e0e0e0;
border-radius: 8px;
background: white;
cursor: pointer;
transition: all 0.3s ease;
display: flex;
align-items: center;
gap: 8px;
font-size: 13px;
color: #333;
margin-bottom: 8px;
}
.tool-btn ion-icon {
font-size: 18px;
color: #0d1b2a;
}
.tool-btn:hover {
border-color: #0d1b2a;
background: #f8f9fa;
}
.select-group {
margin-bottom: 10px;
}
.select-group select {
width: 100%;
padding: 8px;
border: 2px solid #e0e0e0;
border-radius: 8px;
font-size: 13px;
}
.select-group select:focus {
outline: none;
border-color: #0d1b2a;
}
.editor-main {
display: grid;
grid-template-rows: auto 1fr;
gap: 20px;
}
.editor-tabs {
background: white;
border-radius: 16px;
padding: 15px 20px;
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.3);
display: flex;
gap: 10px;
flex-wrap: wrap;
}
.tab-btn {
padding: 10px 20px;
border: 2px solid #e0e0e0;
border-radius: 8px;
background: white;
cursor: pointer;
transition: all 0.3s ease;
display: flex;
align-items: center;
gap: 8px;
font-size: 14px;
font-weight: 600;
color: #666;
}
.tab-btn.active {
border-color: #0d1b2a;
background: #0d1b2a;
color: white;
}
.tab-btn ion-icon {
font-size: 18px;
}
.editor-content {
background: white;
border-radius: 16px;
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.3);
overflow: hidden;
display: grid;
grid-template-rows: auto 1fr;
}
.editor-actions {
padding: 15px 20px;
border-bottom: 2px solid #e0e0e0;
display: flex;
gap: 10px;
flex-wrap: wrap;
}
.btn {
padding: 8px 16px;
border: none;
border-radius: 8px;
font-size: 13px;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
display: inline-flex;
align-items: center;
gap: 6px;
}
.btn-primary {
background: #0d1b2a;
color: white;
}
.btn-primary:hover {
background: #1b263b;
}
.btn-secondary {
background: #e0e0e0;
color: #333;
}
.btn-secondary:hover {
background: #d0d0d0;
}
.editor-area {
display: grid;
grid-template-columns: 1fr 1fr;
height: 600px;
}
.code-editor {
padding: 20px;
overflow: auto;
border-right: 2px solid #e0e0e0;
}
.code-textarea {
width: 100%;
height: 100%;
border: none;
outline: none;
font-family: 'Courier New', monospace;
font-size: 14px;
line-height: 1.6;
resize: none;
color: #333;
}
.preview-area {
padding: 20px;
overflow: auto;
background: #f8f9fa;
}
.preview-content {
background: white;
padding: 20px;
border-radius: 8px;
min-height: 100%;
}
.single-view {
grid-template-columns: 1fr;
}
.single-view .code-editor {
border-right: none;
}
.stats-bar {
padding: 15px 20px;
background: #f8f9fa;
border-top: 2px solid #e0e0e0;
display: flex;
justify-content: space-between;
align-items: center;
font-size: 12px;
color: #666;
flex-wrap: wrap;
gap: 15px;
}
.stat-item {
display: flex;
align-items: center;
gap: 5px;
}
.stat-value {
font-weight: 700;
color: #0d1b2a;
}
@media (max-width: 1200px) {
.editor-layout {
grid-template-columns: 1fr;
}
.toolbar {
position: static;
}
}
@media (max-width: 768px) {
body {
padding: 10px;
}
.header h1 {
font-size: 28px;
}
.editor-area {
grid-template-columns: 1fr;
height: auto;
}
.code-editor,
.preview-area {
min-height: 400px;
}
.code-editor {
border-right: none;
border-bottom: 2px solid #e0e0e0;
}
.stats-bar {
flex-direction: column;
align-items: flex-start;
}
}
</style>
console.log('Editor loaded!');
let clickCount = 0;
function handleClick() {
clickCount++;
const output = document.getElementById('output');
output.innerHTML = `
<h3>Clicked ${clickCount} time(s)!</h3>
<p>Time: ${new Date().toLocaleTimeString()}</p>
`;
console.log(`Button clicked ${clickCount} times`);
}
No comments yet. Be the first!