drag.js 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. #ifdef 0
  2. /* This Source Code Form is subject to the terms of the Mozilla Public
  3. * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  4. * You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. #endif
  6. /**
  7. * This singleton implements site dragging functionality.
  8. */
  9. var gDrag = {
  10. /**
  11. * The site offset to the drag start point.
  12. */
  13. _offsetX: null,
  14. _offsetY: null,
  15. /**
  16. * The site that is dragged.
  17. */
  18. _draggedSite: null,
  19. get draggedSite() { return this._draggedSite; },
  20. /**
  21. * The cell width/height at the point the drag started.
  22. */
  23. _cellWidth: null,
  24. _cellHeight: null,
  25. get cellWidth() { return this._cellWidth; },
  26. get cellHeight() { return this._cellHeight; },
  27. /**
  28. * Start a new drag operation.
  29. * @param aSite The site that's being dragged.
  30. * @param aEvent The 'dragstart' event.
  31. */
  32. start: function(aSite, aEvent) {
  33. this._draggedSite = aSite;
  34. // Mark nodes as being dragged.
  35. let selector = ".newtab-site, .newtab-control, .newtab-thumbnail";
  36. let parentCell = aSite.node.parentNode;
  37. let nodes = parentCell.querySelectorAll(selector);
  38. for (let i = 0; i < nodes.length; i++)
  39. nodes[i].setAttribute("dragged", "true");
  40. parentCell.setAttribute("dragged", "true");
  41. this._setDragData(aSite, aEvent);
  42. // Store the cursor offset.
  43. let node = aSite.node;
  44. let rect = node.getBoundingClientRect();
  45. this._offsetX = aEvent.clientX - rect.left;
  46. this._offsetY = aEvent.clientY - rect.top;
  47. // Store the cell dimensions.
  48. let cellNode = aSite.cell.node;
  49. this._cellWidth = cellNode.offsetWidth;
  50. this._cellHeight = cellNode.offsetHeight;
  51. gTransformation.freezeSitePosition(aSite);
  52. },
  53. /**
  54. * Handles the 'drag' event.
  55. * @param aSite The site that's being dragged.
  56. * @param aEvent The 'drag' event.
  57. */
  58. drag: function(aSite, aEvent) {
  59. // Get the viewport size.
  60. let {clientWidth, clientHeight} = document.documentElement;
  61. // We'll want a padding of 5px.
  62. let border = 5;
  63. // Enforce minimum constraints to keep the drag image inside the window.
  64. let left = Math.max(scrollX + aEvent.clientX - this._offsetX, border);
  65. let top = Math.max(scrollY + aEvent.clientY - this._offsetY, border);
  66. // Enforce maximum constraints to keep the drag image inside the window.
  67. left = Math.min(left, scrollX + clientWidth - this.cellWidth - border);
  68. top = Math.min(top, scrollY + clientHeight - this.cellHeight - border);
  69. // Update the drag image's position.
  70. gTransformation.setSitePosition(aSite, {left: left, top: top});
  71. },
  72. /**
  73. * Ends the current drag operation.
  74. * @param aSite The site that's being dragged.
  75. * @param aEvent The 'dragend' event.
  76. */
  77. end: function(aSite, aEvent) {
  78. let nodes = gGrid.node.querySelectorAll("[dragged]")
  79. for (let i = 0; i < nodes.length; i++)
  80. nodes[i].removeAttribute("dragged");
  81. // Slide the dragged site back into its cell (may be the old or the new cell).
  82. gTransformation.slideSiteTo(aSite, aSite.cell, {unfreeze: true});
  83. this._draggedSite = null;
  84. },
  85. /**
  86. * Checks whether we're responsible for a given drag event.
  87. * @param aEvent The drag event to check.
  88. * @return Whether we should handle this drag and drop operation.
  89. */
  90. isValid: function(aEvent) {
  91. let link = gDragDataHelper.getLinkFromDragEvent(aEvent);
  92. // Check that the drag data is non-empty.
  93. // Can happen when dragging places folders.
  94. if (!link || !link.url) {
  95. return false;
  96. }
  97. // Check that we're not accepting URLs which would inherit the caller's
  98. // principal (such as javascript: or data:).
  99. return gLinkChecker.checkLoadURI(link.url);
  100. },
  101. /**
  102. * Initializes the drag data for the current drag operation.
  103. * @param aSite The site that's being dragged.
  104. * @param aEvent The 'dragstart' event.
  105. */
  106. _setDragData: function(aSite, aEvent) {
  107. let {url, title} = aSite;
  108. let dt = aEvent.dataTransfer;
  109. dt.mozCursor = "default";
  110. dt.effectAllowed = "move";
  111. dt.setData("text/plain", url);
  112. dt.setData("text/uri-list", url);
  113. dt.setData("text/x-moz-url", url + "\n" + title);
  114. dt.setData("text/html", "<a href=\"" + url + "\">" + url + "</a>");
  115. // Create and use an empty drag element. We don't want to use the default
  116. // drag image with its default opacity.
  117. let dragElement = document.createElementNS(HTML_NAMESPACE, "div");
  118. dragElement.classList.add("newtab-drag");
  119. let scrollbox = document.getElementById("newtab-vertical-margin");
  120. scrollbox.appendChild(dragElement);
  121. dt.setDragImage(dragElement, 0, 0);
  122. // After the 'dragstart' event has been processed we can remove the
  123. // temporary drag element from the DOM.
  124. setTimeout(() => scrollbox.removeChild(dragElement), 0);
  125. }
  126. };