Author: | acode |
---|---|
Views Total: | 196 views |
Official Page: | Go to website |
Last Update: | April 17, 2021 |
License: | MIT |
Preview:

Description:
Copenhagen is a simple, lightweight, extensible code editor that supports popular languages like HTML, CSS, JavaScript, JSON, Markdown, and Plain Text.
Main Features:
- Easy to implement.
- Code autocomplete.
- Syntax highlighting.
- Line numbers.
- Custom hotkeys.
- Multi-cursor selection.
- Find and replace.
Basic usage:
1. Load the Copenhagen’s JavaScript and CSS files.
<link rel=”stylesheet” href=”./compiled/copenhagen.min.css”>
<script src=”./compiled/copenhagen.min.js”></script>
2. Create a container for the editor and determine which language you want to use: “javascript”, “json”, “markdown”, “html”, “css” and “text”.
<div class="editor" data-language="javascript" data-maxrows="20"> // JS Code Here </div>
3. Initialize the Copenhagen editor and done.
window.addEventListener('DOMContentLoaded', function () { var editor = Copenhagen.initSelectorAll('.editor'); });
4. All configurations that can be passed via either JavaScript or data-option
attributes:
var editor = new Copenhagen.Editor({ // enable readonly here readonly: false, // hide the editor hidden: false, // disable the editor booleandisabled: false, // determine whether to take up the entirety of the relative parent maximized: false, // minimum number of rows of the editor rows: 1, // maximum number of rows of the editor rmaxrows: 30, // determine whether you can "tab out" of the editor tabout: false, // disable line numbers here nolines: false, });
5. Add your own autocomplete (suggestions) to the editor.
function CodeCompleter () { this.suggestions = this.generateSuggestions(this.suggestionMap); }; CodeCompleter.prototype.cursorCharacter = '·'; CodeCompleter.prototype.wildcardWordCharacter = '¤'; CodeCompleter.prototype.wildcardPhraseCharacter = '…'; CodeCompleter.prototype.wildcardReplaceCharacter = '\\$1'; CodeCompleter.prototype.suggestionMap = { 'javascript': [ 'const ', 'const ¤ = ', 'const {…} = ', 'const […] = ', 'console.log(`·Got here: A·`);', 'console.error(`·Error·`);', 'let ', 'let ¤ = ', 'let {…} = ', 'let […] = ', 'var ', 'var ¤ = ', 'var {…} = ', 'var […] = ', 'lib.', 'module.exports = ', 'module.exports = async ', 'return ', 'require(\'·\')', 'class ', 'class ¤ {·}', 'function ', 'function (·)', 'function ¤ (·)', 'function () {·}', 'function ¤ () {·}', 'function (…) {·}', 'function ¤ (…) {·}', 'if (·true·)', 'if () {·}', 'if (…) {·}', 'else ', 'else {·}', 'else if (·true·)', 'for (let i = 0; i < ·10·; i++)', 'for () {·}', 'for (…) {·}', 'while (·true·)', 'while () {·}', 'while (…) {·}', 'await ', 'await lib.', 'await new Promise((resolve, reject) => {·});', 'async ', 'async (·)', '() => {·}', '(…) => {·}', '/**\n * ·\n */', '* @param {·}', '* @param {…} ·paramName·', '* @returns {·}', '* @returns {…} ·returnValue·', 'true', 'false', 'null', 'new ', 'new Promise((resolve, reject) => {·});', 'Promise((resolve, reject) => {·});', 'Promise.all([·]);', 'setTimeout(() => {·}, 1);', 'setInterval(() => {·}, 1);', 'try {·}', 'catch (e) {·}', 'catch (…) {·}', 'throw ', 'throw new Error(`·Oops!·`);', 'new Error(`·Oops!·`)', 'Error(`·Oops!·`)', 'Error(…)' ] }; CodeCompleter.prototype.generateSuggestions = function () { var suggestionMap = this.suggestionMap; var cursorCharacter = this.cursorCharacter; return Object.keys(suggestionMap).reduce(function (suggestions, language) { var phraseList = suggestionMap[language].map(function (value) { var cursorStart = value.indexOf(cursorCharacter); var cursorEnd = value.lastIndexOf(cursorCharacter); var cursorLength = 0; if (cursorStart !== cursorEnd) { cursorLength = cursorEnd - cursorStart - 1; value = value.slice(0, cursorEnd) + value.slice(cursorEnd + 1); } var adjust = cursorStart === -1 ? 0 : cursorStart - value.length + 1; if (adjust) { value = value.substr(0, value.length + adjust - 1) + value.substr(value.length + adjust); } return { value: value, adjust: adjust, cursorLength: cursorLength }; }.bind(this)); suggestions[language] = { lookup: this.generateLookupTrie(phraseList), }; return suggestions; }.bind(this), {}); }; CodeCompleter.prototype.generateLookupTrie = function (phraseList) { var wildcardWord = this.wildcardWordCharacter; var wildcardPhrase = this.wildcardPhraseCharacter; var root = {}; var curNode, node, phrase, value; var i, j, k; for (i = 0; i < phraseList.length; i++) { phrase = phraseList[i]; value = phrase.value; for (j = value.length - 1; j >= 0; j--) { curNode = root; for (k = j; k >= 0; k--) { char = value[k]; curNode[char] = curNode[char] || {}; if (char === wildcardWord || char === wildcardPhrase) { curNode[char][char] = curNode[char][char] || curNode[char]; } curNode = curNode[char]; } curNode.phrases = curNode.phrases || []; curNode.phrases.push({ value: value, ranking: i, adjust: phrase.adjust, cursorLength: phrase.cursorLength, re: phrase.re }); } } return root; }; CodeCompleter.prototype.complete = function (tree, value, index, subs, inWildcard) { index = index || 0; subs = subs || []; inWildcard = inWildcard || ''; var wildcardWord = this.wildcardWordCharacter; var wildcardPhrase = this.wildcardPhraseCharacter; var wildcardReplace = this.wildcardReplaceCharacter; var char; var results = []; var node = tree; for (var i = value.length - 1; i >= 0; i--) { index++; var char = value[i]; if (node[wildcardWord]) { if (char.match(/[0-9a-z_$]/i)) { var newSubs = subs.slice(); if (inWildcard) { newSubs[0] = char + newSubs[0]; } else { newSubs.unshift(char); } results = results.concat( this.complete(node[wildcardWord], value.substr(0, i), index - 1, newSubs, wildcardWord) ); } } if (node[wildcardPhrase]) { if (char.match(/[^\(\)\[\]\{\}\"\'\`]/i)) { var newSubs = subs.slice(); if (inWildcard) { newSubs[0] = char + newSubs[0]; } else { newSubs.unshift(char); } results = results.concat( this.complete(node[wildcardPhrase], value.substr(0, i), index - 1, newSubs, wildcardPhrase) ); } } if (node[char]) { inWildcard = ''; if (node.phrases && (char === ' ')) { results = results.concat( node.phrases.map(function (p) { var curSubs = subs.slice(); return { value: p.value.replace( new RegExp('(' + [wildcardWord, wildcardPhrase, wildcardReplace].join('|') + ')', 'gi'), function ($0) { return curSubs.shift() || ''; } ), ranking: p.ranking, adjust: p.adjust, offset: index - 1 + subs.join('').length, cursorLength: p.cursorLength }; }) ); } node = node[char]; } else { break; } } if (node.phrases && (i < 0 || value[i] === ' ')) { (i < 0) && index++; results = results.concat( node.phrases.map(function (p) { var curSubs = subs.slice(); return { value: p.value.replace( new RegExp('(' + [wildcardWord, wildcardPhrase, wildcardReplace].join('|') + ')', 'gi'), function ($0) { return curSubs.shift() || ''; } ), ranking: p.ranking, adjust: p.adjust, offset: index - 1 + subs.join('').length, cursorLength: p.cursorLength }; }) ); } return results .sort(function (p1, p2) { return p2.offset - p1.offset || p1.ranking - p2.ranking; }) .filter(function (p) { return p.offset < p.value.length; }); }; CodeCompleter.protot
6. API methods.
// Create a custom autocompletion detector to add your own autocomplete box editor.addAutocomplete(name, function(editor, selection, inString, inComment){ // ... }) // Add custom hotkeys editor.addHotkey(keys, function(value, cursors){ // ... }) // Disable animation editor.animateNo() // Blur the editor editor.blur() // Enable autocomplete editor.canSuggest() // Clear history editor.clearHistory() // Clear meta data editor.clearMetadata(metadata) // Disable editor.disable() // Emulate a user action editor.emulateUserAction(userAction) // Enable editor.enable() // Show find and replace dialog editor.find(value) // Find the complement of a character at a specific index based on the language dictionary editor.findComplements(value, index) // Set focus to the editor editor.focus() // Retrieve the active formatter function based on the active language editor.getActiveFormatter() // Retrieve the currently active language for the editor editor.getActiveLanguage() // Retrieve the currently active language dictionary for the editor editor.getActiveLanguageDictionary() // Retrieves the formatter function for a language or return the text formatter if it is not found editor.getFormatter(language) // Retrieve metadata from the editor editor.getMetadata(metadata, defaultValue) // Retrieve the current value of the editor editor.getValue() // Navigate the user action history editor.gotoHistory(amount) // Determine whether the editor is focused editor.hasFocus() // Hide the editor editor.hide() // Determine whether a specific character index is within a comment or not based on the language dictionary editor.inComment(index) // Determine whether a specific character index is within a string or not based on the language dictionary. editor.inString(index) // Retrieve the current read-only status of the editor. editor.isReadOnly() // Open the editor instance editor.open(element, focus, replaceText) // Remove an autocompletion detector editor.removeAutocomplete() // Remove a hotkey handler editor.removeHotkey(hotkey) // Render the editor on the next available frame editor.render(value, forceRender) // Dispatches a "save" event and creates a history entry if the user has performed an action editor.save(value) // Scrolls the editor by a visible "page" amount based on the height of the editor // "up" or "down" editor.scrollPage(direction) // Scrolls to the currently selected text in the editor editor.scrollToText() // Scrolls to a specific line index in the editor editor.scrollToLine(index) // Scrolls the editor to a specific (x, y) coordinate from the top left of the editor editor.scrollTo(x, y) // Select text in the editor at a specific start and end index editor.select(start, end) // Set emulation mode. editor.setEmulationMode(true/false) // Set an error state in the editor editor.setError(lineIndex, column) // Set a custom formatter for a language editor.setFormatter(language, function(){ // ... }) // Set the language editor.setLanguage(language) // Set maximized mode on the editor so that it takes up all of its relative parent's height editor.setMaximized(true/false) // Sets metadata on the editor editor.setMetadata(metadata, value) // Set read-only mode on the editor editor.setReadOnly(true/false) // Set the value of the editor editor.setValue(value) // Show the editor editor.show() // Perform a user action editor.userAction(userAction)
Changelog:
04/17/2021
- Bugfix