mirror of
https://github.com/neocities/neocities.git
synced 2025-04-24 17:22:35 +02:00
354 lines
13 KiB
Text
354 lines
13 KiB
Text
<style>
|
|
html {
|
|
overflow-y: hidden;
|
|
}
|
|
#editor {
|
|
position: absolute;
|
|
top: 0;
|
|
right: 0;
|
|
bottom: 0;
|
|
left: 0;
|
|
}
|
|
.theme-Code{
|
|
float:right;
|
|
position:relative;
|
|
top:-50px;
|
|
}
|
|
.page {
|
|
background: #1D1F21;
|
|
position: fixed;
|
|
height: 100%;
|
|
}
|
|
.footer-Base {
|
|
display: none;
|
|
}
|
|
|
|
.monaco-editor .suggest-widget .monaco-list .monaco-list-row .monaco-highlighted-label span {
|
|
background-color: transparent !important;
|
|
line-height: normal;
|
|
vertical-align: middle;
|
|
padding: 0;
|
|
margin-bottom: 1px;
|
|
}
|
|
</style>
|
|
|
|
<div class="header-Outro editor">
|
|
<div class="row content">
|
|
<div class="breadcrumbs">
|
|
<a href="/dashboard"><strong>Dashboard</strong></a> >
|
|
<span class="filename">
|
|
<% dir_array = Pathname(@filename).dirname.to_s.split '/' %>
|
|
<% dir_array = [] if dir_array == ['.'] %>
|
|
<% dir_array.each_with_index do |dir,i| %><a href="/dashboard?dir=<%= Rack::Utils.escape dir_array[0..i].join('/') %>"><%= dir %></a> / <% end %><%= Pathname(@filename).basename %>
|
|
</span>
|
|
</div>
|
|
<div class="tools">
|
|
<div class="theme">
|
|
Theme:
|
|
<select id="theme" size="1" onchange="setTheme();" onkeyup="setTheme();">
|
|
<optgroup label="Dark">
|
|
<option value="allhallowseve">All Hallows Eve</option>
|
|
<option value="amy">Amy</option>
|
|
<option value="birdsofparadise">Birds of Paradise</option>
|
|
<option value="blackboard">Blackboard</option>
|
|
<option value="brillianceblack">Brilliance Black</option>
|
|
<option value="brilliancedull">Brilliance Dull</option>
|
|
<option value="cloudsmidnight">Clouds Midnight</option>
|
|
<option value="cobalt">Cobalt</option>
|
|
<option value="cobalt2">Cobalt2</option>
|
|
<option value="dominionday">Dominion Day</option>
|
|
<option value="dracula">Dracula</option>
|
|
<option value="espressolibre">Espresso Libre</option>
|
|
<option value="githubdark">GitHub Dark</option>
|
|
<option value="hc-black">High Contrast Dark</option>
|
|
<option value="idlefingers">idleFingers</option>
|
|
<option value="krtheme">krTheme</option>
|
|
<option value="merbivore">Merbivore</option>
|
|
<option value="monoindustrial">monoindustrial</option>
|
|
<option value="monokai">Monokai</option>
|
|
<option value="nightowl">Night Owl</option>
|
|
<option value="nord">Nord</option>
|
|
<option value="oceanicnext">Oceanic Next</option>
|
|
<option value="pastelsondark">Pastels on Dark</option>
|
|
<option value="solarized-dark">Solarized-dark</option>
|
|
<option value="spacecadet">SpaceCadet</option>
|
|
<option value="sunburst">Sunburst</option>
|
|
<option value="tomorrow-night">Tomorrow-Night</option>
|
|
<option value="tomorrow-night-blue">Tomorrow-Night-Blue</option>
|
|
<option value="tomorrow-night-bright">Tomorrow-Night-Bright</option>
|
|
<option value="tomorrow-night-eighties">Tomorrow-Night-Eighties</option>
|
|
<option value="twilight">Twilight</option>
|
|
<option value="vibrantink">Vibrant Ink</option>
|
|
<option value="zenburnesque">Zenburnesque</option>
|
|
<option value="vs-dark">VS Dark</option>
|
|
</optgroup>
|
|
<optgroup label="Bright">
|
|
<option value="github">GitHub</option>
|
|
<option value="githublight">GitHub Light</option>
|
|
<option value="hc-light">High Contrast Light</option>
|
|
<option value="iplastic">iPlastic</option>
|
|
<option value="katzenmilch">Katzenmilch</option>
|
|
<option value="lazy">LAZY</option>
|
|
<option value="magicwbamiga">MagicWB (Amiga)</option>
|
|
<option value="solarized-light">Solarized-light</option>
|
|
<option value="tomorrow">Tomorrow</option>
|
|
<option value="vs-light">VS Light</option>
|
|
<option value="xcodedefault">Xcode_default</option>
|
|
</optgroup>
|
|
</select>
|
|
</div>
|
|
<a id="saveButton" class="btn-Action" href="#" onclick="saveTextFile(false); return false" style="opacity: 0.5"><span class="hide-on-mobile"><i class="fa fa-save"></i></span>Save</a>
|
|
<span class="hide-on-mobile">
|
|
<a class="btn-Action" href="<%= current_site.uri @filename %>" target="_blank"><i class="fa fa-globe"></i> View</a>
|
|
<a href="#" id="shareButton" class="btn-Action" data-container="body" data-toggle="popover" data-placement="bottom" data-content='<%== erb :'_share', layout: false, locals: {site: current_site, page_uri: "#{current_site.uri}/#{@filename}"} %>'><i class="fa fa-share-alt chat-button"></i> Share</a><!-- <% if current_site.supporter? %><a class="btn-Action" id="chatButton"><i class="fa fa-comments"></i> Penelope <span style="font-size: 8pt">(beta)</span></a><% end %> -->
|
|
</span>
|
|
<!-- <a id="saveAndExitButton" class="btn-Action" href="#" onclick="saveTextFile(true); return false" style="opacity: 0.5"><i class="fa fa-save"></i> Save and Exit</a> -->
|
|
<div id="editorUpdates" class="tooltip fade bottom in hidden" style="top: 90px;right: 12.5em;">
|
|
<div class="tooltip-arrow"></div>
|
|
<div class="tooltip-inner">
|
|
<span></span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script src="/js/purify.min.js"></script>
|
|
<script src="/js/marked.min.js"></script>
|
|
<script src="/js/sse.min.js"></script>
|
|
<!--
|
|
<% if current_site.supporter? %>
|
|
<script src="/js/chat.js"></script>
|
|
<% end %>
|
|
-->
|
|
|
|
<script src="/js/htmlhint.min.js"></script>
|
|
|
|
|
|
<div class="row editor">
|
|
<div class="col left-col" style="display: <% current_site.supporter? ? 'none' : 'block' %>; margin-left: 20px;">
|
|
<div id="editor"></div>
|
|
</div>
|
|
<div class="col right-col chat-container" style="display: none">
|
|
<div class="resize-handle"></div>
|
|
<div id="chat-box" class="chat-box">
|
|
<div class="bot-message message">
|
|
<img src="/img/heartcat.png" style="width: 30px; margin-bottom: 10px;">
|
|
<p>I'm Penelope, your coding assistant! I'm here to help you with your web site.</p>
|
|
<p>I'm good at coding but can be wrong on general knowledge, <strong>so be sure to verify facts I give you</strong>.</p>
|
|
<p>How can I help you today?</p>
|
|
</div>
|
|
</div>
|
|
<div id="chat-form">
|
|
<form>
|
|
<input name="csrf_token" value="<%= csrf_token %>" type="hidden">
|
|
<input type="text" id="chat-input" placeholder="Ask a coding question..." autocomplete="off">
|
|
<button type="submit" class="btn-Action">Send</button>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script src="/monaco/min/vs/loader.js"></script>
|
|
<script>
|
|
window.MonacoEnvironment = {
|
|
getWorkerUrl: function(workerId, label) {
|
|
return `/monaco/min/vs/base/worker/workerMain.js`;
|
|
}
|
|
};
|
|
require.config({ paths: { 'vs': '/monaco/min/vs' } });
|
|
|
|
var unsavedChanges = false
|
|
|
|
function setTheme(name) {
|
|
var editorTheme = $('#theme option:selected')
|
|
|
|
var defaultThemes = ['vs-light', 'hc-light', 'vs-dark', 'hc-black']
|
|
|
|
if(defaultThemes.includes(editorTheme.val())) {
|
|
monaco.editor.setTheme(editorTheme.val());
|
|
} else {
|
|
fetch('/monaco/themes/'+editorTheme.text()+'.json')
|
|
.then(data => data.json())
|
|
.then(data => {
|
|
monaco.editor.defineTheme(editorTheme.val(), data);
|
|
monaco.editor.setTheme(editorTheme.val());
|
|
})
|
|
}
|
|
|
|
$.post('/site/<%= current_site.username %>/set_editor_theme', {
|
|
csrf_token: '<%= csrf_token %>',
|
|
editor_theme: editorTheme.text()
|
|
})
|
|
}
|
|
|
|
<% if current_site.editor_theme %>
|
|
$('#theme option').filter(function() {
|
|
return ($(this).text() == '<%= current_site.editor_theme %>')
|
|
}).prop('selected', true)
|
|
<% else %>
|
|
$('#theme option').filter(function() {
|
|
return ($(this).text() == 'VS Dark')
|
|
}).prop('selected', true)
|
|
<% end %>
|
|
|
|
function saveTextFile(quit) {
|
|
if(unsavedChanges == false)
|
|
return
|
|
|
|
var formData = new FormData();
|
|
var fileContent = editor.getValue();
|
|
formData.append('<%== escape_javascript @filename %>', new File([fileContent], '<%== escape_javascript @filename %>', { type: 'text/html' }));
|
|
formData.append('csrf_token', '<%== escape_javascript csrf_token %>');
|
|
formData.append('username', '<%== escape_javascript current_site.username %>');
|
|
|
|
$.ajax({
|
|
url: '/api/upload',
|
|
data: formData,
|
|
processData: false,
|
|
contentType: false,
|
|
type: 'POST',
|
|
error: function(jqXHR, textStatus, errorThrown) {
|
|
var errorMessage = 'There has been an error saving your file, please try again. If it continues to fail, make a copy of the file locally so you don\'t lose your changes!'
|
|
|
|
if(jqXHR.responseText) {
|
|
try {
|
|
// Attempt to parse the JSON responseText to get the error message
|
|
var parsedResponse = JSON.parse(jqXHR.responseText);
|
|
errorMessage += ' ERROR MESSAGE: ' + parsedResponse.message;
|
|
} catch (error) {
|
|
}
|
|
}
|
|
|
|
$('#saveButton').tooltip('show')
|
|
$('#editorUpdates span').text(errorMessage)
|
|
$('#editorUpdates').fadeIn()
|
|
$('#editorUpdates').removeClass('hidden')
|
|
},
|
|
success: function(response, textStatus, xhr){
|
|
if(xhr.status == 200) {
|
|
unsavedChanges = false
|
|
if(quit === true) {
|
|
window.location = '/dashboard'
|
|
} else {
|
|
$('#editorUpdates span').html('<i class="fa fa-check"></i> Your file has been saved.')
|
|
$('a#saveButton,a#saveAndExitButton').css('opacity', 0.5)
|
|
setTimeout(function() {
|
|
$('#editorUpdates').fadeOut(); //.addClass('hidden');
|
|
}, 2000)
|
|
}
|
|
|
|
} else {
|
|
$('#saveButton').tooltip('show')
|
|
$('#editorUpdates span').text(response)
|
|
}
|
|
$('#editorUpdates').fadeIn()
|
|
$('#editorUpdates').removeClass('hidden')
|
|
|
|
}
|
|
})
|
|
}
|
|
|
|
var editor = {}
|
|
|
|
require(['vs/editor/editor.main'], function() {
|
|
$(document).ready(function() {
|
|
$.ajax({
|
|
url: "/site_files/download/<%= Site.escape_path(@filename) %>",
|
|
cache: false,
|
|
success: function(resp) {
|
|
document.getElementById('editor').innerHTML = '';
|
|
|
|
monaco.languages.css.cssDefaults.setOptions({
|
|
data: {
|
|
useDefaultDataProvider: false
|
|
}
|
|
});
|
|
|
|
// Disable MDN info tips for HTML
|
|
monaco.languages.html.htmlDefaults.setOptions({
|
|
data: {
|
|
useDefaultDataProvider: false
|
|
}
|
|
});
|
|
|
|
// Initialize Monaco Editor
|
|
editor = monaco.editor.create(document.getElementById('editor'), {
|
|
value: resp,
|
|
language: '<%= @monaco_mode %>',
|
|
fontSize: 14,
|
|
automaticLayout: true,
|
|
scrollBeyondLastLine: false,
|
|
wordWrap: 'on',
|
|
wrappingIndent: 'same',
|
|
tabSize: 2,
|
|
minimap: { enabled: false },
|
|
padding: {
|
|
bottom: 25
|
|
},
|
|
fixedOverflowWidgets: true,
|
|
suggestOnTriggerCharacters: false,
|
|
quickSuggestions: false,
|
|
parameterHints: {
|
|
enabled: false
|
|
}
|
|
});
|
|
setTheme();
|
|
|
|
|
|
// Handle change event for unsaved changes
|
|
editor.onDidChangeModelContent(function() {
|
|
$('a#saveButton,a#saveAndExitButton').css('opacity', 1);
|
|
unsavedChanges = true;
|
|
});
|
|
|
|
// Add save command (Ctrl+S / Command+S)
|
|
editor.addCommand(monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyS, function() {
|
|
saveTextFile(false);
|
|
});
|
|
|
|
<% if @monaco_mode == 'html' %>
|
|
// Function to set markers based on HTMLHint validation
|
|
function setHTMLMarkers() {
|
|
const code = editor.getValue();
|
|
const results = HTMLHint.HTMLHint.verify(code);
|
|
|
|
const markers = results.map((error) => {
|
|
return {
|
|
startLineNumber: error.line,
|
|
startColumn: error.col,
|
|
endLineNumber: error.line,
|
|
endColumn: error.col + 1,
|
|
message: error.message,
|
|
severity: monaco.MarkerSeverity.Error,
|
|
};
|
|
});
|
|
|
|
monaco.editor.setModelMarkers(editor.getModel(), 'htmlhint', markers);
|
|
}
|
|
|
|
// Register event listener to validate and set markers on content change
|
|
editor.onDidChangeModelContent(() => {
|
|
setHTMLMarkers();
|
|
});
|
|
|
|
// Initial validation
|
|
setHTMLMarkers();
|
|
<% end %>
|
|
}
|
|
});
|
|
});
|
|
});
|
|
|
|
window.onbeforeunload = function() {
|
|
if(unsavedChanges == true)
|
|
return "You have unsaved changes!"
|
|
}
|
|
|
|
$('a#saveButton,a#saveAndExitButton').click(function() {
|
|
if(!unsavedChanges)
|
|
return false
|
|
return true
|
|
})
|
|
|
|
</script>
|