1
0
mirror of https://github.com/chinchang/web-maker.git synced 2025-07-28 17:20:13 +02:00

Merge pull request #66 from chinchang/release-2.3

Release 2.3
This commit is contained in:
Kushagra Gour
2017-02-05 20:34:23 +05:30
committed by GitHub
6 changed files with 376 additions and 23 deletions

View File

@@ -8,7 +8,7 @@
"accessor-pairs": "error",
"array-bracket-spacing": "off",
"array-callback-return": "error",
"arrow-body-style": "error",
"arrow-body-style": "off",
"arrow-parens": "error",
"arrow-spacing": "error",
"block-scoped-var": "error",
@@ -120,7 +120,7 @@
"no-native-reassign": "error",
"no-negated-condition": "off",
"no-nested-ternary": "off",
"no-new": "error",
"no-new": "off",
"no-new-func": "error",
"no-new-object": "error",
"no-new-require": "error",
@@ -246,6 +246,8 @@
]
},
"globals": {
"ArrayBuffer": true,
"Uint8Array": true,
"chrome": true,
"CodeMirror": true,
"Split": true,

View File

@@ -105,12 +105,18 @@
<symbol id="codepen-logo" viewBox="0 0 120 120"><path class="outer-ring" d="M60.048 0C26.884 0 0 26.9 0 60.048s26.884 60 60 60.047c33.163 0 60.047-26.883 60.047-60.047 S93.211 0 60 0z M60.048 110.233c-27.673 0-50.186-22.514-50.186-50.186S32.375 9.9 60 9.9 c27.672 0 50.2 22.5 50.2 50.186S87.72 110.2 60 110.233z"/><path class="inner-box" d="M97.147 48.319c-0.007-0.047-0.019-0.092-0.026-0.139c-0.016-0.09-0.032-0.18-0.056-0.268 c-0.014-0.053-0.033-0.104-0.05-0.154c-0.025-0.078-0.051-0.156-0.082-0.232c-0.021-0.053-0.047-0.105-0.071-0.156 c-0.033-0.072-0.068-0.143-0.108-0.211c-0.029-0.051-0.061-0.1-0.091-0.148c-0.043-0.066-0.087-0.131-0.135-0.193 c-0.035-0.047-0.072-0.094-0.109-0.139c-0.051-0.059-0.104-0.117-0.159-0.172c-0.042-0.043-0.083-0.086-0.127-0.125 c-0.059-0.053-0.119-0.104-0.181-0.152c-0.048-0.037-0.095-0.074-0.145-0.109c-0.019-0.012-0.035-0.027-0.053-0.039L61.817 23.5 c-1.072-0.715-2.468-0.715-3.54 0L24.34 46.081c-0.018 0.012-0.034 0.027-0.053 0.039c-0.05 0.035-0.097 0.072-0.144 0.1 c-0.062 0.049-0.123 0.1-0.181 0.152c-0.045 0.039-0.086 0.082-0.128 0.125c-0.056 0.055-0.108 0.113-0.158 0.2 c-0.038 0.045-0.075 0.092-0.11 0.139c-0.047 0.062-0.092 0.127-0.134 0.193c-0.032 0.049-0.062 0.098-0.092 0.1 c-0.039 0.068-0.074 0.139-0.108 0.211c-0.024 0.051-0.05 0.104-0.071 0.156c-0.031 0.076-0.057 0.154-0.082 0.2 c-0.017 0.051-0.035 0.102-0.05 0.154c-0.023 0.088-0.039 0.178-0.056 0.268c-0.008 0.047-0.02 0.092-0.025 0.1 c-0.019 0.137-0.029 0.275-0.029 0.416V71.36c0 0.1 0 0.3 0 0.418c0.006 0 0 0.1 0 0.1 c0.017 0.1 0 0.2 0.1 0.268c0.015 0.1 0 0.1 0.1 0.154c0.025 0.1 0.1 0.2 0.1 0.2 c0.021 0.1 0 0.1 0.1 0.154c0.034 0.1 0.1 0.1 0.1 0.213c0.029 0 0.1 0.1 0.1 0.1 c0.042 0.1 0.1 0.1 0.1 0.193c0.035 0 0.1 0.1 0.1 0.139c0.05 0.1 0.1 0.1 0.2 0.2 c0.042 0 0.1 0.1 0.1 0.125c0.058 0.1 0.1 0.1 0.2 0.152c0.047 0 0.1 0.1 0.1 0.1 c0.019 0 0 0 0.1 0.039L58.277 96.64c0.536 0.4 1.2 0.5 1.8 0.537c0.616 0 1.233-0.18 1.77-0.537 l33.938-22.625c0.018-0.012 0.034-0.027 0.053-0.039c0.05-0.035 0.097-0.072 0.145-0.109c0.062-0.049 0.122-0.1 0.181-0.152 c0.044-0.039 0.085-0.082 0.127-0.125c0.056-0.055 0.108-0.113 0.159-0.172c0.037-0.045 0.074-0.09 0.109-0.139 c0.048-0.062 0.092-0.127 0.135-0.193c0.03-0.049 0.062-0.098 0.091-0.146c0.04-0.07 0.075-0.141 0.108-0.213 c0.024-0.051 0.05-0.102 0.071-0.154c0.031-0.078 0.057-0.156 0.082-0.234c0.017-0.051 0.036-0.102 0.05-0.154 c0.023-0.088 0.04-0.178 0.056-0.268c0.008-0.045 0.02-0.092 0.026-0.137c0.018-0.139 0.028-0.277 0.028-0.418V48.735 C97.176 48.6 97.2 48.5 97.1 48.319z M63.238 32.073l25.001 16.666L77.072 56.21l-13.834-9.254V32.073z M56.856 32.1 v14.883L43.023 56.21l-11.168-7.471L56.856 32.073z M29.301 54.708l7.983 5.34l-7.983 5.34V54.708z M56.856 88.022L31.855 71.4 l11.168-7.469l13.833 9.252V88.022z M60.048 67.597l-11.286-7.549l11.286-7.549l11.285 7.549L60.048 67.597z M63.238 88.022V73.14 l13.834-9.252l11.167 7.469L63.238 88.022z M90.794 65.388l-7.982-5.34l7.982-5.34V65.388z"/></symbol>
</svg>
<a href="" id="codepenBtn" class="mode-btn hint--rounded hint--top-left" data-hint="Edit on CodePen">
<a href="" id="codepenBtn" class="mode-btn hint--rounded hint--top-left" aria-label="Edit on CodePen">
<svg>
<use xlink:href="#codepen-logo"></use>
</svg>
</a>
<a href="" id="screenshotBtn" class="mode-btn hint--rounded hint--top-left" d-click="takeScreenshot" aria-label="Take screenshot of preview">
<svg style="width:24px;height:24px" viewBox="0 0 24 24">
<path d="M4,4H7L9,2H15L17,4H20A2,2 0 0,1 22,6V18A2,2 0 0,1 20,20H4A2,2 0 0,1 2,18V6A2,2 0 0,1 4,4M12,7A5,5 0 0,0 7,12A5,5 0 0,0 12,17A5,5 0 0,0 17,12A5,5 0 0,0 12,7M12,9A3,3 0 0,1 15,12A3,3 0 0,1 12,15A3,3 0 0,1 9,12A3,3 0 0,1 12,9Z" />
</svg>
</a>
<div class="footer__separator"></div>
<a id="layoutBtn1" class="mode-btn">
@@ -172,10 +178,10 @@
<div class="modal__content" id="app">
<h1>Add Library</h1>
<h3>JavaScript</h3>
<textarea id="js-external-js" class="full-width" id="" cols="30" rows="5" placeholder="Put each library in new line"></textarea>
<textarea id="js-external-js" class="full-width" id="" cols="30" rows="5" placeholder="Start typing name of a library. Put each library in new line"></textarea>
<h3>CSS</h3>
<textarea id="js-external-css" class="full-width" id="" cols="30" rows="5" placeholder="Put each library in new line"></textarea>
<textarea id="js-external-css" class="full-width" id="" cols="30" rows="5" placeholder="Start typing name of a library. Put each library in new line"></textarea>
<div style="margin-top:20px;">
Choose from popular libraries:
@@ -194,7 +200,7 @@
<div class="modal" id="helpModal">
<div class="modal__content">
<h1>Web Maker<small style="font-size:14px;"> v2.2.2</small></h1>
<h1>Web Maker<small style="font-size:14px;"> v2.3.0</small></h1>
<div>
<p>Made by <a href="https://twitter.com/chinchang457" target="_blank">Kushagra Gour</a></p>
<p>Tweet out your feature requests, comments & suggestions to <a target="_blank" href="https://twitter.com/webmakerApp">@webmakerApp</a>.</p>
@@ -288,6 +294,21 @@
<div class="modal" id="notificationsModal">
<div class="modal__content">
<h1>Whats new?</h1>
<div class="notification">
<span class="notification__version">2.3.0</span>
<ul>
<li><strong>Add Library Autocompletion</strong> - Just start typing the name of library and you'll be shown matching libraries from cdnjs.</li>
<li><strong>Preview Screenshot Capture</strong> - Want to grab a nice screenshot of your creation. You have it! Click and capture.</li>
<li><strong>Auto Indent Code</strong> - Select your code and hit Shift-Tab to auto-indent it!</li>
<li><strong>Keyboard Navigation in Saved List</strong> - Now select your creation using arrow keys and hit ENTER to open it.</li>
<li>Highlight active line in code panes.</li>
<li><strong>Bugfix</strong> - Fix in generated title of new creation.</li>
<li><strong>Bugfix</strong> - HTML autocompletion is manual triggered now with Ctrl+Space.</li>
<li><a href="https://github.com/chinchang/web-maker/issues" target="_blank">Suggest a feature.</a></li>
<li>Thank you for being a part of this awesome 4000+ developers community. If you find Web Maker helpful, <a href="https://chrome.google.com/webstore/detail/web-maker/lkfkkhfhhdkiemehlpkgjeojomhpccnh/reviews" target="_blank" class="btn">Please rate Web Maker <span class="star"></span></a> & <a href="http://twitter.com/share?url=https://kushagragour.in/lab/web-maker/&text=Web Maker - Convert your Chrome tabs into a blazing fast offline web playground! via @webmakerApp&related=webmakerApp&hashtags=web,editor" target="_blank" target="_blank" class="btn">share it</a>.</li>
</ul>
</div>
<div class="notification">
<span class="notification__version">2.2.0</span>
<ul>
@@ -297,8 +318,6 @@
<li><strong>Faster CSS update</strong> - Preview updates instantly without refresh when just CSS is changed.</li>
<li><strong>Bugfix</strong> - Indentation fixed while going on new line.</li>
<li><strong>Bugfix</strong> - Works even in Chrome Canary now. Though libraries can be added only through CDNs.</li>
<li><a href="https://github.com/chinchang/web-maker/issues" target="_blank">Suggest a feature.</a></li>
<li>Thank you for being a part of this awesome 4000+ developers community. If you find Web Maker helpful, <a href="https://chrome.google.com/webstore/detail/web-maker/lkfkkhfhhdkiemehlpkgjeojomhpccnh/reviews" target="_blank" class="btn">Please rate Web Maker <span class="star"></span></a> & <a href="http://twitter.com/share?url=https://kushagragour.in/lab/web-maker/&text=Web Maker - Convert your Chrome tabs into a blazing fast offline web playground! via @webmakerApp&related=webmakerApp&hashtags=web,editor" target="_blank" target="_blank" class="btn">share it</a>.</li>
</ul>
</div>
@@ -386,6 +405,7 @@
<script src="lib/codemirror/addon/hint/xml-hint.js"></script>
<script src="lib/codemirror/addon/hint/html-hint.js"></script>
<script src="lib/codemirror/addon/hint/css-hint.js"></script>
<script src="lib/codemirror/addon/selection/active-line.js"></script>
<script src="lib/codemirror/mode/xml/xml.js"></script>
<script src="lib/codemirror/mode/javascript/javascript.js"></script>
@@ -405,6 +425,7 @@
<script src="loader.js"></script>
<script src="notifications.js"></script>
<script src="library-list.js"></script>
<script src="textarea-autocomplete.js"></script>
<script src="script.js"></script>
<script src="dropdown.js"></script>
</body>

View File

@@ -6,7 +6,9 @@
"homepage_url": "https://kushagragour.in/lab/web-maker",
"permissions": [
"storage",
"tabs"
"tabs",
"<all_urls>",
"downloads"
],
"content_security_policy": "script-src 'self' https://ajax.googleapis.com https://code.jquery.com https://cdnjs.cloudflare.com https://unpkg.com https://maxcdn.bootstrapcdn.com https://cdn.jsdelivr.net/ https://www.google-analytics.com 'unsafe-eval'; object-src 'self'",
"options_ui": {

View File

@@ -3,7 +3,8 @@
onboardModal, layoutBtn1, layoutBtn2, layoutBtn3, layoutBtn4, helpBtn, onboardModal, onboardModal,
addLibraryModal, addLibraryModal, notificationsBtn, notificationsModal, notificationsModal,
notificationsModal, notificationsBtn, codepenBtn, saveHtmlBtn, openBtn, saveBtn, newBtn,
settingsBtn, onboardModal, notificationsBtn, onboardShowInTabOptionBtn, onboardDontShowInTabOptionBtn */
settingsBtn, onboardModal, notificationsBtn, onboardShowInTabOptionBtn, onboardDontShowInTabOptionBtn
TextareaAutoComplete */
/* eslint-disable no-extra-semi */
;(function (alertsService) {
@@ -63,6 +64,7 @@ settingsBtn, onboardModal, notificationsBtn, onboardShowInTabOptionBtn, onboardD
// TODO: for legacy reasons when. Will be refactored as global preferences.
, prefs = {}
, codeInPreview = { html: null, css: null, js: null }
, isSavedItemsPaneOpen = false
// DOM nodes
, frame = $('#demo-frame')
@@ -279,7 +281,8 @@ settingsBtn, onboardModal, notificationsBtn, onboardShowInTabOptionBtn, onboardD
} else {
savedItemsPane.classList.toggle('is-open');
}
document.body.classList[savedItemsPane.classList.contains('is-open') ? 'add' : 'remove']('overlay-visible');
isSavedItemsPaneOpen = savedItemsPane.classList.contains('is-open');
document.body.classList[isSavedItemsPaneOpen ? 'add' : 'remove']('overlay-visible');
}
function openSavedItemsPane() {
chrome.storage.local.get('items', function (result) {
@@ -312,7 +315,7 @@ settingsBtn, onboardModal, notificationsBtn, onboardShowInTabOptionBtn, onboardD
function createNewItem() {
var d = new Date();
currentItem = {
title: 'Untitled ' + d.getDate() + '-' + d.getMonth() + '-' + d.getHours() + ':' + d.getMinutes(),
title: 'Untitled ' + d.getDate() + '-' + (d.getMonth() + 1) + '-' + d.getHours() + ':' + d.getMinutes(),
html: '',
css: '',
js: '',
@@ -757,9 +760,24 @@ settingsBtn, onboardModal, notificationsBtn, onboardShowInTabOptionBtn, onboardD
theme: 'monokai',
lint: !!options.lint,
foldGutter: true,
styleActiveLine: true,
gutters: options.gutters || [],
// cursorScrollMargin: '20', has issue with scrolling
profile: options.profile || ''
profile: options.profile || '',
extraKeys: {
'Up': function (editor) {
// Stop up/down keys default behavior when saveditempane is open
if (isSavedItemsPaneOpen) { return; }
CodeMirror.commands.goLineUp(editor);
},
'Down': function (editor) {
if (isSavedItemsPaneOpen) { return; }
CodeMirror.commands.goLineDown(editor);
},
'Shift-Tab': function(editor) {
CodeMirror.commands.indentAuto(editor);
}
}
});
cm.on('change', function onChange() {
clearTimeout(updateTimer);
@@ -767,17 +785,24 @@ settingsBtn, onboardModal, notificationsBtn, onboardShowInTabOptionBtn, onboardD
scope.setPreviewContent();
}, updateDelay);
});
cm.on('inputRead', function onChange(editor, input) {
if (input.text[0] === ';' || input.text[0] === ' ') { return; }
CodeMirror.commands.autocomplete(cm, null, { completeSingle: false })
});
if (options.noAutocomplete) {
cm.addKeyMap({
'Ctrl-Space': 'autocomplete'
});
} else {
cm.on('inputRead', function onChange(editor, input) {
if (input.text[0] === ';' || input.text[0] === ' ') { return; }
CodeMirror.commands.autocomplete(cm, null, { completeSingle: false })
});
}
return cm;
}
scope.cm.html = initEditor(htmlCode, {
mode: 'htmlmixed',
profile: 'xhtml',
gutters: [ 'CodeMirror-linenumbers', 'CodeMirror-foldgutter' ]
gutters: [ 'CodeMirror-linenumbers', 'CodeMirror-foldgutter' ],
noAutocomplete: true
});
emmetCodeMirror(scope.cm.html);
scope.cm.css = initEditor(cssCode, {
@@ -822,6 +847,92 @@ settingsBtn, onboardModal, notificationsBtn, onboardShowInTabOptionBtn, onboardD
trackEvent('ui', 'onboardDontShowInTabClick');
}
function saveScreenshot(dataURI) {
// convert base64 to raw binary data held in a string
// doesn't handle URLEncoded DataURIs
var byteString = atob(dataURI.split(',')[1]);
// separate out the mime component
var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0];
// write the bytes of the string to an ArrayBuffer
var ab = new ArrayBuffer(byteString.length);
var ia = new Uint8Array(ab);
for (var i = 0; i < byteString.length; i++) {
ia[i] = byteString.charCodeAt(i);
}
// create a blob for writing to a file
var blob = new Blob([ab], { type: mimeString });
var size = blob.size + (1024 / 2);
var d = new Date();
var fileName = [ 'web-maker-screenshot', d.getFullYear(), d.getMonth(), d.getDate(), d.getHours(), d.getMinutes(), d.getSeconds() ].join('-');
fileName += '.png';
function onWriteEnd() {
var filePath = 'filesystem:chrome-extension://' + chrome.i18n.getMessage('@@extension_id') + '/temporary/' + fileName;
chrome.downloads.download({
url: filePath
}, function() {
// If there was an error, just open the screenshot in a tab.
// This happens in incognito mode where extension cannot access filesystem.
if (chrome.runtime.lastError) {
window.open(filePath);
}
});
}
function errorHandler(e) {
utils.log(e);
}
// create a blob for writing to a file
window.webkitRequestFileSystem(window.TEMPORARY, size, (fs) => {
fs.root.getFile(fileName, { create: true }, (fileEntry) => {
fileEntry.createWriter((fileWriter) => {
fileWriter.onwriteend = onWriteEnd;
fileWriter.write(blob);
}, errorHandler);
}, errorHandler);
}, errorHandler);
}
scope.takeScreenshot = function (e) {
// Hide tooltips so that they don't show in the screenshot
var s = document.createElement('style');
s.textContent = '[class*="hint"]:after, [class*="hint"]:before { display: none!important; }';
document.body.appendChild(s);
function onImgLoad(image) {
var c = document.createElement('canvas');
var iframeBounds = frame.getBoundingClientRect();
c.width = iframeBounds.width;
c.height = iframeBounds.height;
var ctx = c.getContext('2d');
ctx.drawImage(image,
iframeBounds.left, iframeBounds.top, iframeBounds.width, iframeBounds.height,
0, 0, iframeBounds.width, iframeBounds.height);
image.removeEventListener('load', onImgLoad);
saveScreenshot(c.toDataURL());
}
setTimeout(() => {
chrome.tabs.captureVisibleTab(null, { format: 'png', quality: 100 }, function(dataURI) {
s.remove();
if (dataURI) {
var image = new Image();
image.src = dataURI;
image.addEventListener('load', () => onImgLoad(image, dataURI));
}
});
}, 50);
trackEvent('ui', 'takeScreenshotBtnClick');
e.preventDefault();
}
function compileNodes() {
var nodes = [].slice.call($all('[d-click]'));
nodes.forEach(function (el) {
@@ -973,6 +1084,7 @@ settingsBtn, onboardModal, notificationsBtn, onboardShowInTabOptionBtn, onboardD
});
window.addEventListener('keydown', function (event) {
var selectedItemElement;
// Ctrl/⌘ + S
if ((event.ctrlKey || event.metaKey) && (event.keyCode === 83)) {
event.preventDefault();
@@ -988,6 +1100,31 @@ settingsBtn, onboardModal, notificationsBtn, onboardShowInTabOptionBtn, onboardD
else if (event.keyCode === 27) {
closeAllOverlays();
}
if (event.keyCode === 40 && isSavedItemsPaneOpen) {
selectedItemElement = $('.js-saved-item-tile.selected');
if (selectedItemElement) {
selectedItemElement.classList.remove('selected');
selectedItemElement.nextElementSibling.classList.add('selected');
} else {
$('.js-saved-item-tile:first-child').classList.add('selected');
}
$('.js-saved-item-tile.selected').scrollIntoView(false);
} else if (event.keyCode === 38 && isSavedItemsPaneOpen) {
selectedItemElement = $('.js-saved-item-tile.selected');
if (selectedItemElement) {
selectedItemElement.classList.remove('selected');
selectedItemElement.previousElementSibling.classList.add('selected');
} else {
$('.js-saved-item-tile:first-child').classList.add('selected');
}
$('.js-saved-item-tile.selected').scrollIntoView(false);
} else if (event.keyCode === 13 && isSavedItemsPaneOpen) {
selectedItemElement = $('.js-saved-item-tile.selected');
setTimeout(function () {
openItem(selectedItemElement.dataset.itemId);
}, 350);
toggleSavedItemsPane();
}
});
window.addEventListener('click', function(e) {
@@ -1024,8 +1161,11 @@ settingsBtn, onboardModal, notificationsBtn, onboardShowInTabOptionBtn, onboardD
trackEvent('ui', 'addLibrarySelect', target.selectedOptions[0].label);
onExternalLibChange();
});
externalJsTextarea.addEventListener('change', onExternalLibChange);
externalCssTextarea.addEventListener('change', onExternalLibChange);
externalJsTextarea.addEventListener('blur', onExternalLibChange);
externalCssTextarea.addEventListener('blur', onExternalLibChange);
new TextareaAutoComplete(externalJsTextarea, (obj) => obj.latest.match(/\.js$/));
new TextareaAutoComplete(externalCssTextarea, (obj) => obj.latest.match(/\.css$/));
chrome.storage.local.get({
layoutMode: 1,

View File

@@ -211,6 +211,9 @@ select, input[type="text"], textarea {
.cm-s-monokai .CodeMirror-guttermarker-subtle {
opacity: 0.4;
}
.CodeMirror-activeline-background, .CodeMirror-activeline-gutter {
background: rgba(0,0,0,0.1) !important;
}
.CodeMirror-guttermarker-subtle {
/*visibility: hidden !important;*/
}
@@ -466,7 +469,8 @@ li.CodeMirror-hint-active {
transform: translateX(0px);
}
}
.saved-item-tile:hover {
.saved-item-tile:hover,
.saved-item-tile.selected {
background: rgba(255,255,255,0.1);
}
.saved-item-tile__close-btn {
@@ -553,6 +557,32 @@ li.CodeMirror-hint-active {
top: 2px;
left: 2px;
}
.loader,
.loader:after {
border-radius: 50%;
width: 3em;
height: 3em;
}
.loader {
font-size: 5px;
position: relative;
text-indent: -9999em;
border-top: 1.1em solid rgba(118,57,229, 0.2);
border-right: 1.1em solid rgba(118,57,229, 0.2);
border-bottom: 1.1em solid rgba(118,57,229, 0.2);
border-left: 1.1em solid #7639e5;
transform: translateZ(0);
animation: load8 1.1s infinite linear;
}
@keyframes load8 {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
.btn-group {
position: relative;
cursor: pointer;
@@ -565,12 +595,13 @@ li.CodeMirror-hint-active {
margin: 0;
min-width: 200px;
display: block;
font-size: 0.88rem;
list-style: none;
border-radius: 4px;
overflow: hidden;
opacity: 0;
visibility: hidden;
transition: 0.25s ease;
transition: transform 0.25s ease;
transform: translateY(10px);
z-index: 5;
background: white;
@@ -581,6 +612,7 @@ li.CodeMirror-hint-active {
color: #333;
cursor: pointer;
}
.dropdown__menu > li.selected > a,
.dropdown__menu > li > a:hover {
background: var(--color-sidebar);
color: white;
@@ -589,7 +621,8 @@ li.CodeMirror-hint-active {
border-bottom: 1px solid rgba(0,0,0,0.05);
}
.open .dropdown__menu {
.open > .dropdown__menu,
.dropdown__menu.is-open {
opacity: 1;
visibility: visible;
transform: translateY(0);
@@ -677,3 +710,17 @@ li.CodeMirror-hint-active {
background: white url('data:image/svg+xml;charset=UTF-8,<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="width:32px;height:32px" viewBox="0 0 24 24"><path fill="limegreen" d="M12,2A10,10 0 0,1 22,12A10,10 0 0,1 12,22A10,10 0 0,1 2,12A10,10 0 0,1 12,2M11,16.5L18,9.5L16.59,8.09L11,13.67L7.91,10.59L6.5,12L11,16.5Z" /></svg>');
}
.autocomplete-dropdown {
border-top-left-radius: 0;
border-top-right-radius: 0;
right: 0;
max-height: 200px;
overflow-y: auto;
border: 1px solid rgba(0,0,0,0.5);
z-index: 2001;
}
.autocomplete__loader {
position: absolute;
right: 10px;
bottom: 10px;
}

View File

@@ -0,0 +1,141 @@
// textarea-autocomplete.js
(function() {
class TextareaAutoComplete {
constructor (textarea, filter) {
this.t = textarea;
this.filter = filter;
var wrap = document.createElement('div');
wrap.classList.add('btn-group');
textarea.parentElement.insertBefore(wrap, textarea);
wrap.insertBefore(textarea, null);
this.list = document.createElement('ul');
this.list.classList.add('dropdown__menu');
this.list.classList.add('autocomplete-dropdown');
wrap.insertBefore(this.list, null);
this.loader = document.createElement('div');
this.loader.classList.add('loader');
this.loader.classList.add('autocomplete__loader');
this.loader.style.display = 'none';
wrap.insertBefore(this.loader, null);
// after list is insrted into the DOM, we put it in the body
// fixed at same position
setTimeout(() => {
requestIdleCallback(() => {
document.body.appendChild(this.list);
this.list.style.position = 'fixed';
});
},100);
this.t.addEventListener('input', (e) => this.onInput(e));
this.t.addEventListener('keydown', (e) => this.onKeyDown(e));
this.t.addEventListener('blur', (e) => this.closeSuggestions(e));
this.list.addEventListener('mousedown', (e) => this.onListMouseDown(e));
}
get currentLineNumber() {
return this.t.value.substr(0, this.t.selectionStart).split('\n').length;
}
get currentLine() {
var line = this.currentLineNumber;
return this.t.value.split('\n')[line - 1];
}
closeSuggestions() {
this.list.classList.remove('is-open');
this.isShowingSuggestions = false;
}
getList(input) {
var url = 'https://api.cdnjs.com/libraries?search=';
return fetch(url + input)
.then((response) => {
return response.json().then((json) => json.results);
});
}
replaceCurrentLine(val) {
var lines = this.t.value.split('\n');
lines.splice(this.currentLineNumber - 1, 1, val)
this.t.value = lines.join('\n');
}
onInput() {
var currentLine = this.currentLine;
if (currentLine) {
if (currentLine.indexOf('/') !== -1 || currentLine.match(/https*:\/\//)) { return; }
clearTimeout(this.timeout);
this.timeout = setTimeout(() => {
this.loader.style.display = 'block';
this.getList(currentLine).then((arr) => {
this.loader.style.display = 'none';
if (!arr.length) {
this.closeSuggestions();
return;
}
this.list.innerHTML = '';
if (this.filter) {
/* eslint-disable no-param-reassign */
arr = arr.filter(this.filter);
}
for (var i = 0; i < Math.min(arr.length, 10); i++) {
this.list.innerHTML += `<li data-url="${arr[i].latest}"><a>${arr[i].name}</a></li>`;
}
this.isShowingSuggestions = true;
if (!this.textareaBounds) {
this.textareaBounds = this.t.getBoundingClientRect();
this.list.style.top = this.textareaBounds.bottom + 'px';
this.list.style.left = this.textareaBounds.left + 'px';
this.list.style.width = this.textareaBounds.width + 'px';
}
this.list.classList.add('is-open');
});
}, 500);
}
}
onKeyDown(event) {
var selectedItemElement;
if (!this.isShowingSuggestions) { return; }
if (event.keyCode === 27) {
this.closeSuggestions();
event.stopPropagation();
}
if (event.keyCode === 40 && this.isShowingSuggestions) {
selectedItemElement = this.list.querySelector('.selected');
if (selectedItemElement) {
selectedItemElement.classList.remove('selected');
selectedItemElement.nextElementSibling.classList.add('selected');
} else {
this.list.querySelector('li:first-child').classList.add('selected');
}
this.list.querySelector('.selected').scrollIntoView(false);
event.preventDefault();
} else if (event.keyCode === 38 && this.isShowingSuggestions) {
selectedItemElement = this.list.querySelector('.selected');
if (selectedItemElement) {
selectedItemElement.classList.remove('selected');
selectedItemElement.previousElementSibling.classList.add('selected');
} else {
this.list.querySelector('li:first-child').classList.add('selected');
}
this.list.querySelector('.selected').scrollIntoView(false);
event.preventDefault();
} else if (event.keyCode === 13 && this.isShowingSuggestions) {
selectedItemElement = this.list.querySelector('.selected');
this.replaceCurrentLine(selectedItemElement.dataset.url)
this.closeSuggestions();
}
}
onListMouseDown(event) {
var target = event.target;
if (target.parentElement.dataset.url) {
this.replaceCurrentLine(target.parentElement.dataset.url)
this.closeSuggestions();
}
}
}
window.TextareaAutoComplete = TextareaAutoComplete;
})();