Code Monkey home page Code Monkey logo

Comments (14)

vogella avatar vogella commented on July 19, 2024 4

Any plans to provide this as a default option?

from asciidoctor-extensions-lab.

minad avatar minad commented on July 19, 2024 3

The following works for me, the button will be shown for pre blocks in the top corner or just below the language. The button will be shown when hovering the pre element. I would love to see that included in asciidoctor.

<script src="assets/clipboard.js"></script>
<style>
 .listingblock:hover .clipboard {
     display: block;
 }

 .clipboard {
     display: none;
     border: 0;
     font-size: .75em;
     text-transform: uppercase;
     font-weight: 500;
     padding: 6px;
     color: #999;
     position: absolute;
     top: .425rem;
     right: .5rem;
     background: transparent;
 }

 code + .clipboard {
     top: 2rem !important;
 }

 .clipboard:hover, .clipboard:focus, .clipboard:active {
     outline: 0;
     background-color: #eee9e6;
 }
</style>
<script>
 $(function() {
     var pre = document.getElementsByTagName('pre');
     for (var i = 0; i < pre.length; i++) {
	 var b = document.createElement('button');
	 b.className = 'clipboard';
	 b.textContent = 'Copy';
         if (pre[i].childNodes.length === 1 && pre[i].childNodes[0].nodeType === 3) {
	     var div = document.createElement('div');
	     div.textContent = pre[i].textContent;
             pre[i].textContent = '';
             pre[i].appendChild(div);
         }
	 pre[i].appendChild(b);
     }
     new ClipboardJS('.clipboard', {
	 target: function(b) {
             var p = b.parentNode;
	     return p.className.includes("highlight")
                  ? p.getElementsByClassName("code")[0]
                  : p.childNodes[0];
         }
     }).on('success', function(e) {
	 e.clearSelection();
	 e.trigger.textContent = 'Copied';
	 setTimeout(function() {
	     e.trigger.textContent = 'Copy';
	 }, 2000);
     });
 });
</script>

from asciidoctor-extensions-lab.

mojavelinux avatar mojavelinux commented on July 19, 2024 3

I implemented this behavior in the default Antora UI using the built-in clipboard API of the browser. I'll share the steps for how to integrate into a standalone HTML document generated by Asciidoctor. Please note that this code is MPL-2.0.

  1. Download the script https://gitlab.com/antora/antora-ui-default/-/raw/master/src/js/06-copy-to-clipboard.js into your output directory and rename it to copy-to-clipboard.js
  2. Download the icons SVG https://gitlab.com/antora/antora-ui-default/-/raw/master/src/img/octicons-16.svg into the img folder of the output directory (i.e, img/octicons-16.svg)
  3. Add [.doc] above your document title. The script assumes that the CSS class "doc" is set on the content container.
  4. Define the document attribute :docinfo: shared-footer in the document header to enable the docinfo footer.
  5. Create the file docinfo-footer.html in the source directory (which may be the output directory) and populate it with the following contents:
<style>
.doc .listingblock > .content {
  position: relative;
}

.doc .listingblock code[data-lang]::before {
  content: none;
}

.doc .source-toolbox {
  display: flex;
  position: absolute;
  visibility: hidden;
  top: 0.25rem;
  right: 0.5rem;
  color: #808080;
  white-space: nowrap;
  font-size: 0.85em;
}

.doc .listingblock:hover .source-toolbox {
  visibility: visible;
}

.doc .source-toolbox .source-lang {
  font-family: "Droid Sans Mono", "DejaVu Sans Mono", monospace;
  text-transform: uppercase;
  letter-spacing: 0.075em;
}

.doc .source-toolbox > :not(:last-child)::after {
  content: "|";
  letter-spacing: 0;
  padding: 0 1ch;
}

.doc .source-toolbox .copy-button {
  cursor: pointer;
  display: flex;
  flex-direction: column;
  align-items: center;
  background: none;
  border: none;
  color: inherit;
  outline: none;
  padding: 0;
  font-family: inherit;
  font-size: inherit;
  line-height: inherit;
  width: 1em;
  height: 1em;
}

.doc .source-toolbox .copy-icon {
  flex: none;
  width: inherit;
  height: inherit;
  filter: invert(50.2%);
  margin-top: 0.05em;
}

.doc .source-toolbox .copy-toast {
  flex: none;
  position: relative;
  display: inline-flex;
  justify-content: center;
  margin-top: 1em;
  border-radius: 0.25em;
  padding: 0.5em;
  cursor: auto;
  opacity: 0;
  transition: opacity 0.5s ease 0.75s;
  background: rgba(0, 0, 0, 0.8);
  color: #fff;
}

.doc .source-toolbox .copy-toast::after {
  content: "";
  position: absolute;
  top: 0;
  width: 1em;
  height: 1em;
  border: 0.55em solid transparent;
  border-left-color: rgba(0, 0, 0, 0.8);
  transform: rotate(-90deg) translateX(50%) translateY(50%);
  transform-origin: left;
}

.doc .source-toolbox .copy-button.clicked .copy-toast {
  opacity: 1;
  transition: none;
}
</style>
<script src="copy-to-clipboard.js"></script>

Now convert the document using Asciidoctor.

There's a fair amount of CSS required to support this feature since it needs to be placed very specifically within the listing block and react to the interaction.

Please note that the clipboard API is not available when the file is served over http unless the host is localhost.

from asciidoctor-extensions-lab.

danyill avatar danyill commented on July 19, 2024 1

To implement the approach shown above in #61 (comment) you could probably just use a Docinfo processor but this wouldn't provide flexibility to enable and disable on particular blocks or documents which might be desirable.

from asciidoctor-extensions-lab.

mojavelinux avatar mojavelinux commented on July 19, 2024

Agreed! I especially like the "no flash" part.

We'll have to think about where to put the button because we're already using the upper right for the source language. Perhaps we can implement something like a double click to copy. That seems natural. We could put a floating hint under the listing block with the instructions to provide the hint.

Related issues:

from asciidoctor-extensions-lab.

jnerlich avatar jnerlich commented on July 19, 2024

We would really welcome this functionality. Is there a chance that this gets included in the next release?

from asciidoctor-extensions-lab.

mojavelinux avatar mojavelinux commented on July 19, 2024

I think it can be an extension, perhaps even a dedicated project. It's certainly a great addition, but not something I'm not yet comfortable putting into core. Though we are planning to add it to Antora (see https://gitlab.com/antora/antora-ui-default/issues/70).

from asciidoctor-extensions-lab.

jnerlich avatar jnerlich commented on July 19, 2024

@mojavelinux thanks for the answer.

from asciidoctor-extensions-lab.

xstefank avatar xstefank commented on July 19, 2024

Hi, is there any progress on this, please?

from asciidoctor-extensions-lab.

danyill avatar danyill commented on July 19, 2024

If you use asciidoctorj you could look at the Puravida extension and also the documentation. The way the extension works is shown in the docs.

In this case it's been implemented as a PostProcessor with resources added directly to the output of the processing. It could be implemented in a bunch of different ways but to get similar effect perhaps a Docinfo Processor and a PostProcessor would be one way.

from asciidoctor-extensions-lab.

chuck-confluent avatar chuck-confluent commented on July 19, 2024

The following works for me, the button will be shown for pre blocks in the top corner or just below the language. The button will be shown when hovering the pre element. I would love to see that included in asciidoctor.

<script src="assets/clipboard.js"></script>
<style>
 .listingblock:hover .clipboard {
     display: block;
 }

 .clipboard {
     display: none;
     border: 0;
     font-size: .75em;
     text-transform: uppercase;
     font-weight: 500;
     padding: 6px;
     color: #999;
     position: absolute;
     top: .425rem;
     right: .5rem;
     background: transparent;
 }

 code + .clipboard {
     top: 2rem !important;
 }

 .clipboard:hover, .clipboard:focus, .clipboard:active {
     outline: 0;
     background-color: #eee9e6;
 }
</style>
<script>
 $(function() {
     var pre = document.getElementsByTagName('pre');
     for (var i = 0; i < pre.length; i++) {
	 var b = document.createElement('button');
	 b.className = 'clipboard';
	 b.textContent = 'Copy';
         if (pre[i].childNodes.length === 1 && pre[i].childNodes[0].nodeType === 3) {
	     var div = document.createElement('div');
	     div.textContent = pre[i].textContent;
             pre[i].textContent = '';
             pre[i].appendChild(div);
         }
	 pre[i].appendChild(b);
     }
     new ClipboardJS('.clipboard', {
	 target: function(b) {
             var p = b.parentNode;
	     return p.className.includes("highlight")
                  ? p.getElementsByClassName("code")[0]
                  : p.childNodes[0];
         }
     }).on('success', function(e) {
	 e.clearSelection();
	 e.trigger.textContent = 'Copied';
	 setTimeout(function() {
	     e.trigger.textContent = 'Copy';
	 }, 2000);
     });
 });
</script>

@minad Pardon my ignorance of web dev, but I tried pasting the above snippet into the <head> section of an html file rendered from asciidoctor just to see what would happen, and I wasn't able to get it to work. I made a local clipboard.js file from the contents here and changed <script src="assets/clipboard.js"> to just <script src="clipboard.js"> since it's all in the same directory. It didn't work for me. I'm sure I'm missing something embarrassingly simple, but I just wanted a quick proof of concept.

Could you explain how to get this to work to a web dev novice?

from asciidoctor-extensions-lab.

schonbachler avatar schonbachler commented on July 19, 2024

Here is a slightly adapted variant, which works for me. You have to provide clipboard.min.js in the assets folder.

<script src="assets/clipboard.min.js"></script>
<style>
    .listingblock:hover .clipboard {
        display: block;
    }

    .clipboard {
        display: none;
        border: 0;
        font-size: .75em;
        text-transform: uppercase;
        font-weight: 500;
        padding: 6px;
        color: #999;
        position: absolute;
        top: .425rem;
        right: .5rem;
        background: transparent;
    }

    code + .clipboard {
        top: 2rem !important;
    }

    .clipboard:hover, .clipboard:focus, .clipboard:active {
        outline: 0;
        background-color: #eee9e6;
    }
</style>
<script >
    window.onload = function() {
        var pre = document.getElementsByTagName('pre');
        for (var i = 0; i < pre.length; i++) {
            var b = document.createElement('button');
            b.className = 'clipboard';
            b.textContent = 'Copy';
            if (pre[i].childNodes.length === 1 && pre[i].childNodes[0].nodeType === 3) {
                var div = document.createElement('div');
                div.textContent = pre[i].textContent;
                pre[i].textContent = '';
                pre[i].appendChild(div);
            }
            pre[i].appendChild(b);
        }
        var clipboard = new ClipboardJS('.clipboard', {
           target: function(b) {
                var p = b.parentNode;
                if (p.className.includes("highlight")) {
                    var elems = p.getElementsByTagName("code");
                    if (elems.length > 0)
                        return elems[0];
                }
                return p.childNodes[0];
            }
        });
        clipboard.on('success', function(e) {
            e.clearSelection();
            e.trigger.textContent = 'Copied';
            setTimeout(function() {
                e.trigger.textContent = 'Copy';
            }, 2000);
        });
        clipboard.on('error', function(e) {
            console.error('Action:', e.action, e);
            console.error('Trigger:', e.trigger);
        });
    };
</script>

from asciidoctor-extensions-lab.

AshkanV avatar AshkanV commented on July 19, 2024

Thanks to you all. I modified the code a little to be more like AsciiDoctor website layout, and I also add a rotation animation instead of copied text:

<script src="assets/clipboard.min.js"></script>
<style>
    .listingblock code[data-lang]::before {
        display: none;
        content: attr(data-lang) " |";
        position: absolute;
        font-size: 0.75em;
        top: 0.425rem;
        right: 1.7rem;
        line-height: 1;
        text-transform: uppercase;
        color: inherit;
        opacity: 0.5
    }
    
    .listingblock:hover code[data-lang]::before {
        display: block
    }

    .listingblock:hover .clipboard {
        display: block;
    }

    .clipboard {
        display: none;
        content: "  ";
        position: absolute;
        top: 0.3rem;
        right: 0.5em;
        height: 1em;
        color: inherit;
        border: none;
        opacity: 0.5;
        cursor: pointer;
        filter: invert(50.2%);
        background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' width='16' height='16'%3E%3Cpath fill-rule='evenodd' d='M5.75 1a.75.75 0 00-.75.75v3c0 .414.336.75.75.75h4.5a.75.75 0 00.75-.75v-3a.75.75 0 00-.75-.75h-4.5zm.75 3V2.5h3V4h-3zm-2.874-.467a.75.75 0 00-.752-1.298A1.75 1.75 0 002 3.75v9.5c0 .966.784 1.75 1.75 1.75h8.5A1.75 1.75 0 0014 13.25v-9.5a1.75 1.75 0 00-.874-1.515.75.75 0 10-.752 1.298.25.25 0 01.126.217v9.5a.25.25 0 01-.25.25h-8.5a.25.25 0 01-.25-.25v-9.5a.25.25 0 01.126-.217z'%3E%3C/path%3E%3C/svg%3E") no-repeat;
    }

    @keyframes clibpard_rotation_frame {
        50% { transform: rotateY(180deg); }
    }

    .clipboard_success {
        filter: invert(100%);
        animation: clibpard_rotation_frame 1s;
    }
</style>

<script >
    window.onload = function() {
        var pre = document.getElementsByTagName('pre');

        for (var i = 0; i < pre.length; i++) {
            var b = document.createElement('button');
            b.className = 'clipboard';
            b.textContent = ' ';
            if (pre[i].childNodes.length === 1 && pre[i].childNodes[0].nodeType === 3) {
                var div = document.createElement('div');
                div.textContent = pre[i].textContent;
                pre[i].textContent = '';
                pre[i].appendChild(div);
            }
            pre[i].appendChild(b);
        }

        var clipboard = new ClipboardJS('.clipboard', {
           target: function(b) {
                var p = b.parentNode;
                if (p.className.includes("highlight")) {
                    var elems = p.getElementsByTagName("code");
                    if (elems.length > 0)
                        return elems[0];
                }
                return p.childNodes[0];
            }
        });

        clipboard.on('success', function(e) {
            e.clearSelection();
            e.trigger.classList.add('clipboard_success');
            setTimeout(function() {
                e.trigger.classList.remove('clipboard_success');
            }, 1300);
        });

        clipboard.on('error', function(e) {
            console.error('Action:', e.action, e);
            console.error('Trigger:', e.trigger);
        });
    };
</script>

from asciidoctor-extensions-lab.

mojavelinux avatar mojavelinux commented on July 19, 2024

I've gone ahead and added this extension to the lab.

from asciidoctor-extensions-lab.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.