Commit 9c944cf7 authored by Michael Murtaugh's avatar Michael Murtaugh
Browse files

new front end folder + working on js linting

parent 89531b07
module.exports = {
env: {
browser: true,
es2021: true,
},
extends: [
'airbnb-base',
],
parserOptions: {
ecmaVersion: 12,
sourceType: 'module',
},
rules: {
},
};
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
env/
build/
venv/
*.pyc
*~
makeserver.egg-info/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
*.egg-info/
.installed.cfg
*.egg
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*,cover
.hypothesis/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
# Sphinx documentation
docs/_build/
# PyBuilder
target/
#Ipython Notebook
.ipynb_checkpoints
# pyenv
.python-version
.sconsign.dblite
node_modules/
......@@ -17,27 +17,6 @@
<header>
<h1 class="title">Makeserver: Change log</h1>
</header>
<nav id="TOC">
<ul>
<li><a href="#section">2016</a><ul>
<li><a href="#nov">24 nov</a></li>
<li><a href="#nov-1">23 nov</a></li>
<li><a href="#nov-2">22 nov</a></li>
<li><a href="#dec">1 Dec</a></li>
</ul></li>
<li><a href="#section-1">2017</a><ul>
<li><a href="#march">March</a></li>
<li><a href="#august">August</a></li>
</ul></li>
<li><a href="#section-2">2018</a></li>
<li><a href="#section-3">2020</a></li>
<li><a href="#section-4">2021</a></li>
<li><a href="#design-decisions">Design decisions</a><ul>
<li><a href="#single-makefile">Single makefile</a></li>
<li><a href="#from-indexical-back-to-dynamic-index">From Indexical back to dynamic index</a></li>
</ul></li>
</ul>
</nav>
<h1 id="section">2016</h1>
<p>It seemed very strong how when generalizing the data join, I suddenly (finally) started to care about the form of the incoming data. In other words, the specific labels of the data started to have an effect as they connected (or didn’t) with the names of properties in the rdfa “template” element. Thus the document becomes instrumentalized as a sort of filter / query into the incoming data stream. Now, finally, the benefits of data rewriting via a mechanism like json-ld would be most useful (and appreciated) to complete the loop without a need for ad hoc reframing / tweaking of the data. The hit or miss effect of the selection, filtering and ignoring unnecessary data, is reminiscent (in an encouraging way) of json-ld’s contexts as filters.</p>
<p>A surprising discovery has been the re-finding of writing “template” code in the form of a sample table row with rdfa properties. It seems it might be useful to revisit early web publishing flows that must have used this kind of mechanism (vague memories of Internet Explorer specific html element properties like data-source).</p>
......@@ -189,14 +168,81 @@ mdsrc=$(shell find . -iname &quot;*.md&quot;)</code></pre>
<p>backend: python / aiohttp server to serve files, run scons / terminal</p>
<p>(terminado / tornado?)</p>
<p>Bootstrap</p>
<p>Minimal starting point is makeserver like functionality with: * scons * terminal output * (interactive terminal?!) * (auth)</p>
<p>Minimal starting point is makeserver like functionality with: * scons * terminal output * (interactive terminal?!) * (auth) * ?edit =&gt; local editor frame (based on code mirror ?) * … if terminado is in place could also be say nano … but would that be interesting / useful INSIDE editor * … linking to etherpad WOULD be useful, as indeed an OUTSIDE shared editor</p>
<p>… for “sponge” like editing … a javascript “session” with access to metadata ? But it’s a server… so if anything (temporary) let that be on the backend .. eventually (as in sponge) connected to a db / persistent index</p>
<p>So what if … server “sniffs” files producing it’s own (ephemeral) rdf graph.</p>
<p>RDF as a light weight (i’m serious ;) abstraction for understanding / working with a graph of files (and eventually related external resources)</p>
<p>Both make and scons define (indirectly) a dependency graph of files .. ie files that can be “sources” for other files. A light way graph structure for representing these relationships is useful as an abstraction between these different tools and the core makeserver. In addition, the idea of a graph is one open to intervention from “outside” via “sponge” like interventions – ie tools that leave linked data traces such as indexalist, etc.</p>
<p>Challenge: support ephemeral indexing (no backend, or in memory) and also long term indexing (db backend).</p>
<p>INDEX listing using graph &lt;!&gt; inspired by:</p>
<p>scons -Q -n –tree=status</p>
<p>cheat sheet:</p>
<p>-Q: Suppress “Reading/Building” progress messages. -n: dry run –tree=status Print a dependency tree in various formats…</p>
<p>The Long term process question</p>
<p>Some processes take a long time to run (like a video edit, a web crawl, etc). Desire should be to initiate these processes interactively, then “detach” (in tmux style) and later rejoin, evt debug when things go awry. Detaching processes from their interface would be useful (maybe literally making implicit/automatic use of tmux/screen?). (OR maybe it’s about performing the function of tmux – ie deciding how much to buffer / or not (overcome rather than repeat the frustration of “lost” terminal output with tmux – in ability to scrollback)…) In general, it’s about really engaging with the underlying system (processes, etc) while still managing the complexity (designing) for users focussed on aspects other than the system (not “novice”;).</p>
<ul>
<li>Adapt ptyprocess/xterm (terminado) to aiohttp</li>
</ul>
<p><a href="https://scons.org/doc/production/HTML/scons-user.html#idp140637540709104">scons use guide on tree</a></p>
<p>compate output of</p>
<p>make -n –debug=v</p>
<pre><code>GNU Make 4.2.1
Built for x86_64-pc-linux-gnu
Copyright (C) 1988-2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later &lt;http://gnu.org/licenses/gpl.html&gt;
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Reading makefiles...
Reading makefile &#39;Makefile&#39;...
Updating makefiles....
Updating goal targets....
Considering target file &#39;all&#39;.
File &#39;all&#39; does not exist.
Considering target file &#39;LOG.html&#39;.
Considering target file &#39;LOG.md&#39;.
Finished prerequisites of target file &#39;LOG.md&#39;.
No need to remake target &#39;LOG.md&#39;.
Finished prerequisites of target file &#39;LOG.html&#39;.
Prerequisite &#39;LOG.md&#39; is newer than target &#39;LOG.html&#39;.
Must remake target &#39;LOG.html&#39;.
pandoc --toc --css style.css --standalone LOG.md -o LOG.html
Successfully remade target file &#39;LOG.html&#39;.
Considering target file &#39;README.html&#39;.
Considering target file &#39;README.md&#39;.
Finished prerequisites of target file &#39;README.md&#39;.
No need to remake target &#39;README.md&#39;.
Finished prerequisites of target file &#39;README.html&#39;.
Prerequisite &#39;README.md&#39; is older than target &#39;README.html&#39;.
No need to remake target &#39;README.html&#39;.
Finished prerequisites of target file &#39;all&#39;.
Must remake target &#39;all&#39;.
Successfully remade target file &#39;all&#39;.</code></pre>
<p>scons -Q -n –tree=status</p>
<pre><code>scons: `.&#39; is up to date.
E = exists
R = exists in repository only
b = implicit builder
B = explicit builder
S = side effect
P = precious
A = always build
C = current
N = no clean
H = no cache
[E b C ]+-.
[E B C ] +-LOG.html
[E C ] | +-LOG.md
[E C ] | +-style.css
[E C ] | +-/usr/bin/pandoc
[E C ] +-LOG.md
[E B C ] +-README.html
[E C ] | +-README.md
[E C ] | +-style.css
[E C ] | +-/usr/bin/pandoc
[E C ] +-README.md
[E C ] +-SConstruct.py
[E C ] +-style.css</code></pre>
<h1 id="design-decisions">Design decisions</h1>
<p>Why were certain key design decisions made?</p>
<h2 id="single-makefile">Single makefile</h2>
......@@ -205,5 +251,6 @@ mdsrc=$(shell find . -iname &quot;*.md&quot;)</code></pre>
<p>QUESTION the usefulness of multiple levels of makefiles … it’s creating confusion! … A SIMPLE (but maybe too drastic) solution: Assume a single makefile, default is any one in the root of the webserver. Eventually other processes can be run for sub directories.</p>
<h2 id="from-indexical-back-to-dynamic-index">From Indexical back to dynamic index</h2>
<p>Static index documents are (1) annoying to leave litered around in each visited directory, (2) inherantly tricky to manage the make rules to regenerate them as needed (on file deletion for instance)…. ie now fighting with bad indexes. (3) Git integration will only add to this complexity. That said indexical is still interesting as a separate project for generating / merging data + documents.</p>
<p>… (feb 2021) it’s not an either/or, a “live” view showing the dependency graph from make/scons is clearly central to the idea of the make server, the relationship with (statically) generated index documents is related and useful, and indeed rightfully external.</p>
</body>
</html>
......@@ -234,6 +234,31 @@ Minimal starting point is makeserver like functionality with:
* terminal output
* (interactive terminal?!)
* (auth)
* ?edit => local editor frame (based on code mirror ?)
* ... if terminado is in place could also be say nano ... but would that be interesting / useful INSIDE editor
* ... linking to etherpad WOULD be useful, as indeed an OUTSIDE shared editor
... for "sponge" like editing ...
a javascript "session" with access to metadata ?
But it's a server... so if anything (temporary) let that be on the backend .. eventually (as in sponge) connected to a db / persistent index
So what if ... server "sniffs" files producing it's own (ephemeral) rdf graph.
RDF as a light weight (i'm serious ;) abstraction for understanding / working with a graph of files (and eventually related external resources)
Both make and scons define (indirectly) a dependency graph of files .. ie files that can be "sources" for other files. A light way graph structure for representing these relationships is useful as an abstraction between these different tools and the core makeserver. In addition, the idea of a graph is one open to intervention from "outside" via "sponge" like interventions -- ie tools that leave linked data traces such as indexalist, etc.
Challenge: support ephemeral indexing (no backend, or in memory) and also long term indexing (db backend).
INDEX listing using graph <!> inspired by:
scons -Q -n --tree=status
cheat sheet:
-Q: Suppress "Reading/Building" progress messages.
-n: dry run
--tree=status Print a dependency tree in various formats...
The Long term process question
......@@ -245,7 +270,119 @@ Some processes take a long time to run (like a video edit, a web crawl, etc). De
[scons use guide on tree](https://scons.org/doc/production/HTML/scons-user.html#idp140637540709104)
scons -Q -n --tree=status
compate output of
make -n --debug=v
```
GNU Make 4.2.1
Built for x86_64-pc-linux-gnu
Copyright (C) 1988-2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Reading makefiles...
Reading makefile 'Makefile'...
Updating makefiles....
Updating goal targets....
Considering target file 'all'.
File 'all' does not exist.
Considering target file 'LOG.html'.
Considering target file 'LOG.md'.
Finished prerequisites of target file 'LOG.md'.
No need to remake target 'LOG.md'.
Finished prerequisites of target file 'LOG.html'.
Prerequisite 'LOG.md' is newer than target 'LOG.html'.
Must remake target 'LOG.html'.
pandoc --toc --css style.css --standalone LOG.md -o LOG.html
Successfully remade target file 'LOG.html'.
Considering target file 'README.html'.
Considering target file 'README.md'.
Finished prerequisites of target file 'README.md'.
No need to remake target 'README.md'.
Finished prerequisites of target file 'README.html'.
Prerequisite 'README.md' is older than target 'README.html'.
No need to remake target 'README.html'.
Finished prerequisites of target file 'all'.
Must remake target 'all'.
Successfully remade target file 'all'.
```
scons -Q -n --tree=status
```
scons: `.' is up to date.
E = exists
R = exists in repository only
b = implicit builder
B = explicit builder
S = side effect
P = precious
A = always build
C = current
N = no clean
H = no cache
[E b C ]+-.
[E B C ] +-LOG.html
[E C ] | +-LOG.md
[E C ] | +-style.css
[E C ] | +-/usr/bin/pandoc
[E C ] +-LOG.md
[E B C ] +-README.html
[E C ] | +-README.md
[E C ] | +-style.css
[E C ] | +-/usr/bin/pandoc
[E C ] +-README.md
[E C ] +-SConstruct.py
[E C ] +-style.css
```
04 Feb 2021: Code folding + Framing!
-----------------
Putting "collage code" into the project feels very right, suddenly playing youtube videos through the player, but in the context of an annotation with full CC writability! This feels like a very satisfying confirmation that the idea of sponge + collage code + makeserver fitting together is indeed justified. It's a joy to (not have to) paste a youtube URL directly in the browser bar but rather in a text file where I can contextualize it with writing ... see it as a basis for something useful -- so "Sex crimes" from the Eurthmics becomes the starting point of a playlist, (eventually to be transformed into something, sharable, more durable and *critically* under my own conditions rather than those of the site in question.
Annotation? It's a VIEW of a (future) file...
File menu ipv Annotations makes sense with standard opts (save etc).
<!> need to differentiate local files + external URLs. But this division is indeed a key distinction to the whole inside out basis of the makeserver (and of course collage code, video wiki, etc).
"Frame" tabs are linked to a "target" (initially there is a single "default"). This is a simple extension of the standard behaviour of the browser. In a way then browser tabs correspond to additional targets (which indeed are then shown as separate (cc) tabs).
There's something then special about the relationship of the Annotation & Frame with an eventual Source & Target relationship (from make/scons)... ie the annotation is linked in part to the target ...
When editing a markdown source (say README.md) while README.html is open, there's never a need to open README.md in the frame (it's not HTML or media for one).
When opening a document, it's a useful view to see a "map" with the recognized IDs within the document.
AHA: DUAL view: frame shows directly while other views show "filtered" view... scanning the src, for instance ... (still there's a need /use for a filtered view that localizes links ...)
sponge models...
* part-whole
* original-format (versions)
* tags
* media
AHA original->format is like source->target
The preferred referent is not always the original? (but in any case the resolution of links in a weft to an "original" is interesting).
How does an therpad view come to be?
(another) powerful idea:
etherpad is (just) another frame... what "adapter"(s) (sponge, etherpad plugin?) need to be in place to integrate as a space for writing annotations (or just to functionally use as a source for derived targets) -- the case of wefts is a good one thus.
CODEMIRROR is a view for a (local) file (could also be used for remote file, just not editable then)...
post shower aha: the mising link with etherpad (etherdump) scons/make ... is an abstraction of version / last modified / content md5 ... a key function of the system would be to (be able to) bridge between (local) targets and (partially) online sources via an abstraction of version. etherdump, in this sense, is *suggestive* of a solution (rather than directly a solution), ie making an abstraction to api/scraping to (efficiently determine when resources have changed, and integrating their eventual download and integration into a local make workflow is key.
ultimately the inside out ness of the system doesn't dictate what external tools are used, but it does favor those tools with porousness / e.g. API access, that allows adaptation an integration (recurring theme, see for instance zulip/integrations).
The confusion of documents/data that Daniel Punday writes about is reflecting in a confusion of work practices and standards for representation (RDF). A line that stands out now for me in Punday is the observation of the signficance (not expanded upon) of Licklider's desire for destroying barriers of disciplinarity (is Punday thus saying that such an erasure isn't possible/desirable!).
Inspiration: Things I hate: playing music in Rhythm box and not being able to edit the title + artist data (presumably because the right extensions aren't installed to actually edit the metadata for whatever format the music file is) ... but also ... what if the file is the whole album (not broken into tracks... also!)...
rdf is like binary... an extreme reduction that is on one hand revolutionary and a foundation for making computing general purpose, and on the other hand not in and of itself an important "encoding" to consider / look at. In actual use, digital data need interpretive/algorithmic frames to reconstitute and represent it. I think in a similar way, RDF as a data structure is a kind of extreme data normalization, permitting a general purpose way for relational data to be expressed. But in terms of actually using/reading/writing the data, its more appropriate to consider the framing as an essential part of making the process meaningful. (There's nothing pure about a bit, nor is there about a triple of "data").... zooming out and framing is necessary to ascribe meaning and the consider the quality / recombine documents. When a document / article / book is "rediscovered", read again years after publication (or an initial reading) -- and one "discovers" something new -- it's because the value derived from documents and from reading depends on a changing (personal / culutural) frame.
Design decisions
......@@ -265,3 +402,6 @@ From Indexical back to dynamic index
-------------------------------------
Static index documents are (1) annoying to leave litered around in each visited directory, (2) inherantly tricky to manage the make rules to regenerate them as needed (on file deletion for instance).... ie now fighting with bad indexes. (3) Git integration will only add to this complexity. That said indexical is still interesting as a separate project for generating / merging data + documents.
... (feb 2021) it's not an either/or, a "live" view showing the dependency graph from make/scons is clearly central to the idea of the make server, the relationship with (statically) generated index documents is related and useful, and indeed rightfully external.
# install:
# pip3 install -e .
mdsrc=$(shell ls *.md)
html_from_md=$(mdsrc:%.md=%.html)
all: $(html_from_md)
print-%:
@echo '$*=$($*)'
%.html: %.md
pandoc --toc --css style.css --standalone $< -o $@
install-statics:
mkdir -p makeserver/data/htdocs/static/plyr
cp node_modules/plyr/dist/plyr.css makeserver/data/htdocs/static/plyr/
mkdir -p makeserver/data/htdocs/static/codemirror
cp node_modules/codemirror/lib/codemirror.css makeserver/data/htdocs/static/codemirror/
\ No newline at end of file
......@@ -14,17 +14,6 @@
<link rel="stylesheet" href="style.css" />
</head>
<body>
<nav id="TOC">
<ul>
<li><a href="#makeserver">makeserver</a><ul>
<li><a href="#some-design-goals">Some Design Goals</a></li>
<li><a href="#faq">FAQ</a></li>
<li><a href="#installation">Installation</a></li>
<li><a href="#usage">Usage</a></li>
</ul></li>
<li><a href="#changelog">Changelog</a></li>
</ul>
</nav>
<h1 id="makeserver">makeserver</h1>
<pre><code>in the course of a practice...
......@@ -52,11 +41,15 @@ A: Indeed, make was first released by Stuart Feldman in 1977. In a world where s
A: Not exactly, though it does incorporate the ace.js project to provide browser-based file editing and viewing with syntax coloring.</p>
<h2 id="installation">Installation</h2>
<p>TODO: Update for latest version.</p>
<h2 id="development">Development</h2>
<p>To build from scratch</p>
<p>The frontend:</p>
<p>yarn build</p>
<h2 id="usage">Usage</h2>
<ul>
<li>Add ?remake to url to force a remake (equivalent to make -f)</li>
</ul>
<h1 id="changelog">Changelog</h1>
<p><a href="LOG.html">See LOG</a></p>
<p><a href="LOG.md">See LOG</a> (<a href="LOG.html">html</a>)</p>
</body>
</html>
......@@ -48,6 +48,15 @@ Installation
TODO: Update for latest version.
Development
-----------------
To build from scratch
The frontend:
yarn build
Usage
-----------
......@@ -56,3 +65,4 @@ Usage
Changelog
================
[See LOG](LOG.md) ([html](LOG.html))
HTMLFromMarkdown = Builder(action="""pandoc --css ${SOURCES[1]} --standalone ${SOURCES[0]} -o $TARGET""")
env = Environment(BUILDERS={
'HTMLFromMarkdown': HTMLFromMarkdown
})
from pathlib import Path
for path in Path(".").glob("*.md"):
env.HTMLFromMarkdown(path.stem+".html", [str(path), "style.css"])
# this doesn't work since the files are served statically (can't bootstrap)
# cclabsrcs = []
# for path in Path("front/*.js"):
# cclabsrcs.append(str(path))
# for path in Path("front/style/*.css"):
# cclabsrcs.append(str(path))
# Command("makeserver/data/htdocs/cclab/cclab.js", cclabsrcs, "yarn build")
/* Fresh start 2021 */
import { CommandRegistry } from '@lumino/commands';
import { Message } from '@lumino/messaging';
import { BoxPanel, SplitPanel, CommandPalette, ContextMenu, DockPanel, Menu, MenuBar, Widget } from '@lumino/widgets';
import './style/index.css';
// import '@fortawesome/fontawesome-free/css/all.min.css';
import { URLBar } from './urlbar.js';
import { EditorWidget } from './editor.js';
import { FrameWidget } from './frame.js';
import { Sniffer } from './sniffer.js';
// import { ListingWidget } from './listing.js';
import * as reflinks from './reflinks.js';
// import * as ticdb from './ticdb.js';
const VIDEO_URL = "http://vandal.ist/thesituationisttimes/video/2017-12-14/MVI_0033.web.mp4";
const _cc = {};
window._cc = _cc;
const commands = new CommandRegistry();
function parse_fragment (url) {
// console.log("parse_fragment", url);
var ret = {}
if (url.indexOf("#") >= 0) {
var p = url.split("#", 2);
ret.base = p[0];
ret.fragment = p[1];
} else {
ret.base = url;
ret.fragment = '';
}
return ret;
}
_cc.handle_link = function (href, target) {
// HANDLE HREF + TARGET
console.log("_cc.handle_link", href, target);
if (_cc.frame) {
_cc.frame.src = href;
}
}
_cc.paste_link = function () {
var href = urlbar.url,
hash = urlbar.fragment;
console.log("paste_link", href, hash);
if (_cc.editor) {
var ev = _cc.editor.getValue();
var thereflinks = reflinks.extract_reflink_definitions(ev);
if (hash) {
href = parse_fragment(href).base + hash;
}
var compact_href = reflinks.compactRefLink(href, thereflinks);
if (compact_href !== href) {
_cc.editor.replaceSelection("["+compact_href+"]");
} else {
_cc.editor.replaceSelection("<"+href+">");
}
}
}
_cc.setActiveEditor = (editor) => {
if (editor !== _cc.editor) {
// console.log("setActiveEditor", editor);
_cc.editor = editor;
}
}
_cc.hashchange = (baseurl, fragment) => {
urlbar.url=baseurl;
urlbar.fragment = fragment;
}
let urlbar;
function main () {
const dialog = document.getElementById("dialog"),
openfile = document.getElementById("openfile"),
openfile_fileinput = document.getElementById("openfile_fileinput"),
openfile_cancel = document.getElementById("openfile_cancel");
function dialog_is_open () {
return dialog.style.display != "none";
}
function close_dialog() {
dialog.style.display = "none";
openfile.style.display = "none";
openfile_fileinput.value = null;
}
function show_openfile() {
dialog.style.display = "flex";
openfile.style.display = "block";
openfile_fileinput.focus();
}
openfile_cancel.addEventListener("click", e=> {
close_dialog();
})
commands.addCommand('annotation:new', {
label: 'New',
mnemonic: 1,
iconClass: 'fa fa-file',
execute: () => {
// console.log('Import...');
// show_openfile();
let editor = new EditorWidget();
dock.addWidget(editor);
}
});
commands.addCommand('annotation:save', {
label: 'Save',
mnemonic: 1,
iconClass: 'fa fa-save',
execute: () => {
console.log('Save');
// show_openfile();
}
});
commands.addCommand('annotation:save-as', {
label: 'Save As...',
mnemonic: 1,
iconClass: 'fa fa-save',
execute: () => {
console.log('Save As...');
// show_openfile();
}
});
commands.addCommand('media:toggle', {
label: 'Play/Pause',
mnemonic: 1,
iconClass: 'fa fa-play',
execute: () => {
console.log('Play/Pause media...');
// show_openfile();
_cc.frame.toggle();
}
});
commands.addCommand('media:step-back', {
label: 'Step back',
mnemonic: 2,
iconClass: 'fa fa-step-backward',
execute: () => {
console.log('Media Back...');
_cc.frame.jumpback();
}
});
commands.addCommand('media:step-forward', {
label: 'Step forward',
mnemonic: 3,
iconClass: 'fa fa-step-forward',
execute: () => {
console.log('Media Forward...');
_cc.frame.jumpforward();
}
});
commands.addCommand('cc:pastefragment', {
label: 'Paste fragment',
mnemonic: 1,
iconClass: 'fa fa-paste',
execute: () => {
console.log('Paste fragment...');
_cc.paste_link();
}
});