986ba5dc828ebbf16abc97a25d70b2e4fb405d239dfebf6862cbc1ff173818391e0b0cf42f80e72b1e47a0c0a481ad62c8deeb065e24e97514a7d0965a5809 3.3 KB

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