editHyperlinks.js 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. /**
  2. * Copyright (C) 2013 KO GmbH <copyright@kogmbh.com>
  3. *
  4. * @licstart
  5. * This file is part of WebODF.
  6. *
  7. * WebODF is free software: you can redistribute it and/or modify it
  8. * under the terms of the GNU Affero General Public License (GNU AGPL)
  9. * as published by the Free Software Foundation, either version 3 of
  10. * the License, or (at your option) any later version.
  11. *
  12. * WebODF is distributed in the hope that it will be useful, but
  13. * WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU Affero General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Affero General Public License
  18. * along with WebODF. If not, see <http://www.gnu.org/licenses/>.
  19. * @licend
  20. *
  21. * @source: http://www.webodf.org/
  22. * @source: https://github.com/kogmbh/WebODF/
  23. */
  24. /*global define,require,document,odf */
  25. define("webodf/editor/widgets/editHyperlinks", [
  26. "webodf/editor/EditorSession",
  27. "webodf/editor/widgets/dialogWidgets/editHyperlinkPane",
  28. "dijit/form/Button",
  29. "dijit/form/DropDownButton",
  30. "dijit/TooltipDialog"],
  31. function (EditorSession, EditHyperlinkPane, Button, DropDownButton, TooltipDialog) {
  32. "use strict";
  33. runtime.loadClass("odf.OdfUtils");
  34. var EditHyperlinks = function (callback) {
  35. var self = this,
  36. widget = {},
  37. editorSession,
  38. hyperlinkController,
  39. linkEditorContent,
  40. editHyperlinkButton,
  41. removeHyperlinkButton,
  42. odfUtils = new odf.OdfUtils(),
  43. textSerializer = new odf.TextSerializer(),
  44. dialog;
  45. /**
  46. * @param {!Range} selection
  47. * @return {!string}
  48. */
  49. function getTextContent(selection) {
  50. var document = selection.startContainer.ownerDocument,
  51. fragmentContainer = document.createElement('span');
  52. fragmentContainer.appendChild(selection.cloneContents());
  53. return textSerializer.writeToString(fragmentContainer);
  54. }
  55. function updateLinkEditorContent() {
  56. var selection = editorSession.getSelectedRange(),
  57. linksInSelection = editorSession.getSelectedHyperlinks(),
  58. linkTarget = linksInSelection[0] ? odfUtils.getHyperlinkTarget(linksInSelection[0]) : "http://";
  59. if (selection && selection.collapsed && linksInSelection.length === 1) {
  60. // Selection is collapsed within a single hyperlink. Assume user is modifying the hyperlink
  61. linkEditorContent.set({
  62. linkDisplayText: textSerializer.writeToString(linksInSelection[0]),
  63. linkUrl: linkTarget,
  64. isReadOnlyText: true
  65. });
  66. } else if (selection && !selection.collapsed) {
  67. // User has selected part of a hyperlink or a block of text. Assume user is attempting to modify the
  68. // existing hyperlink, or wants to convert the selection into a hyperlink
  69. linkEditorContent.set({
  70. linkDisplayText: getTextContent(selection),
  71. linkUrl: linkTarget,
  72. isReadOnlyText: true
  73. });
  74. } else {
  75. // Selection is collapsed and is not in an existing hyperlink
  76. linkEditorContent.set({
  77. linkDisplayText: "",
  78. linkUrl: linkTarget,
  79. isReadOnlyText: false
  80. });
  81. }
  82. }
  83. function checkHyperlinkButtons() {
  84. var linksInSelection = editorSession.getSelectedHyperlinks();
  85. // The 3rd parameter is false to avoid firing onChange when setting the value programmatically.
  86. removeHyperlinkButton.set('disabled', linksInSelection.length === 0, false);
  87. }
  88. function enableHyperlinkButtons(isEnabled) {
  89. widget.children.forEach(function (element) {
  90. element.setAttribute('disabled', !isEnabled);
  91. });
  92. }
  93. function updateSelectedLink(hyperlinkData) {
  94. var selection = editorSession.getSelectedRange(),
  95. selectionController = editorSession.sessionController.getSelectionController(),
  96. selectedLinkRange,
  97. linksInSelection = editorSession.getSelectedHyperlinks();
  98. if (hyperlinkData.isReadOnlyText == "true") {
  99. if (selection && selection.collapsed && linksInSelection.length === 1) {
  100. // Editing the single link the cursor is currently within
  101. selectedLinkRange = selection.cloneRange();
  102. selectedLinkRange.selectNode(linksInSelection[0]);
  103. selectionController.selectRange(selectedLinkRange, true)
  104. }
  105. hyperlinkController.removeHyperlinks();
  106. hyperlinkController.addHyperlink(hyperlinkData.linkUrl);
  107. } else {
  108. hyperlinkController.addHyperlink(hyperlinkData.linkUrl, hyperlinkData.linkDisplayText);
  109. linksInSelection = editorSession.getSelectedHyperlinks();
  110. selectedLinkRange = selection.cloneRange();
  111. selectedLinkRange.selectNode(linksInSelection[0]);
  112. selectionController.selectRange(selectedLinkRange, true)
  113. }
  114. }
  115. this.setEditorSession = function (session) {
  116. if (editorSession) {
  117. editorSession.unsubscribe(EditorSession.signalCursorMoved, checkHyperlinkButtons);
  118. editorSession.unsubscribe(EditorSession.signalParagraphChanged, checkHyperlinkButtons);
  119. editorSession.unsubscribe(EditorSession.signalParagraphStyleModified, checkHyperlinkButtons);
  120. hyperlinkController.unsubscribe(gui.HyperlinkController.enabledChanged, enableHyperlinkButtons);
  121. }
  122. editorSession = session;
  123. if (editorSession) {
  124. hyperlinkController = editorSession.sessionController.getHyperlinkController();
  125. editorSession.subscribe(EditorSession.signalCursorMoved, checkHyperlinkButtons);
  126. editorSession.subscribe(EditorSession.signalParagraphChanged, checkHyperlinkButtons);
  127. editorSession.subscribe(EditorSession.signalParagraphStyleModified, checkHyperlinkButtons);
  128. hyperlinkController.subscribe(gui.HyperlinkController.enabledChanged, enableHyperlinkButtons);
  129. enableHyperlinkButtons(hyperlinkController.isEnabled());
  130. checkHyperlinkButtons();
  131. } else {
  132. enableHyperlinkButtons( false );
  133. }
  134. };
  135. this.onToolDone = function () {};
  136. function init() {
  137. textSerializer.filter = new odf.OdfNodeFilter();
  138. linkEditorContent = new EditHyperlinkPane();
  139. dialog = new TooltipDialog({
  140. title: runtime.tr("Edit link"),
  141. content: linkEditorContent.widget(),
  142. onShow: updateLinkEditorContent
  143. });
  144. editHyperlinkButton = new DropDownButton({
  145. label: runtime.tr('Edit link'),
  146. showLabel: false,
  147. disabled: true,
  148. iconClass: 'dijitEditorIcon dijitEditorIconCreateLink',
  149. dropDown: dialog
  150. });
  151. removeHyperlinkButton = new Button({
  152. label: runtime.tr('Remove link'),
  153. showLabel: false,
  154. disabled: true,
  155. iconClass: 'dijitEditorIcon dijitEditorIconUnlink',
  156. onClick: function () {
  157. hyperlinkController.removeHyperlinks();
  158. self.onToolDone();
  159. }
  160. });
  161. linkEditorContent.onSave = function () {
  162. var hyperlinkData = linkEditorContent.value();
  163. editHyperlinkButton.closeDropDown(false);
  164. updateSelectedLink(hyperlinkData);
  165. self.onToolDone();
  166. };
  167. linkEditorContent.onCancel = function () {
  168. editHyperlinkButton.closeDropDown(false);
  169. self.onToolDone();
  170. };
  171. widget.children = [editHyperlinkButton, removeHyperlinkButton];
  172. widget.startup = function () {
  173. widget.children.forEach(function (element) {
  174. element.startup();
  175. });
  176. };
  177. widget.placeAt = function (container) {
  178. widget.children.forEach(function (element) {
  179. element.placeAt(container);
  180. });
  181. return widget;
  182. };
  183. callback(widget);
  184. }
  185. init();
  186. };
  187. return EditHyperlinks;
  188. });