Skip to content
This repository was archived by the owner on Mar 5, 2024. It is now read-only.

Commit a0c479a

Browse files
committed
Code buttons by @nlarew, tweaked by me.
1 parent 870ae3b commit a0c479a

File tree

14 files changed

+217
-67
lines changed

14 files changed

+217
-67
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,5 @@ src/build/
2626
/world-builder/source
2727
/world-builder/build
2828
/world-builder/.ninja*
29+
30+
.vscode

sphinxext/fixed_only.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
1-
import logging
21
from docutils import nodes
32
from docutils.parsers.rst import Directive, directives
43
from sphinx.util.nodes import nested_parse_with_titles
54

6-
logger = logging.getLogger('fasthtml')
7-
85

96
class Cond(Directive):
107
"""

sphinxext/mongodb.py

Lines changed: 139 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
from docutils.parsers.rst import directives
1919

2020
import sphinx
21+
import sphinx.directives.code
2122
from sphinx.domains import Domain, ObjType
2223
from sphinx.locale import l_, _
2324
from sphinx.directives import ObjectDescription
@@ -29,14 +30,17 @@
2930

3031
from mongodb_conf import conf
3132

33+
3234
def make_index_entry(*args):
3335
"""Sphinx 1.4 makes a breaking change in index format, so return a valid
3436
index entry whichever version we're running."""
3537
return args + (None,) if sphinx.version_info >= (1, 4) else args
3638

39+
3740
def basename(path):
3841
return os.path.splitext(os.path.basename(path))[0]
3942

43+
4044
class MongoDBObject(ObjectDescription):
4145
"""
4246
Description of a MongoDB object.
@@ -157,7 +161,6 @@ def add_target_and_index(self, name_obj, sig, signode):
157161
else:
158162
objects[fullname] = self.env.docname, self.objtype
159163

160-
161164
indextext = self.get_index_text(objectname, name_obj)
162165
if indextext:
163166
self.indexnode['entries'].append(
@@ -210,9 +213,11 @@ def run(self):
210213
names=('rtype',)),
211214
]
212215

216+
213217
class MongoDBMethod(MongoDBObject):
214218
has_arguments = True
215219

220+
216221
class MongoDBXRefRole(XRefRole):
217222
def process_link(self, env, refnode, has_explicit_title, title, target):
218223
# basically what sphinx.domains.python.PyXRefRole does
@@ -230,10 +235,11 @@ def process_link(self, env, refnode, has_explicit_title, title, target):
230235
refnode['refspecific'] = True
231236
return title, target
232237

238+
233239
def render_domain_data(mongodb_directives):
234-
directives = { }
235-
roles = { }
236-
object_types = { }
240+
directives = {}
241+
roles = {}
242+
object_types = {}
237243

238244
for directive in mongodb_directives:
239245
reftype = directive['name']
@@ -248,6 +254,7 @@ def render_domain_data(mongodb_directives):
248254

249255
return directives, roles, object_types
250256

257+
251258
class MongoDBDomain(Domain):
252259
"""MongoDB Documentation domain."""
253260
name = 'mongodb'
@@ -257,7 +264,7 @@ class MongoDBDomain(Domain):
257264
directives, roles, object_types = render_domain_data(conf['directives'])
258265

259266
initial_data = {
260-
'objects': {}, # fullname -> docname, objtype
267+
'objects': {}, # fullname -> docname, objtype
261268
}
262269

263270
def find_obj(self, env, obj, name, typ, searchorder=0):
@@ -336,11 +343,136 @@ def run(self):
336343
return result
337344

338345

346+
class code_button_row(nodes.Element):
347+
pass
348+
349+
350+
def visit_code_button_row(self, node):
351+
start_tag = self.starttag(node, 'div', CLASS='button-row')
352+
self.body.append(start_tag)
353+
354+
355+
def depart_code_button_row(self, node):
356+
self.body.append('</div>\n')
357+
358+
359+
class code_button(nodes.Element):
360+
pass
361+
362+
363+
def visit_code_button(self, node):
364+
href = node.get('href', False)
365+
css_class = ' '.join(['code-button'] + node.get('classes', []))
366+
367+
if href:
368+
start_tag = self.starttag(node, 'a', CLASS=css_class, role='button', href=href, target='_blank')
369+
else:
370+
start_tag = self.starttag(node, 'a', CLASS=css_class, role='button')
371+
372+
self.body.append(start_tag)
373+
374+
375+
def depart_code_button(self, node):
376+
self.body.append(node['text'][0] + '</a>\n')
377+
378+
379+
class code_container(nodes.Element):
380+
pass
381+
382+
383+
def visit_code_container(self, node):
384+
start_tag = self.starttag(node, 'div', CLASS='button-code-block')
385+
self.body.append(start_tag)
386+
387+
388+
def depart_code_container(self, node):
389+
self.body.append('</div>\n')
390+
391+
392+
def create_button(button_type, link, classes=[]):
393+
"""Create a button inside of a code block with the given label and link."""
394+
button = code_button('')
395+
button['text'] = [button_type]
396+
button['classes'] = classes
397+
398+
if link:
399+
button['href'] = [link]
400+
401+
return button
402+
403+
404+
def add_buttons(parent_class):
405+
"""
406+
Add copy, show in stitch, and github buttons to code block.
407+
"""
408+
class InnerClass(parent_class):
409+
option_spec = parent_class.option_spec.copy()
410+
option_spec.update({
411+
'button-github': directives.uri,
412+
'button-stitch': directives.uri,
413+
'copyable': lambda argument: directives.choice(argument,
414+
('true', 'false', None)),
415+
})
416+
417+
def run(self):
418+
codeblock = parent_class.run(self)
419+
420+
# Only provide buttons if we are generating html
421+
config = self.state.document.settings.env.config
422+
if not config._raw_config['tags'].eval_condition('html'):
423+
return codeblock
424+
425+
options = self.options
426+
container = code_container('')
427+
br = code_button_row('')
428+
429+
if options.get('copyable', 'true') != 'false':
430+
codeblock[0]['classes'] += ['copyable-code-block']
431+
br += create_button('copy', False, classes=['code-button--copy'])
432+
433+
if options.get('button-github'):
434+
br += create_button(
435+
'github',
436+
options['button-github'],
437+
classes=['code-button--github']
438+
)
439+
440+
if options.get('button-stitch'):
441+
br += create_button(
442+
'stitch',
443+
options['button-stitch'],
444+
classes=['code-button--stitch']
445+
)
446+
447+
container += br
448+
container += codeblock
449+
return [container]
450+
451+
return InnerClass
452+
453+
454+
CodeBlock = add_buttons(sphinx.directives.code.CodeBlock)
455+
LiteralInclude = add_buttons(sphinx.directives.code.LiteralInclude)
456+
457+
339458
def setup(app):
340459
app.add_domain(MongoDBDomain)
341460
directives.register_directive('figure', ExtendedFigure)
342461

462+
app.add_node(code_button_row, html=(
463+
visit_code_button_row, depart_code_button_row
464+
))
465+
app.add_node(code_button, html=(
466+
visit_code_button, depart_code_button
467+
))
468+
app.add_node(code_container, html=(
469+
visit_code_container, depart_code_container
470+
))
471+
directives.register_directive('code-block', CodeBlock)
472+
directives.register_directive('sourcecode', CodeBlock)
473+
directives.register_directive('literalinclude', LiteralInclude)
474+
343475
# Do NOT turn on parallel reads until we know what's causing massive
344476
# (2+ GB per worker) memory bloat and thrashing.
345-
return { 'parallel_read_safe': False,
346-
'parallel_write_safe': True }
477+
return {'parallel_read_safe': False,
478+
'parallel_write_safe': True}

themes/mongodb/src/Makefile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@ CSS_INPUTS=css/bootstrap-custom.css \
66
css/feedback.css \
77
css/header.css \
88
css/mws.css \
9-
css/copy-button.css \
109
css/tabs.css \
11-
css/lightbox.css
10+
css/lightbox.css \
11+
css/code-buttons.css
1212
CSS_FILES=$(CSS_INPUTS) css/basic.css
1313

1414
CSS_ERRORS=errors,empty-rules,duplicate-properties,selector-max-approaching
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
.button-row {
2+
/* background-color: #494747; */
3+
background-image: url(https://media.mongodb.org/code-block-bg.png);
4+
display: flex;
5+
flex-direction: row-reverse;
6+
border-left: 5px solid rgb(73, 71, 71);
7+
}
8+
9+
.code-button {
10+
color: #ffffff;
11+
flex-grow: 0;
12+
min-width: 75px;
13+
background: #7a7b7b;
14+
text-align: center;
15+
text-decoration: none;
16+
cursor: pointer;
17+
18+
height: 24px;
19+
line-height: 16px;
20+
margin: 0px 1px;
21+
padding: 4px 8px;
22+
border-radius: 0px;
23+
24+
-webkit-user-select: none;
25+
user-select: none;
26+
}
27+
28+
.code-button:first-of-type {
29+
margin-right: 4px;
30+
margin-right: 0px;
31+
}
32+
33+
.code-button:hover, .code-button:focus {
34+
background: #9d9e9e;
35+
color: #ffffff;
36+
text-decoration: none;
37+
}
38+
39+
.code-button:active {
40+
background: #7a7b7b;
41+
}
42+
43+
.button-code-block pre {
44+
margin: 0 auto;
45+
padding-top: 2px;
46+
padding-bottom: 24px;
47+
}
48+
49+
@media print {
50+
.button-row {
51+
display: none;
52+
}
53+
}

themes/mongodb/src/css/copy-button.css

Lines changed: 0 additions & 32 deletions
This file was deleted.

themes/mongodb/src/css/mongodb-docs.css

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -550,12 +550,17 @@ div.highlight pre {
550550
}
551551
}
552552

553-
table.docutils td div.highlight pre {
553+
table.docutils div.highlight pre {
554554
background: none;
555555
border: none;
556556
padding: 0;
557557
}
558558

559+
table.docutils .button-row {
560+
border: none;
561+
background: none;
562+
}
563+
559564
h2 + div.section,
560565
h3 + div.section,
561566
h4 + div.section {

themes/mongodb/src/js/componentCopyButtons.js

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,22 @@
11
export function setup() {
2-
const copyableBlocks = document.getElementsByClassName('copyable-code');
2+
const copyableBlocks = document.getElementsByClassName('copyable-code-block');
33
for (const copyBlock of copyableBlocks) {
44
const highlightElement = copyBlock.getElementsByClassName('highlight')[0];
55
if (!highlightElement) {
66
return;
77
}
88

9-
const text = highlightElement.innerText.trim();
10-
const copyButtonContainer = document.createElement('div');
11-
const copyButton = document.createElement('button');
12-
const copyIcon = document.createElement('span');
13-
copyButtonContainer.className = 'copy-button-container';
14-
copyIcon.className = 'fa fa-clipboard';
15-
copyButton.className = 'copy-button';
16-
copyButton.appendChild(copyIcon);
17-
copyButton.appendChild(document.createTextNode('Copy'));
18-
copyButtonContainer.appendChild(copyButton);
19-
highlightElement.insertBefore(copyButtonContainer, highlightElement.children[0]);
9+
const buttonRow = copyBlock.previousElementSibling;
10+
const copyButton = buttonRow.getElementsByClassName('code-button--copy')[0];
11+
if (!copyButton) {
12+
return;
13+
}
14+
2015
copyButton.addEventListener('click', () => {
2116
const tempElement = document.createElement('textarea');
2217
tempElement.style.position = 'fixed';
2318
document.body.appendChild(tempElement);
24-
tempElement.value = text;
19+
tempElement.value = highlightElement.innerText.trim();
2520
tempElement.select();
2621

2722
try {
@@ -30,7 +25,6 @@ export function setup() {
3025
throw new Error('Failed to copy');
3126
}
3227
} catch (err) {
33-
console.error('Failed to copy');
3428
console.error(err);
3529
}
3630

0 commit comments

Comments
 (0)