diff --git a/assets/images/icons.png b/assets/images/icons.png
index 939c9c0e..4622399c 100644
Binary files a/assets/images/icons.png and b/assets/images/icons.png differ
diff --git a/assets/images/icons@2x.png b/assets/images/icons@2x.png
index ee8cc1aa..edf961c0 100644
Binary files a/assets/images/icons@2x.png and b/assets/images/icons@2x.png differ
diff --git a/assets/javascripts/lib/util.coffee b/assets/javascripts/lib/util.coffee
index e1c2fcff..9f54e485 100644
--- a/assets/javascripts/lib/util.coffee
+++ b/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
diff --git a/assets/javascripts/news.json b/assets/javascripts/news.json
index 42944337..c2959755 100644
--- a/assets/javascripts/news.json
+++ b/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: Phalcon"
], [
diff --git a/assets/javascripts/views/content/entry_page.coffee b/assets/javascripts/views/content/entry_page.coffee
index 8c21c16d..957dddd5 100644
--- a/assets/javascripts/views/content/entry_page.coffee
+++ b/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 = ''
+
+ 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
diff --git a/assets/stylesheets/components/_content.scss b/assets/stylesheets/components/_content.scss
index 48728fc0..7f652cc0 100644
--- a/assets/stylesheets/components/_content.scss
+++ b/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;
diff --git a/assets/stylesheets/global/_base.scss b/assets/stylesheets/global/_base.scss
index 3a20b844..3988c374 100644
--- a/assets/stylesheets/global/_base.scss
+++ b/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;
diff --git a/assets/stylesheets/global/_icons.scss b/assets/stylesheets/global/_icons.scss
index 77fb1c93..113a4e3a 100644
--- a/assets/stylesheets/global/_icons.scss
+++ b/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; }
diff --git a/public/icons/ui/clipboard-white/16.png b/public/icons/ui/clipboard-white/16.png
new file mode 100644
index 00000000..f61a28eb
Binary files /dev/null and b/public/icons/ui/clipboard-white/16.png differ
diff --git a/public/icons/ui/clipboard-white/16@2x.png b/public/icons/ui/clipboard-white/16@2x.png
new file mode 100644
index 00000000..2cf04855
Binary files /dev/null and b/public/icons/ui/clipboard-white/16@2x.png differ
diff --git a/public/icons/ui/clipboard-white/SOURCE b/public/icons/ui/clipboard-white/SOURCE
new file mode 100644
index 00000000..57116488
--- /dev/null
+++ b/public/icons/ui/clipboard-white/SOURCE
@@ -0,0 +1 @@
+https://github.com/github/octicons/blob/master/svg/clippy.svg
diff --git a/public/icons/ui/clipboard/16.png b/public/icons/ui/clipboard/16.png
new file mode 100644
index 00000000..a2d7f8dd
Binary files /dev/null and b/public/icons/ui/clipboard/16.png differ
diff --git a/public/icons/ui/clipboard/16@2x.png b/public/icons/ui/clipboard/16@2x.png
new file mode 100644
index 00000000..1b24a228
Binary files /dev/null and b/public/icons/ui/clipboard/16@2x.png differ
diff --git a/public/icons/ui/clipboard/SOURCE b/public/icons/ui/clipboard/SOURCE
new file mode 100644
index 00000000..57116488
--- /dev/null
+++ b/public/icons/ui/clipboard/SOURCE
@@ -0,0 +1 @@
+https://github.com/github/octicons/blob/master/svg/clippy.svg