clipboard.js 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. import ClipboardAction from './clipboard-action';
  2. import Emitter from 'tiny-emitter';
  3. import listen from 'good-listener';
  4. /**
  5. * Base class which takes one or more elements, adds event listeners to them,
  6. * and instantiates a new `ClipboardAction` on each click.
  7. */
  8. class Clipboard extends Emitter {
  9. /**
  10. * @param {String|HTMLElement|HTMLCollection|NodeList} trigger
  11. * @param {Object} options
  12. */
  13. constructor(trigger, options) {
  14. super();
  15. this.resolveOptions(options);
  16. this.listenClick(trigger);
  17. }
  18. /**
  19. * Defines if attributes would be resolved using internal setter functions
  20. * or custom functions that were passed in the constructor.
  21. * @param {Object} options
  22. */
  23. resolveOptions(options = {}) {
  24. this.action = (typeof options.action === 'function') ? options.action : this.defaultAction;
  25. this.target = (typeof options.target === 'function') ? options.target : this.defaultTarget;
  26. this.text = (typeof options.text === 'function') ? options.text : this.defaultText;
  27. this.container = (typeof options.container === 'object') ? options.container : document.body;
  28. }
  29. /**
  30. * Adds a click event listener to the passed trigger.
  31. * @param {String|HTMLElement|HTMLCollection|NodeList} trigger
  32. */
  33. listenClick(trigger) {
  34. this.listener = listen(trigger, 'click', (e) => this.onClick(e));
  35. }
  36. /**
  37. * Defines a new `ClipboardAction` on each click event.
  38. * @param {Event} e
  39. */
  40. onClick(e) {
  41. const trigger = e.delegateTarget || e.currentTarget;
  42. if (this.clipboardAction) {
  43. this.clipboardAction = null;
  44. }
  45. this.clipboardAction = new ClipboardAction({
  46. action : this.action(trigger),
  47. target : this.target(trigger),
  48. text : this.text(trigger),
  49. container : this.container,
  50. trigger : trigger,
  51. emitter : this
  52. });
  53. }
  54. /**
  55. * Default `action` lookup function.
  56. * @param {Element} trigger
  57. */
  58. defaultAction(trigger) {
  59. return getAttributeValue('action', trigger);
  60. }
  61. /**
  62. * Default `target` lookup function.
  63. * @param {Element} trigger
  64. */
  65. defaultTarget(trigger) {
  66. const selector = getAttributeValue('target', trigger);
  67. if (selector) {
  68. return document.querySelector(selector);
  69. }
  70. }
  71. /**
  72. * Returns the support of the given action, or all actions if no action is
  73. * given.
  74. * @param {String} [action]
  75. */
  76. static isSupported(action = ['copy', 'cut']) {
  77. const actions = (typeof action === 'string') ? [action] : action;
  78. let support = !!document.queryCommandSupported;
  79. actions.forEach((action) => {
  80. support = support && !!document.queryCommandSupported(action);
  81. });
  82. return support;
  83. }
  84. /**
  85. * Default `text` lookup function.
  86. * @param {Element} trigger
  87. */
  88. defaultText(trigger) {
  89. return getAttributeValue('text', trigger);
  90. }
  91. /**
  92. * Destroy lifecycle.
  93. */
  94. destroy() {
  95. this.listener.destroy();
  96. if (this.clipboardAction) {
  97. this.clipboardAction.destroy();
  98. this.clipboardAction = null;
  99. }
  100. }
  101. }
  102. /**
  103. * Helper function to retrieve attribute value.
  104. * @param {String} suffix
  105. * @param {Element} element
  106. */
  107. function getAttributeValue(suffix, element) {
  108. const attribute = `data-clipboard-${suffix}`;
  109. if (!element.hasAttribute(attribute)) {
  110. return;
  111. }
  112. return element.getAttribute(attribute);
  113. }
  114. export default Clipboard;