소스 검색

Add "Copy to clipboard" icon inside each code block

Closes #253.
Thibaut 10 년 전
부모
커밋
a37e9d87cf

BIN
assets/images/icons.png


BIN
assets/images/icons@2x.png


+ 15 - 0
assets/javascripts/lib/util.coffee

@@ -292,3 +292,18 @@ $.highlight = (el, options = {}) ->
   el.classList.add(options.className)
   setTimeout (-> el.classList.remove(options.className)), options.delay
   return
+
+$.copyToClipboard = (string) ->
+  textarea = document.createElement('textarea')
+  textarea.style.position = 'fixed'
+  textarea.style.opacity = 0
+  textarea.value = string
+  document.body.appendChild(textarea)
+  try
+    textarea.select()
+    result = !!document.execCommand('copy')
+  catch
+    result = false
+  finally
+    document.body.removeChild(textarea)
+  result

+ 3 - 0
assets/javascripts/news.json

@@ -1,5 +1,8 @@
 [
   [
+    "2015-10-18",
+    "Added a \"Copy to clipboard\" button inside each code block."
+  ], [
     "2015-09-13",
     "New documentation: <a href=\"/phalcon/\">Phalcon</a>"
   ], [

+ 14 - 1
assets/javascripts/views/content/entry_page.coffee

@@ -35,6 +35,14 @@ class app.views.EntryPage extends app.View
       @hiddenView = new app.views.HiddenPage @el, @entry
 
     @trigger 'loaded'
+    @delay @addClipboardLinks
+    return
+
+  CLIPBOARD_LINK = '<a class="_pre-clip" title="Copy to clipboard"></a>'
+
+  addClipboardLinks: =>
+    for el in @findAllByTag('pre')
+      el.insertAdjacentHTML('afterbegin', CLIPBOARD_LINK)
     return
 
   LINKS =
@@ -118,7 +126,12 @@ class app.views.EntryPage extends app.View
       true
 
   onClick: (event) =>
-    if event.target.hasAttribute 'data-retry'
+    target = event.target
+    if target.hasAttribute 'data-retry'
       $.stopEvent(event)
       @load()
+    else if target.classList.contains '_pre-clip'
+      $.stopEvent(event)
+      target.classList.add if $.copyToClipboard(target.parentNode.textContent) then '_pre-clip-success' else '_pre-clip-error'
+      setTimeout (-> target.className = '_pre-clip'), 2000
     return

+ 28 - 0
assets/stylesheets/components/_content.scss

@@ -396,6 +396,34 @@
 ._label { @extend %label; }
 ._highlight { background: $highlightBackground !important; }
 
+._pre-clip {
+  display: none;
+  position: absolute;
+  top: 0;
+  right: 0;
+  opacity: .5;
+  padding: .375rem;
+  cursor: pointer;
+
+  pre:hover > & { display: block; }
+  &:hover { opacity: 1; }
+
+  @if $style == 'dark' {
+    &:before { @extend %icon, %icon-clipboard-white; }
+  } @else {
+    &:before { @extend %icon, %icon-clipboard; }
+  }
+
+  &._pre-clip-success, &._pre-clip-error {
+    &:before { display: none; }
+    &:after {
+      content: 'Copied';
+      padding-right: .25rem;
+    }
+  }
+  &._pre-clip-error:after { content: 'Error'; }
+}
+
 ._github-btn {
   display: inline-block;
   vertical-align: text-top;

+ 2 - 1
assets/stylesheets/global/_base.scss

@@ -99,8 +99,9 @@ pre, code, samp, %pre, %code {
 }
 
 pre, %pre {
+  position: relative;
   margin: 1.5em 0;
-  padding: .375rem .75rem;
+  padding: .375rem .625rem;
   line-height: 1.5;
   overflow: auto;
   @extend %box;

+ 2 - 0
assets/stylesheets/global/_icons.scss

@@ -113,3 +113,5 @@
 %icon-contract-white        { background-position: -9rem -8rem; }
 ._icon-react_native:before  { background-position: 0 -9rem; }
 ._icon-phalcon:before       { background-position: -1rem -9rem; }
+%icon-clipboard             { background-position: -2rem -9rem; }
+%icon-clipboard-white       { background-position: -3rem -9rem; }

BIN
public/icons/ui/clipboard-white/16.png


BIN
public/icons/ui/clipboard-white/16@2x.png


+ 1 - 0
public/icons/ui/clipboard-white/SOURCE

@@ -0,0 +1 @@
+https://github.com/github/octicons/blob/master/svg/clippy.svg

BIN
public/icons/ui/clipboard/16.png


BIN
public/icons/ui/clipboard/16@2x.png


+ 1 - 0
public/icons/ui/clipboard/SOURCE

@@ -0,0 +1 @@
+https://github.com/github/octicons/blob/master/svg/clippy.svg