Skip to content

Commit

Permalink
Script support (#20)
Browse files Browse the repository at this point in the history
* added option to for using escaped script tags
* replaced styling code to another js file
* added support for tabs
* refactor code that sets the value

Co-authored-by: Aditya Shankar <[email protected]>
  • Loading branch information
therealadityashankar and therealadityashankar authored Jun 19, 2020
1 parent 9468594 commit 59eb83b
Show file tree
Hide file tree
Showing 5 changed files with 528 additions and 518 deletions.
20 changes: 12 additions & 8 deletions dev/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,20 @@
</wc-codemirror> -->

<!-- external -->
<!-- <wc-codemirror src="sample.txt"></wc-codemirror> -->
<!--<wc-codemirror src="sample.html"></wc-codemirror>-->

<!-- inline read-only="nocursor" -->
<!-- <wc-codemirror mode="javascript" readonly="nocursor">
<script type="wc-content">
function myGoodPerson(){
return "what can I do for you ?"
}
</script>
</wc-codemirror> -->
<wc-codemirror mode="javascript" readonly="nocursor">
<script type="wc-content">
function myGoodPerson(){
return "what can I do for you ?"
}

function wouldYouLikeAScriptTag(){
return "&lt;script&gt;&lt;/script&gt;"
}
</script>
</wc-codemirror>

<!-- syntax-highlighting -->
<!-- <wc-codemirror mode="javascript"></wc-codemirror> -->
Expand Down
303 changes: 153 additions & 150 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9742,156 +9742,6 @@ addLegacyProps(CodeMirror);

CodeMirror.version = "5.54.0";

/* eslint no-undef: 0 */
self.CodeMirror = CodeMirror;

/**
* WCCodeMirror
*/
class WCCodeMirror extends HTMLElement {
static get observedAttributes () {
return ['src'];
}

attributeChangedCallback (name, oldValue, newValue) {
if (!this.__initialized) { return; }
if (oldValue !== newValue) {
this[name] = newValue;
}
}

get src () { return this.getAttribute('src'); }
set src (value) {
this.setAttribute('src', value);
this.setSrc();
}

get value () { return this.editor.getValue(); }
set value (value) {
this.setValue(value);
}

constructor () {
super();
const template = document.createElement('template');
template.innerHTML = WCCodeMirror.template();
this.appendChild(template.content.cloneNode(true));
this.__initialized = false;
this.__element = null;
this.editor = null;
}

async connectedCallback () {
this.style.display = 'block';
this.__element = this.querySelector('textarea');

const mode = this.hasAttribute('mode') ? this.getAttribute('mode') : 'null';
const theme = this.hasAttribute('theme') ? this.getAttribute('theme') : 'default';
let readOnly = this.getAttribute('readonly');

if (readOnly === '') readOnly = true;
else if (readOnly !== 'nocursor') readOnly = false;

let content = '';
const innerScriptTag = this.querySelector('script');
if (innerScriptTag) {
if (innerScriptTag.getAttribute('type') === 'wc-content') {
content = WCCodeMirror.dedentText(innerScriptTag.innerHTML);
}
}

let viewportMargin = CodeMirror.defaults.viewportMargin;
if (this.hasAttribute('viewport-margin')) {
const viewportMarginAttr = this.getAttribute('viewport-margin').toLowerCase();
viewportMargin = viewportMarginAttr === 'infinity' ? Infinity : parseInt(viewportMarginAttr);
}

this.editor = CodeMirror.fromTextArea(this.__element, {
lineNumbers: true,
readOnly,
mode,
theme,
viewportMargin
});

if (this.hasAttribute('src')) {
this.setSrc(this.getAttribute('src'));
} else {
// delay until editor initializes
await new Promise(resolve => setTimeout(resolve, 50));
this.setValue(content);
}

this.__initialized = true;
}

async setSrc () {
const src = this.getAttribute('src');
const contents = await this.fetchSrc(src);
this.editor.swapDoc(CodeMirror.Doc(contents, this.getAttribute('mode')));
this.editor.refresh();
}

async setValue (value) {
this.editor.swapDoc(CodeMirror.Doc(value, this.getAttribute('mode')));
this.editor.refresh();
}

async fetchSrc (src) {
const response = await fetch(src);
return response.text();
}

static template () {
return `
<textarea style="display:inherit; width:inherit; height:inherit;"></textarea>
`;
}

/**
* De-dents the code by getting the padding from the first line,
* then removes the same indent amount padding from the rest of the lines
*
* @param {string} text - the text to dedent
* @returns {string} the dedented text
*/
static dedentText (text) {
const lines = text.split('\n');

// remove the first line if it is an empty line
if (lines[0] === '') lines.splice(0, 1);

const initline = lines[0];
let fwdPad = 0;

while (true) {
if (initline[fwdPad] === ' ') {
fwdPad += 1;
} else {
break;
}
}

const fixedLines = [];

for (const line of lines) {
let fixedLine = line;
for (let i = 0; i < fwdPad; i++) {
if (fixedLine[0] === ' ') {
fixedLine = fixedLine.substring(1);
} else {
break;
}
}
fixedLines.push(fixedLine);
}

if (fixedLines[fixedLines.length - 1] === '') fixedLines.splice(fixedLines.length - 1, 1);

return fixedLines.join('\n');
}
}

document.body.insertAdjacentHTML('beforeend', `
<style>
/* BASICS */
Expand Down Expand Up @@ -10246,6 +10096,159 @@ span.CodeMirror-selectedtext { background: none; }
</style>
`);

/* eslint no-undef: 0 */

self.CodeMirror = CodeMirror;

/**
* WCCodeMirror
*/
class WCCodeMirror extends HTMLElement {
static get observedAttributes () {
return ['src'];
}

attributeChangedCallback (name, oldValue, newValue) {
if (!this.__initialized) { return; }
if (oldValue !== newValue) {
this[name] = newValue;
}
}

get src () { return this.getAttribute('src'); }
set src (value) {
this.setAttribute('src', value);
this.setSrc();
}

get value () { return this.editor.getValue(); }
set value (value) {
this.setValue(value);
}

constructor () {
super();
const template = document.createElement('template');
template.innerHTML = WCCodeMirror.template();
this.appendChild(template.content.cloneNode(true));
this.__initialized = false;
this.__element = null;
this.editor = null;
}

async connectedCallback () {
this.style.display = 'block';
this.__element = this.querySelector('textarea');

const mode = this.hasAttribute('mode') ? this.getAttribute('mode') : 'null';
const theme = this.hasAttribute('theme') ? this.getAttribute('theme') : 'default';
let readOnly = this.getAttribute('readonly');

if (readOnly === '') readOnly = true;
else if (readOnly !== 'nocursor') readOnly = false;

let content = '';
const innerScriptTag = this.querySelector('script');
if (innerScriptTag) {
if (innerScriptTag.getAttribute('type') === 'wc-content') {
content = WCCodeMirror.dedentText(innerScriptTag.innerHTML);
content = content.replace(/&lt;(\/?script)&gt;/g, '<$1>');
}
}

let viewportMargin = CodeMirror.defaults.viewportMargin;
if (this.hasAttribute('viewport-margin')) {
const viewportMarginAttr = this.getAttribute('viewport-margin').toLowerCase();
viewportMargin = viewportMarginAttr === 'infinity' ? Infinity : parseInt(viewportMarginAttr);
}

this.editor = CodeMirror.fromTextArea(this.__element, {
lineNumbers: true,
readOnly,
mode,
theme,
viewportMargin
});

if (this.hasAttribute('src')) {
this.setSrc(this.getAttribute('src'));
} else {
// delay until editor initializes
await new Promise(resolve => setTimeout(resolve, 50));
this.value = content;
}

this.__initialized = true;
}

async setSrc () {
const src = this.getAttribute('src');
const contents = await this.fetchSrc(src);
this.value = contents;
}

async setValue (value) {
this.editor.swapDoc(CodeMirror.Doc(value, this.getAttribute('mode')));
this.editor.refresh();
}

async fetchSrc (src) {
const response = await fetch(src);
return response.text();
}

static template () {
return `
<textarea style="display:inherit; width:inherit; height:inherit;"></textarea>
`;
}

/**
* De-dents the code by getting the padding from the first line,
* then removes the same indent amount padding from the rest of the lines
*
* @param {string} text - the text to dedent
* @returns {string} the dedented text
*/
static dedentText (text) {
const lines = text.split('\n');

// remove the first line if it is an empty line
if (lines[0] === '') lines.splice(0, 1);

const initline = lines[0];
let fwdPad = 0;
const usingTabs = initline[0] === '\t';
const checkChar = usingTabs ? '\t' : '';

while (true) {
if (initline[fwdPad] === checkChar) {
fwdPad += 1;
} else {
break;
}
}

const fixedLines = [];

for (const line of lines) {
let fixedLine = line;
for (let i = 0; i < fwdPad; i++) {
if (fixedLine[0] === checkChar) {
fixedLine = fixedLine.substring(1);
} else {
break;
}
}
fixedLines.push(fixedLine);
}

if (fixedLines[fixedLines.length - 1] === '') fixedLines.splice(fixedLines.length - 1, 1);

return fixedLines.join('\n');
}
}

customElements.define('wc-codemirror', WCCodeMirror);

export { WCCodeMirror };
2 changes: 1 addition & 1 deletion index.min.js

Large diffs are not rendered by default.

Loading

0 comments on commit 59eb83b

Please sign in to comment.