From af2e8001e51f04ef15c8542b225db08b6672f5bf Mon Sep 17 00:00:00 2001 From: Peter Bacon Darwin Date: Wed, 20 Jan 2016 12:07:00 +0000 Subject: [PATCH] feat(app): add and use `copy-button` and `copy-container` directives Closes #728 and issue #720 This change let's users click on a button to automatically copy a code block to the clipboard to make it easier to follow the guides and tutorials. --- public/_includes/_head-include.jade | 2 +- public/_includes/_scripts-include.jade | 10 ++-- public/resources/images/icons/clippy.svg | 3 + .../resources/js/directives/code-example.js | 18 ++++-- public/resources/js/directives/code-pane.js | 10 ++-- public/resources/js/directives/copy.js | 60 +++++++++++++++++++ public/resources/js/vendor/clipboard.min.js | 7 +++ 7 files changed, 97 insertions(+), 13 deletions(-) create mode 100644 public/resources/images/icons/clippy.svg create mode 100644 public/resources/js/directives/copy.js create mode 100755 public/resources/js/vendor/clipboard.min.js diff --git a/public/_includes/_head-include.jade b/public/_includes/_head-include.jade index 42ba8c424a..2e46febe96 100644 --- a/public/_includes/_head-include.jade +++ b/public/_includes/_head-include.jade @@ -34,7 +34,7 @@ meta(itemprop="description" content="#{description}") meta(itemprop="image" content="https://angular.io/resources/images/logos/standard/shield-large.png") link(rel="icon" type="image/x-icon" href="/resources/images/icons/favicon.ico") -link(rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/angular_material/0.8.3/angular-material.min.css") +link(rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/angular_material/1.0.0/angular-material.min.css") link(href="https://fonts.googleapis.com/css?family=Roboto:400,300,500,400italic,700" rel='stylesheet' type='text/css') link(href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet") link(rel="stylesheet" href="/resources/css/vendor/icomoon/style.css") diff --git a/public/_includes/_scripts-include.jade b/public/_includes/_scripts-include.jade index b916ec74ef..2449222ad0 100644 --- a/public/_includes/_scripts-include.jade +++ b/public/_includes/_scripts-include.jade @@ -3,13 +3,14 @@ script(src="/resources/js/vendor/prettify.js") script(src="/resources/js/vendor/lang-basic.js") script(src="/resources/js/vendor/lang-dart.js") script(src="/resources/js/vendor/lodash.js") +script(src="/resources/js/vendor/clipboard.min.js") -script(src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js") -script(src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular-animate.min.js") -script(src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular-aria.min.js") -script(src="https://ajax.googleapis.com/ajax/libs/angular_material/0.8.3/angular-material.min.js") +script(src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js") +script(src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular-animate.min.js") +script(src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular-aria.min.js") +script(src="https://ajax.googleapis.com/ajax/libs/angular_material/1.0.0/angular-material.min.js") @@ -21,6 +22,7 @@ script(src="/resources/js/directives/api-list.js") script(src="/resources/js/directives/bio.js") script(src="/resources/js/directives/bold.js") script(src="/resources/js/directives/code.js") +script(src="/resources/js/directives/copy.js") script(src="/resources/js/directives/code-tabs.js") script(src="/resources/js/directives/code-pane.js") script(src="/resources/js/directives/code-example.js") diff --git a/public/resources/images/icons/clippy.svg b/public/resources/images/icons/clippy.svg new file mode 100644 index 0000000000..e1b1703590 --- /dev/null +++ b/public/resources/images/icons/clippy.svg @@ -0,0 +1,3 @@ + + + diff --git a/public/resources/js/directives/code-example.js b/public/resources/js/directives/code-example.js index 05fc80ff7e..98882d2cb2 100644 --- a/public/resources/js/directives/code-example.js +++ b/public/resources/js/directives/code-example.js @@ -13,9 +13,12 @@ angularIO.directive('codeExample', function() { var html = (attrs.escape === "html") ? _.escape(tElement.html()) : tElement.html(); var classes = 'prettyprint ' + attrs.format + ' lang-' + attrs.language + (attrs.showcase === 'true' ? ' is-showcase' : ''); - var template = '
' +
-                      '' + html + '' +
-                      '
'; + var template = + '' + + '
' +
+            '' + html + '' +
+          '
' + + '
'; // UPDATE ELEMENT WITH NEW TEMPLATE tElement.html(template); @@ -24,4 +27,11 @@ angularIO.directive('codeExample', function() { return function(scope, element, attrs) {}; } }; -}); \ No newline at end of file +}); + + // '
' + + // '' + + // '
' +
+        //     '' + html + '' +
+        //   '
' + + // '
'; diff --git a/public/resources/js/directives/code-pane.js b/public/resources/js/directives/code-pane.js index 6acaddd42b..aafdacc3c5 100644 --- a/public/resources/js/directives/code-pane.js +++ b/public/resources/js/directives/code-pane.js @@ -15,10 +15,12 @@ angularIO.directive('codePane', function() { compile: function(tElement, tAttrs) { var html = (tAttrs.escape === "html") ? _.escape(tElement.html()) : tElement.html(); - var template = '
' +
-                      '' + html + '' +
-                      '
'; - + var template = + '' + + '
' +
+          '' + html + '' +
+          '
' + + '
'; // UPDATE ELEMENT WITH NEW TEMPLATE tElement.html(template); diff --git a/public/resources/js/directives/copy.js b/public/resources/js/directives/copy.js new file mode 100644 index 0000000000..013f75ec54 --- /dev/null +++ b/public/resources/js/directives/copy.js @@ -0,0 +1,60 @@ +/** + * A directive that adds a copy button to a block of text + * Wrap this directive (as an element) around a block of text that you wish to be + * copyable. + * The directive will add a copy button positioned to float in the top right corner + * of the block of text. + * + * This directive is used in the `code-example` and `code-pane` directives. + * + * @example + * + * ```html + * + *
+ *   
+ *   SomeBlockOfCode();
+ *   
+ * 
+ *
+ * ``` + */ +angularIO.directive('copyContainer', function() { + return { + restrict: 'E', + transclude: true, + template: + '
' + + '' + + '' + + '
' + }; +}); + + +/** + * A directive that creates a copy button that will copy the contents of the element that follows + * it. The element containing the content can contain dynamic content itself (e.g. ``) + * but the content element itself most be available at link time. + */ +angularIO.directive('copyButton', function() { + return { + restrict: 'E', + template: + '\n' + + ' \n' + + ' Copy to Clipboard\n' + + '', + link: function link(scope, element) { + var contentElement = element.next(); + var clipboard = new Clipboard(element[0], { + text: function() { + console.log('clicked', contentElement[0].innerText); + return contentElement[0].innerText; } + }); + scope.$on('$destroy', function() { + clipboard.destroy(); + }); + } + }; +}); \ No newline at end of file diff --git a/public/resources/js/vendor/clipboard.min.js b/public/resources/js/vendor/clipboard.min.js new file mode 100755 index 0000000000..4e2a012a64 --- /dev/null +++ b/public/resources/js/vendor/clipboard.min.js @@ -0,0 +1,7 @@ +/*! + * clipboard.js v1.5.5 + * https://zenorocha.github.io/clipboard.js + * + * Licensed MIT © Zeno Rocha + */ +!function(t){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=t();else if("function"==typeof define&&define.amd)define([],t);else{var e;e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,e.Clipboard=t()}}(function(){var t,e,n;return function t(e,n,r){function o(a,c){if(!n[a]){if(!e[a]){var s="function"==typeof require&&require;if(!c&&s)return s(a,!0);if(i)return i(a,!0);var u=new Error("Cannot find module '"+a+"'");throw u.code="MODULE_NOT_FOUND",u}var l=n[a]={exports:{}};e[a][0].call(l.exports,function(t){var n=e[a][1][t];return o(n?n:t)},l,l.exports,t,e,n,r)}return n[a].exports}for(var i="function"==typeof require&&require,a=0;ar;r++)n[r].fn.apply(n[r].ctx,e);return this},off:function(t,e){var n=this.e||(this.e={}),r=n[t],o=[];if(r&&e)for(var i=0,a=r.length;a>i;i++)r[i].fn!==e&&r[i].fn._!==e&&o.push(r[i]);return o.length?n[t]=o:delete n[t],this}},e.exports=r},{}],8:[function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}function o(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}n.__esModule=!0;var i=function(){function t(t,e){for(var n=0;n