Index: TXM/trunk/bundles/org.txm.rcp/src/main/java/org/txm/rcp/editors/TXMBrowserEditor.java
===================================================================
--- TXM/trunk/bundles/org.txm.rcp/src/main/java/org/txm/rcp/editors/TXMBrowserEditor.java	(revision 3903)
+++ TXM/trunk/bundles/org.txm.rcp/src/main/java/org/txm/rcp/editors/TXMBrowserEditor.java	(revision 3904)
@@ -43,6 +43,7 @@
 import org.eclipse.swt.events.MenuEvent;
 import org.eclipse.swt.events.MenuListener;
 import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.MouseListener;
 import org.eclipse.swt.events.MouseWheelListener;
 import org.eclipse.swt.events.SelectionEvent;
 import org.eclipse.swt.events.SelectionListener;
@@ -52,6 +53,7 @@
 import org.eclipse.swt.widgets.MenuItem;
 import org.eclipse.ui.internal.browser.BrowserViewer;
 import org.eclipse.ui.internal.browser.WebBrowserEditor;
+import org.txm.rcp.commands.OpenBrowser;
 import org.txm.rcp.commands.ShowSelected;
 import org.txm.rcp.editors.menu.PagePropertiesMenu;
 import org.txm.rcp.messages.TXMUIMessages;
@@ -107,7 +109,6 @@
 	 */
 	public void initializeProgressListener() {
 		
-		
 		ProgressListener progresslistener = new ProgressListener() {
 			
 			@Override
@@ -123,6 +124,11 @@
 					}
 					cmdLink = new CommandLink(TXMBrowserEditor.this, TXMBrowserEditor.this.getBrowser());
 				}
+				
+				TXMBrowserEditor.this.getBrowser().execute("""
+						document.addEventListener('mouseover', function (e) {
+						   document.currentHoverElement = e.target
+						});	""");
 			}
 		};
 		getBrowser().addProgressListener(progresslistener);
@@ -143,10 +149,10 @@
 	public static void zoom(Browser b, float diff) {
 		
 		if (b == null || b.isDisposed()) return;
-
-	//	b.evaluate("alert(document);");
-	//	b.evaluate("alert(document.children[0].style);");
-//		b.evaluate("alert(document.children[0].children[1]);");
+		
+		//	b.evaluate("alert(document);");
+		//	b.evaluate("alert(document.children[0].style);");
+		//		b.evaluate("alert(document.children[0].children[1]);");
 		boolean isHTML = (boolean) b.evaluate("return document.getElementsByTagName('body')[0] != null;"); //$NON-NLS-1$
 		if (isHTML) {
 			String zoom = (String) b.evaluate("return document.getElementsByTagName('body')[0].style.zoom;"); //$NON-NLS-1$
@@ -175,6 +181,18 @@
 		}
 	}
 	
+	MenuItem sep1;
+	MenuItem copyItem;
+	MenuItem copyLink;
+	MenuItem openLink;
+	MenuItem zoomInItem;
+	MenuItem zoomOutItem;
+	MenuItem zoomResetItem;
+	MenuItem reloadItem;
+	MenuItem backItem;
+	MenuItem forwardItem;
+	MenuItem propertiesItem;
+	
 	public void initMenu() {
 		
 		// create a new menu
@@ -189,115 +207,156 @@
 				
 				Menu menu = menuManager.getMenu();
 				if (menu == null) return;
-				new MenuItem(menu, SWT.SEPARATOR);
 				
-				MenuItem copyItem = new MenuItem(menu, SWT.NONE);
-				copyItem.setText(TXMUIMessages.Copy);
-				copyItem.addSelectionListener(new SelectionListener() {
+				if (sep1 == null) {
 					
-					@Override
-					public void widgetSelected(SelectionEvent e) {
+					sep1 = new MenuItem(menu, SWT.SEPARATOR);
+					
+					copyItem = new MenuItem(menu, SWT.NONE);
+					copyItem.setText(TXMUIMessages.Copy);
+					copyItem.addSelectionListener(new SelectionListener() {
 						
-						String text = TXMBrowserEditor.this.getTextSelection();
-						if (text != null && text.length() > 0) {
-							IOClipboard.write(text);
+						@Override
+						public void widgetSelected(SelectionEvent e) {
+							
+							String text = TXMBrowserEditor.this.getTextSelection();
+							if (text != null && text.length() > 0) {
+								IOClipboard.write(text);
+							}
 						}
-					}
+						
+						@Override
+						public void widgetDefaultSelected(SelectionEvent e) {}
+					});
 					
-					@Override
-					public void widgetDefaultSelected(SelectionEvent e) {}
-				});
-				String text = TXMBrowserEditor.this.getTextSelection();
-				copyItem.setEnabled(text != null && text.length() > 0);
-				
-				MenuItem zoomInItem = new MenuItem(menu, SWT.NONE);
-				zoomInItem.setText(TXMUIMessages.zoomIn);
-				zoomInItem.addSelectionListener(new SelectionListener() {
+					openLink = new MenuItem(menu, SWT.NONE);
+					openLink.setText("Open link");
+					openLink.addSelectionListener(new SelectionListener() {
+						
+						@Override
+						public void widgetSelected(SelectionEvent e) {
+							
+							Object currentHref = TXMBrowserEditor.this.getBrowser().evaluate("return document.currentHoverElement.getAttribute('href')");
+							if (currentHref != null) {
+								OpenBrowser.openfile(currentHref.toString());
+							}
+						}
+						
+						@Override
+						public void widgetDefaultSelected(SelectionEvent e) {}
+					});
 					
-					@Override
-					public void widgetSelected(SelectionEvent e) {
-						zoomIn(getBrowser());
-					}
-					
-					@Override
-					public void widgetDefaultSelected(SelectionEvent e) {}
-				});
-				
-				MenuItem zoomOutItem = new MenuItem(menu, SWT.NONE);
-				zoomOutItem.setText(TXMUIMessages.zoomOut);
-				zoomOutItem.addSelectionListener(new SelectionListener() {
-					
-					@Override
-					public void widgetSelected(SelectionEvent e) {
+					copyLink = new MenuItem(menu, SWT.NONE);
+					copyLink.setText("Copy link");
+					copyLink.addSelectionListener(new SelectionListener() {
 						
-						zoomOut(getBrowser());
-					}
+						@Override
+						public void widgetSelected(SelectionEvent e) {
+							
+							Object currentHref = TXMBrowserEditor.this.getBrowser().evaluate("return document.currentHoverElement.getAttribute('href')");
+							if (currentHref != null) {
+								IOClipboard.write(currentHref.toString());
+							}
+						}
+						
+						@Override
+						public void widgetDefaultSelected(SelectionEvent e) {}
+					});
 					
-					@Override
-					public void widgetDefaultSelected(SelectionEvent e) {}
-				});
-				
-				MenuItem zoomResetItem = new MenuItem(menu, SWT.NONE);
-				zoomResetItem.setText(TXMUIMessages.initialZoom);
-				zoomResetItem.addSelectionListener(new SelectionListener() {
-					
-					@Override
-					public void widgetSelected(SelectionEvent e) {
+					zoomInItem = new MenuItem(menu, SWT.NONE);
+					zoomInItem.setText(TXMUIMessages.zoomIn);
+					zoomInItem.addSelectionListener(new SelectionListener() {
 						
-						zoomReset(getBrowser());
-					}
+						@Override
+						public void widgetSelected(SelectionEvent e) {
+							zoomIn(getBrowser());
+						}
+						
+						@Override
+						public void widgetDefaultSelected(SelectionEvent e) {}
+					});
 					
-					@Override
-					public void widgetDefaultSelected(SelectionEvent e) {}
-				});
-				
-				MenuItem reloadItem = new MenuItem(menu, SWT.NONE);
-				reloadItem.setText(TXMUIMessages.Reload);
-				reloadItem.addSelectionListener(new SelectionListener() {
-					
-					@Override
-					public void widgetSelected(SelectionEvent e) {
+					zoomOutItem = new MenuItem(menu, SWT.NONE);
+					zoomOutItem.setText(TXMUIMessages.zoomOut);
+					zoomOutItem.addSelectionListener(new SelectionListener() {
 						
-						TXMBrowserEditor.this.getBrowser().refresh();
-					}
+						@Override
+						public void widgetSelected(SelectionEvent e) {
+							
+							zoomOut(getBrowser());
+						}
+						
+						@Override
+						public void widgetDefaultSelected(SelectionEvent e) {}
+					});
 					
-					@Override
-					public void widgetDefaultSelected(SelectionEvent e) {}
-				});
-				MenuItem backItem = new MenuItem(menu, SWT.NONE);
-				backItem.setText(TXMUIMessages.Back);
-				backItem.addSelectionListener(new SelectionListener() {
-					
-					@Override
-					public void widgetSelected(SelectionEvent e) {
+					zoomResetItem = new MenuItem(menu, SWT.NONE);
+					zoomResetItem.setText(TXMUIMessages.initialZoom);
+					zoomResetItem.addSelectionListener(new SelectionListener() {
 						
-						TXMBrowserEditor.this.getBrowser().back();
-					}
+						@Override
+						public void widgetSelected(SelectionEvent e) {
+							
+							zoomReset(getBrowser());
+						}
+						
+						@Override
+						public void widgetDefaultSelected(SelectionEvent e) {}
+					});
 					
-					@Override
-					public void widgetDefaultSelected(SelectionEvent e) {}
-				});
-				MenuItem forwardItem = new MenuItem(menu, SWT.NONE);
-				forwardItem.setText(TXMUIMessages.Forward);
-				forwardItem.addSelectionListener(new SelectionListener() {
-					
-					@Override
-					public void widgetSelected(SelectionEvent e) {
+					reloadItem = new MenuItem(menu, SWT.NONE);
+					reloadItem.setText(TXMUIMessages.Reload);
+					reloadItem.addSelectionListener(new SelectionListener() {
 						
-						TXMBrowserEditor.this.getBrowser().forward();
-					}
+						@Override
+						public void widgetSelected(SelectionEvent e) {
+							
+							TXMBrowserEditor.this.getBrowser().refresh();
+						}
+						
+						@Override
+						public void widgetDefaultSelected(SelectionEvent e) {}
+					});
+					backItem = new MenuItem(menu, SWT.NONE);
+					backItem.setText(TXMUIMessages.Back);
+					backItem.addSelectionListener(new SelectionListener() {
+						
+						@Override
+						public void widgetSelected(SelectionEvent e) {
+							
+							TXMBrowserEditor.this.getBrowser().back();
+						}
+						
+						@Override
+						public void widgetDefaultSelected(SelectionEvent e) {}
+					});
+					forwardItem = new MenuItem(menu, SWT.NONE);
+					forwardItem.setText(TXMUIMessages.Forward);
+					forwardItem.addSelectionListener(new SelectionListener() {
+						
+						@Override
+						public void widgetSelected(SelectionEvent e) {
+							
+							TXMBrowserEditor.this.getBrowser().forward();
+						}
+						
+						@Override
+						public void widgetDefaultSelected(SelectionEvent e) {}
+					});
 					
-					@Override
-					public void widgetDefaultSelected(SelectionEvent e) {}
-				});
+					propertiesItem = new PagePropertiesMenu(getBrowser(), menu, SWT.NONE);
+				}
 				
-				MenuItem propertiesItem = new PagePropertiesMenu(getBrowser(), menu, SWT.NONE);
+				String dom = TXMBrowserEditor.this.getTextSelectionDOM();
+				copyItem.setEnabled(dom != null && dom.length() > 0);
+				
+				Object currentHref = TXMBrowserEditor.this.getBrowser().evaluate("return document.currentHoverElement.getAttribute('href')");
+				copyLink.setEnabled(currentHref != null);
+				openLink.setEnabled(currentHref != null);
 			}
 			
 			@Override
-			public void menuHidden(MenuEvent e) {
-				// TODO Auto-generated method stub
-			}
+			public void menuHidden(MenuEvent e) { }
 		});
 		// // restore old listeners
 		// Menu origMenu = this.browser.getMenu();
@@ -317,194 +376,7 @@
 		// replace the menu
 		this.getBrowser().setMenu(menu);
 	}
-	
-	//	/**
-	//	 * Sets the edition.
-	//	 *
-	//	 * @param edition the new edition
-	//	 */
-	//	public void setEdition(Edition edition) {
-	//		this.edition = edition;
-	//	}
-	
-	//	/**
-	//	 * Make page label.
-	//	 *
-	//	 * @return the string
-	//	 */
-	//	public String makePageLabel() {
-	//		return currentPage.getName()
-	//				+ " / " + currentPage.getEdition().getNumPages(); //$NON-NLS-1$
-	//	}
-	//	
-	//	/**
-	//	 * Show page.
-	//	 *
-	//	 * @param page the page
-	//	 */
-	//	public void showPage(Page page) {
-	//		edition = page.getEdition();
-	//		currentPage = page;
-	//		this.webBrowser.setURL(currentPage.toURL());
-	//		page_label.setText(makePageLabel());
-	//	}
-	
-	//	/**
-	//	 * First text.
-	//	 */
-	//	public void firstText() {
-	//		Text current = this.currentPage.getEdition().getText();
-	//		Project corpus = current.getProject();
-	//		Text firstText = corpus.getFirstText();
-	//		
-	//		if (firstText != null) {
-	//			String editionName = corpus.getDefaultEditionName();
-	//			currentPage = firstText.getEdition(editionName).getFirstPage();
-	//			if (currentPage == null) {
-	//				StatusLine.setMessage(TXMUIMessages.noPreviousText);
-	//				return;
-	//			}
-	//			this.setEdition(firstText.getEdition(editionName));
-	//			this.webBrowser.setURL(currentPage.toURL());
-	//			page_label.setText(makePageLabel());
-	//		}
-	//	}
-	//	
-	//	/**
-	//	 * Last text.
-	//	 */
-	//	public void lastText() {
-	//		Text current = this.currentPage.getEdition().getText();
-	//		Project b = current.getProject();
-	//		Text lastText = b.getLastText();
-	//		
-	//		if (lastText != null) {
-	//			currentPage = lastText.getEdition(b.getDefaultEditionName()).getFirstPage();
-	//			if (currentPage == null) {
-	//				StatusLine.setMessage(TXMUIMessages.noTextNext);
-	//				return;
-	//			}
-	//			this.setEdition(lastText.getEdition(b.getDefaultEditionName()));
-	//			this.webBrowser.setURL(currentPage.toURL());
-	//			page_label.setText(makePageLabel());
-	//		}
-	//	}
-	//	
-	//	/**
-	//	 * First page.
-	//	 */
-	//	public void firstPage() {
-	//		// System.out.println(Messages.TxmBrowser_1+currentPage);
-	//		currentPage = edition.getFirstPage();
-	//		this.webBrowser.setURL(currentPage.toURL());
-	//		page_label.setText(makePageLabel());
-	//	}
-	//	
-	//	/**
-	//	 * Last page.
-	//	 */
-	//	public void lastPage() {
-	//		// System.out.println(Messages.TxmBrowser_2+currentPage);
-	//		
-	//		if (currentPage != null && currentPage.getFile().equals(edition.getLastPage().getFile()))
-	//			return;
-	//		currentPage = edition.getLastPage();
-	//		this.webBrowser.setURL(currentPage.toURL());
-	//		page_label.setText(makePageLabel());
-	//	}
-	//	
-	//	/**
-	//	 * Previous page.
-	//	 */
-	//	public void previousPage() {
-	//		// System.out.println(Messages.TxmBrowser_3+currentPage);
-	//		if (currentPage != null) {
-	//			Page previous = edition.getPreviousPage(currentPage);
-	//			if (previous == currentPage) {
-	//				previousText(true);
-	//			}
-	//			else {
-	//				currentPage = previous;
-	//				this.webBrowser.setURL(currentPage.toURL());
-	//			}
-	//		}
-	//		else
-	//			firstPage();
-	//		page_label.setText(makePageLabel());
-	//	}
-	//	
-	//	/**
-	//	 * Next page.
-	//	 */
-	//	public void nextPage() {
-	//		// System.out.println(Messages.TxmBrowser_4+currentPage);
-	//		if (currentPage != null) {
-	//			Page next = edition.getNextPage(currentPage);
-	//			if (currentPage == next) {
-	//				nextText();
-	//			}
-	//			else {
-	//				currentPage = next;
-	//				this.webBrowser.setURL(currentPage.toURL());
-	//			}
-	//			
-	//		}
-	//		else
-	//			firstPage();
-	//		page_label.setText(makePageLabel());
-	//	}
-	//	
-	//	/**
-	//	 * Previous text.
-	//	 * 
-	//	 * @param fromNextText
-	//	 */
-	//	public void previousText(boolean fromNextText) {
-	//		
-	//		Text current = this.currentPage.getEdition().getText();
-	//		Project corpus = current.getProject();
-	//		Text previousText = corpus.getPreviousText(current);
-	//		
-	//		if (previousText != null) {
-	//			String editionName = corpus.getDefaultEditionName();
-	//			if (fromNextText) {
-	//				currentPage = previousText.getEdition(editionName).getLastPage();
-	//			}
-	//			else {
-	//				currentPage = previousText.getEdition(editionName).getFirstPage();
-	//			}
-	//			if (currentPage == null) {
-	//				StatusLine.setMessage(TXMUIMessages.noPreviousText);
-	//				return;
-	//			}
-	//			this.setEdition(previousText.getEdition(editionName));
-	//			this.webBrowser.setURL(currentPage.toURL());
-	//			page_label.setText(makePageLabel());
-	//		}
-	//		// System.out.println("Previous texts "+previousText);
-	//	}
-	//	
-	//	/**
-	//	 * Next text.
-	//	 */
-	//	public void nextText() {
-	//		Text current = this.currentPage.getEdition().getText();
-	//		Project b = current.getProject();
-	//		Text nextText = b.getNextText(current);
-	//		
-	//		if (nextText != null) {
-	//			currentPage = nextText.getEdition(b.getDefaultEditionName()).getFirstPage();
-	//			if (currentPage == null) {
-	//				StatusLine.setMessage(TXMUIMessages.noTextNext);
-	//				return;
-	//			}
-	//			this.setEdition(nextText.getEdition(b.getDefaultEditionName()));
-	//			this.webBrowser.setURL(currentPage.toURL());
-	//			page_label.setText(makePageLabel());
-	//		}
-	//		// System.out.println("Next texts "+nextText);
-	//	}
-	
+		
 	public static void installZoomControls(Browser browser, Menu menu) {
 		
 		browser.addMouseWheelListener(new MouseWheelListener() {
@@ -522,7 +394,7 @@
 			}
 		});
 		
-
+		
 		MenuItem zoomInItem = new MenuItem(menu, SWT.NONE);
 		zoomInItem.setText(TXMUIMessages.zoomIn);
 		zoomInItem.addSelectionListener(new SelectionListener() {
@@ -777,6 +649,22 @@
 		
 		initMenu();
 		
+//		getBrowser().addMouseListener(new MouseListener() {
+//			
+//			@Override
+//			public void mouseUp(MouseEvent e) { }
+//			
+//			@Override
+//			public void mouseDown(MouseEvent e) { }
+//			
+//			@Override
+//			public void mouseDoubleClick(MouseEvent e) {
+//				
+//				Browser b = TXMBrowserEditor.this.webBrowser.getBrowser();
+//				b.evaluate(SCRIPT01)
+//			}
+//		});
+		
 		getBrowser().addMouseWheelListener(new MouseWheelListener() {
 			
 			@Override
Index: TXM/trunk/bundles/org.txm.edition.rcp/src/org/txm/edition/rcp/handlers/OpenEdition.java
===================================================================
--- TXM/trunk/bundles/org.txm.edition.rcp/src/org/txm/edition/rcp/handlers/OpenEdition.java	(revision 3903)
+++ TXM/trunk/bundles/org.txm.edition.rcp/src/org/txm/edition/rcp/handlers/OpenEdition.java	(revision 3904)
@@ -34,6 +34,7 @@
 import org.eclipse.core.commands.AbstractHandler;
 import org.eclipse.core.commands.ExecutionEvent;
 import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.jface.viewers.ISelection;
 import org.eclipse.jface.viewers.IStructuredSelection;
 import org.eclipse.osgi.util.NLS;
 import org.eclipse.ui.IWorkbenchPage;
@@ -68,7 +69,12 @@
 	@Override
 	public Object execute(ExecutionEvent event) throws ExecutionException {
 		
-		IStructuredSelection selection = (IStructuredSelection) HandlerUtil.getCurrentSelection(event);
+		ISelection isel = HandlerUtil.getCurrentSelection(event);
+		
+		if (isel == null) return null;
+		if (!(isel instanceof IStructuredSelection)) return null;
+		
+		IStructuredSelection selection = (IStructuredSelection) isel;
 		if (selection.getFirstElement() instanceof CQPCorpus) {
 			try {
 				CQPCorpus c = (CQPCorpus) selection.getFirstElement();
Index: TXM/trunk/bundles/org.txm.edition.rcp/src/org/txm/edition/rcp/editors/SearchEditionToolbar.java
===================================================================
--- TXM/trunk/bundles/org.txm.edition.rcp/src/org/txm/edition/rcp/editors/SearchEditionToolbar.java	(revision 3903)
+++ TXM/trunk/bundles/org.txm.edition.rcp/src/org/txm/edition/rcp/editors/SearchEditionToolbar.java	(revision 3904)
@@ -197,7 +197,7 @@
 	}
 
 	protected void openConcordance() {
-		System.out.println(NLS.bind(EditionUIMessages.OpeningConcordancesOfQueryP0, this.searchText.getQuery()));
+		Log.info(NLS.bind(EditionUIMessages.OpeningConcordancesOfQueryP0, this.searchText.getQuery()));
 	}
 
 	protected void closeSearch() {
Index: TXM/trunk/bundles/org.txm.edition.rcp/src/org/txm/edition/rcp/editors/EditionPanel.java
===================================================================
--- TXM/trunk/bundles/org.txm.edition.rcp/src/org/txm/edition/rcp/editors/EditionPanel.java	(revision 3903)
+++ TXM/trunk/bundles/org.txm.edition.rcp/src/org/txm/edition/rcp/editors/EditionPanel.java	(revision 3904)
@@ -45,6 +45,7 @@
 import org.txm.objects.Project;
 import org.txm.objects.Text;
 import org.txm.rcp.StatusLine;
+import org.txm.rcp.commands.OpenBrowser;
 import org.txm.rcp.editors.CommandLink;
 import org.txm.rcp.editors.TXMBrowserEditor;
 import org.txm.rcp.editors.menu.PagePropertiesMenu;
@@ -53,76 +54,76 @@
 import org.txm.utils.logger.Log;
 
 public class EditionPanel extends BrowserViewer implements ISelectionProvider {
-
+	
 	private ProgressListener progressListener;
-
+	
 	// private List<String> wordids;
 	// private List<String> lineids;
 	/** The edition. */
 	Text currentText;
-
+	
 	String editionName;
-
+	
 	Edition currentEdition;
-
+	
 	Page currentPage;
-
+	
 	protected SynopticEditionEditor synopticEditionEditor;
-
+	
 	private ISelectionProvider selProvider;
-
+	
 	private MenuManager menuManager;
-
+	
 	private HashSet<int[]> highlightedAreas = null;
-
+	
 	// HashMap<String, ArrayList<RGBA>> highlightedColorSpans = new HashMap<String, ArrayList<RGBA>>(); // background color
-
+	
 	HashMap<String, ArrayList<RGBA>> highlightedColorPerWordIDS = new HashMap<>(); // background color
-
+	
 	public static final String STYLE_NORMAL = "normal"; //$NON-NLS-1$
-
+	
 	public static final String STYLE_ITALIC = "italic"; //$NON-NLS-1$
-
+	
 	public static final String STYLE_OBLIQUE = "oblique"; //$NON-NLS-1$
-
+	
 	HashMap<String, String> fontStylePerWordIDS = new HashMap<>();
-
+	
 	public static final String WEIGHT_NORMAL = "normal"; //$NON-NLS-1$
-
+	
 	public static final String WEIGHT_BOLD = "bold"; //$NON-NLS-1$
-
+	
 	HashMap<String, String> fontWeightPerWordIDS = new HashMap<>();
-
+	
 	HashMap<String, ArrayList<RGBA>> fontColorPerWordIDS = new HashMap<>();
-
+	
 	public static final String SIZE_SMALL = "small"; //$NON-NLS-1$
-
+	
 	public static final String SIZE_MEDIUM = "medium"; //$NON-NLS-1$
-
+	
 	public static final String SIZE_LARGE = "larger"; //$NON-NLS-1$
-
+	
 	public static final String SIZE_SMALLER = "smaller"; //$NON-NLS-1$
-
+	
 	public static final String SIZE_LARGER = "larger"; //$NON-NLS-1$
-
+	
 	HashMap<String, String> fontSizePerWordIDS = new HashMap<>();
-
+	
 	public static final String FAMILLY_TIMES = "\"Times New Roman\", Times"; //$NON-NLS-1$
-
+	
 	public static final String FAMILLY_ARIAL = "Arial"; //$NON-NLS-1$
-
+	
 	public static final String FAMILLY_COURIER = "\"Courier New\", Courier"; //$NON-NLS-1$
-
+	
 	HashMap<String, String> fontFamillyPerWordIDS = new HashMap<>();
-
+	
 	public static final String VARIANT_NORMAL = "normal"; //$NON-NLS-1$
-
+	
 	public static final String VARIANT_SMALLCAPS = "small-caps"; //$NON-NLS-1$
-
+	
 	HashMap<String, String> fontVariantPerWordIDS = new HashMap<>();
-
+	
 	String focusedWordID = null;
-
+	
 	public static final String highlightscript = "try { var elt = document.getElementById(\"%s\");" + //$NON-NLS-1$
 			"elt.style.backgroundColor=\"rgb(%s,%s,%s)\";" + //$NON-NLS-1$
 			// "elt.style.paddingLeft=\"3px\";" + //$NON-NLS-1$
@@ -130,26 +131,26 @@
 			// "elt.style.paddingTop=\"1px\";" + //$NON-NLS-1$
 			// "elt.style.paddingBottom=\"1px\";" + //$NON-NLS-1$
 			"} catch (e) { };"; //$NON-NLS-1$
-
+	
 	public static final String highlightscriptRuleFast = "sheet.insertRule(\"#%s {background-color:rgba(%s,%s,%s,%s);}\", 0);"; //$NON-NLS-1$
-
+	
 	public static final String colorscriptRuleFast = "sheet.insertRule(\"#%s {color:rgba(%s,%s,%s,%s);}\", 0);"; //$NON-NLS-1$
-
+	
 	public static final String sizescriptRuleFast = "sheet.insertRule(\"#%s {font-size:%s;}\", 0);"; //$NON-NLS-1$
-
+	
 	public static final String stylescriptRuleFast = "sheet.insertRule(\"#%s {font-style:%s;}\", 0);"; //$NON-NLS-1$
-
+	
 	public static final String variantscriptRuleFast = "sheet.insertRule(\"#%s {font-variant:%s;}\", 0);"; //$NON-NLS-1$
-
+	
 	public static final String famillyscriptRuleFast = "sheet.insertRule(\"#%s {font-familly:%s;}\", 0);"; //$NON-NLS-1$
-
+	
 	public static final String weightscriptRuleFast = "sheet.insertRule(\"#%s {font-weight:%s;}\", 0);"; //$NON-NLS-1$
-
+	
 	public static final String highlightscriptRule = "sheet.insertRule(\"span[id=\\\"%s\\\"] {background-color:rgba(%s,%s,%s,%s); }\", 0);"; //$NON-NLS-1$
-
+	
 	public static final String clearhighlightscript = "try { var elt = document.getElementById(\"%s\"); elt.style.backgroundColor=\"white\";elt.style.fontWeight=\"\";" + //$NON-NLS-1$
 			"} catch (e) { };"; //$NON-NLS-1$
-
+	
 	public String functions = ""// "alert(\"loading functions\");" //$NON-NLS-1$
 			+ "\ngetNodeText = function getNodeText(node) {" //$NON-NLS-1$
 			+ "\n	if (typeof node == 'string') return node;" //$NON-NLS-1$
@@ -261,31 +262,31 @@
 			+ "\n	};" //$NON-NLS-1$
 			+ "\n}" //$NON-NLS-1$
 			+ "\n} catch(e) {Element.prototype.scrollIntoViewIfNeeded = Element.prototype.scrollIntoView}"; //$NON-NLS-1$
-
+	
 	protected boolean fastWordHighLight = SynopticEditionPreferences.getInstance().getBoolean(SynopticEditionPreferences.FAST_HIGHLIGHT);
-
+	
 	private ArrayList<ProgressListener> beforeHighlighListeners;
-
+	
 	public ArrayList<ProgressListener> getBeforeHighlighListeners() {
-
+		
 		return beforeHighlighListeners;
 	}
-
+	
 	private ArrayList<ProgressListener> afterHighlighListeners;
-
+	
 	private CommandLink cmdLink;
-
+	
 	private EditionLink editionLink;
-
+	
 	public ArrayList<ProgressListener> getAfterHighlighListeners() {
-
+		
 		return beforeHighlighListeners;
 	}
-
+	
 	public Object evaluate(String code) {
-
+		
 		if (Log.getLevel().intValue() <= Level.FINEST.intValue()) System.out.println(code);
-
+		
 		try {
 			if (getBrowser() == null) return null;
 			return getBrowser().evaluate(code);
@@ -297,9 +298,9 @@
 		}
 		return null;
 	}
-
+	
 	public boolean execute(String code) {
-
+		
 		if (Log.getLevel().intValue() <= Level.FINEST.intValue()) System.out.println(code);
 		try {
 			//System.out.println("EXECUTE: "+code.replace("\n", " RET ").subSequence(0, Math.min(200, code.length())));
@@ -311,15 +312,15 @@
 		}
 		return false;
 	}
-
+	
 	public EditionPanel(SynopticEditionEditor synopticEditionEditor, Composite parent, int style, String editionName) {
-
+		
 		super(parent, style);
 		this.synopticEditionEditor = synopticEditionEditor;
 		this.editionName = editionName;
 		// this.currentEdition = edition;
 		// this.currentText = currentEdition.getText();
-
+		
 		File functionsFile = null;
 		try {
 			Bundle bundle = Platform.getBundle("org.txm.edition.rcp"); //$NON-NLS-1$
@@ -332,10 +333,10 @@
 			Log.severe(EditionUIMessages.bind(EditionUIMessages.error_while_readingP0P1, functionsFile, e.getLocalizedMessage()));
 			Log.printStackTrace(e);
 		}
-
+		
 		beforeHighlighListeners = new ArrayList<>();
 		afterHighlighListeners = new ArrayList<>();
-
+		
 		//		this.browser.addLocationListener(new LocationListener() {
 		//			
 		//			@Override
@@ -351,10 +352,10 @@
 		//				if (editionLink != null) cmdLink.dispose();
 		//			}
 		//		});
-
-
+		
+		
 		this.addDisposeListener(new DisposeListener() { // clean the BrowserFunction s
-
+			
 			@Override
 			public void widgetDisposed(DisposeEvent e) {
 				//				System.out.println("dispose listener called");
@@ -363,7 +364,7 @@
 				if (browser!= null && !browser.isDisposed()) browser.dispose();
 			}
 		});
-
+		
 		if (cmdLink == null) {
 			cmdLink = new CommandLink(synopticEditionEditor, browser);
 		}
@@ -388,15 +389,15 @@
 		//				editionLink = new EditionLink(synopticEditionEditor, browser);
 		//			}
 		//		});
-
+		
 		progressListener = new ProgressListener() {
-
+			
 			@Override
 			public void changed(ProgressEvent event) {}
-
+			
 			@Override
 			public synchronized void completed(ProgressEvent event) {
-
+				
 				Browser browser = getBrowser();
 				Object o = browser.evaluate("return typeof " + CommandLink.FCT + ";"); //$NON-NLS-1$ //$NON-NLS-2$
 				if ("undefined".equals(o)) { //$NON-NLS-1$
@@ -414,9 +415,14 @@
 					editionLink = new EditionLink(synopticEditionEditor, browser);
 					//System.out.println("rebuild editionLink");
 				}
-
-
-
+				
+				EditionPanel.this.getBrowser().execute("""
+						document.addEventListener('mouseover', function (e) {
+						   document.currentHoverElement = e.target
+						});	""");
+				
+				
+				
 				Object rez = evaluate("return typeof sheet;"); //$NON-NLS-1$
 				if ("undefined".equals(rez)) { //$NON-NLS-1$
 					Object loadResult = evaluate(functions);
@@ -428,12 +434,12 @@
 						Log.finer("JS functions loaded."); //$NON-NLS-1$
 					}
 				}
-
+				
 				// do something before the highlight is done
 				for (ProgressListener pl : beforeHighlighListeners) {
 					pl.completed(event);
 				}
-
+				
 				// System.out.println("highlight: "+highlightedColorPerWordIDS);
 				StringBuilder buffer = new StringBuilder();
 				// buffer.append("alert(\"\"+sheet);\n");
@@ -445,18 +451,18 @@
 				else {
 					buffer.append("try { while(sheet.cssRules.length > 0) sheet.deleteRule(0); } catch (e) {};\n"); // empty style //$NON-NLS-1$
 				}
-
+				
 				if (buffer.length() > 0) {
 					if (!execute(buffer.toString())) {
 						Log.fine("JS execution error (delete cssRules) with=" + buffer); //$NON-NLS-1$
 					}
 				}
-
-
+				
+				
 				buffer = new StringBuilder();
 				Log.finest("EditionPanel " + currentEdition + " reload " + currentPage); //$NON-NLS-1$ //$NON-NLS-2$
 				if (currentPage != null && currentEdition != null) { // avoid null pointer
-
+					
 					String firstWord = currentPage.getWordId();
 					Page nextPage = currentEdition.getNextPage(currentPage);
 					String lastWord = "w_999999999"; //$NON-NLS-1$
@@ -475,11 +481,11 @@
 					// System.out.println("firstWord="+firstWord+" lastWord="+lastWord);
 					// int n = 0;
 					// long start = System.currentTimeMillis();
-
+					
 					for (String wordid : highlightedColorPerWordIDS.keySet()) {
 						// Log.finest("words to highlight: "+highlightedColorPerWordIDS);
 						if (highlightedColorPerWordIDS.get(wordid).size() == 0) continue; // error
-
+						
 						// if (!slowWordHighLight) { //TODO: this code must be replaced with word position instead of word id comparaison
 						if (Edition.isFirstGTthanSecond(wordid, firstWord) < 0) continue; // skip the word to highlight
 						if (Edition.isFirstGTthanSecond(lastWord, wordid) < 0) continue; // skip the word to highlight
@@ -487,18 +493,18 @@
 						// n++;
 						RGBA composite = new RGBA(0, 0, 0, 0f);
 						int size = highlightedColorPerWordIDS.get(wordid).size();
-
+						
 						for (RGBA color : highlightedColorPerWordIDS.get(wordid)) {
 							composite.r += color.r;
 							composite.g += color.g;
 							composite.b += color.b;
 							composite.a += color.a;
 						}
-
+						
 						composite.r /= size;
 						composite.g /= size;
 						composite.b /= size;
-
+						
 						String s = null;
 						if (!fastWordHighLight) {
 							// s = String.format(highlightscriptRule, wordid, composite.r, composite.g, composite.b, composite.a);
@@ -515,20 +521,20 @@
 							s = String.format(highlightscriptRuleFast, wordid.replace(" ", "\\ "), composite.r, composite.g, composite.b, composite.a); //$NON-NLS-1$ //$NON-NLS-2$
 							// s = String.format(highlightscriptRuleFast, wordid, composite.r, composite.g, composite.b, composite.a);
 						}
-
+						
 						buffer.append(s + "\n"); //$NON-NLS-1$
 					}
 				}
-
+				
 				if (buffer.length() > 0) {
 					if (!execute(buffer.toString())) {
 						Log.fine("JS execution (highlight) error with=" + buffer); //$NON-NLS-1$
 					}
 				}
-
-
+				
+				
 				buffer = new StringBuilder();
-
+				
 				// for (String wordidslist : highlightedColorSpans.keySet()) {
 				// RGBA composite = new RGBA(0,0,0,0f);
 				// int size = highlightedColorSpans.get(wordidslist).size();
@@ -548,40 +554,40 @@
 				// cmd += "wrap(l, \""+wordidslist+"\";\n";
 				// buffer.append(cmd+"\n");
 				// }
-
+				
 				for (String wordid : fontColorPerWordIDS.keySet()) {
 					RGBA composite = new RGBA(0, 0, 0, 0f);
 					int size = fontColorPerWordIDS.get(wordid).size();
-
+					
 					for (RGBA color : fontColorPerWordIDS.get(wordid)) {
 						composite.r += color.r;
 						composite.g += color.g;
 						composite.b += color.b;
 						composite.a += color.a;
 					}
-
+					
 					composite.r /= size;
 					composite.g /= size;
 					composite.b /= size;
-
+					
 					String s = String.format(colorscriptRuleFast, wordid, composite.r, composite.g, composite.b, composite.a);
 					buffer.append(s + "\n"); //$NON-NLS-1$
 				}
-
+				
 				if (buffer.length() > 0) {
 					if (!execute(buffer.toString())) {
 						Log.fine("JS execution (color) error with=" + buffer); //$NON-NLS-1$
 					}
 				}
-
-
+				
+				
 				buffer = new StringBuilder();
-
+				
 				for (String wordid : fontSizePerWordIDS.keySet()) {
 					String s = String.format(sizescriptRuleFast, wordid, fontSizePerWordIDS.get(wordid));
 					buffer.append(s + "\n"); //$NON-NLS-1$
 				}
-
+				
 				for (String wordid : fontWeightPerWordIDS.keySet()) {
 					String s = null;
 					if (!fastWordHighLight) {
@@ -607,28 +613,28 @@
 					}
 					buffer.append(s + "\n"); //$NON-NLS-1$
 				}
-
+				
 				for (String wordid : fontFamillyPerWordIDS.keySet()) {
 					String s = String.format(famillyscriptRuleFast, wordid, fontFamillyPerWordIDS.get(wordid));
 					buffer.append(s + "\n"); //$NON-NLS-1$
 				}
-
+				
 				if (buffer.length() > 0) {
 					if (!execute(buffer.toString())) {
 						Log.fine("JS execution (font) error with=" + buffer); //$NON-NLS-1$
 					}
 				}
-
-
+				
+				
 				buffer = new StringBuilder();
-
+				
 				if (focusedWordID != null) {
 					// System.out.println("Focus on: "+focusedWordID);
 					String s = "try { showElementIfNeeded(document.getElementById(\"" + focusedWordID + "\")); } catch (e) {document.getElementById(\"" + focusedWordID + "\").scrollIntoView();};"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
 					//String s = "document.getElementById(\"" + focusedWordID + "\").scrollIntoView();"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
 					buffer.append(s + "\n"); //$NON-NLS-1$
 				}
-
+				
 				if (buffer.length() > 0) {
 					//Object rez2 = execute(buffer.toString());
 					if (execute(buffer.toString())) {
@@ -638,9 +644,9 @@
 						Log.fine("JS execution (focus) error with script=" + buffer); //$NON-NLS-1$
 					}
 				}
-
+				
 				buffer = new StringBuilder();
-
+				
 				if (highlightedAreas != null) {
 					for (int[] pos : highlightedAreas) {
 						if (pos == null || pos.length != 4) continue;
@@ -649,7 +655,7 @@
 						break;// one word only for now
 					}
 				}
-
+				
 				// System.out.println(buffer);
 				if (buffer.length() > 0) {
 					if (!execute(buffer.toString())) {
@@ -657,49 +663,49 @@
 					}
 				}
 				// System.out.println("n="+n+" time="+(System.currentTimeMillis()-start));
-
+				
 				// do something after the highlight is done
 				for (ProgressListener pl : afterHighlighListeners) {
 					pl.completed(event);
 				}
 			}
 		};
-
+		
 		getBrowser().addMouseListener(new MouseListener() {
-
+			
 			boolean dblClick = false;
-
+			
 			boolean debug = true;
-
+			
 			private int t, x, y;
-
+			
 			@Override
 			public void mouseDoubleClick(MouseEvent e) {
-
+				
 				if (debug) Log.finest("DOUBLE CLICK"); //$NON-NLS-1$
 				dblClick = true;
 			}
-
+			
 			@Override
 			public void mouseDown(MouseEvent e) {
-
+				
 				if (debug) Log.finest("MOUSE DOWN"); //$NON-NLS-1$
 				dblClick = false;
 				t = e.time;
 				x = e.x;
 				y = e.y;
 			}
-
+			
 			@Override
 			public void mouseUp(MouseEvent e) {
-
+				
 				if (dblClick) { // doucle click raised by mouseDoubleClick
 					dblClick = false;
 					return; // stop right now ! :-o
 				}
 				if (debug) Log.finest("MOUSE UP"); //$NON-NLS-1$
 				EditionPanel panel = EditionPanel.this;
-
+				
 				// filter click that are not a left simple click (no drag)
 				// System.out.println("click count="+e.count+" button="+e.button+" time="+e.time+" diff="+(e.time-t)+" dist="+(Math.abs(e.x - x) + Math.abs(e.y - y)));
 				if (e.count > 1) {
@@ -707,25 +713,25 @@
 					// System.out.println("not a simple click");
 					return;
 				}
-
+				
 				int dist = Math.abs(e.x - x) + Math.abs(e.y - y);
 				int deltat = (e.time - t);
 				// System.out.println("deltat ="+deltat);
 				if (dist >= 0 && (deltat > 0 || dist > 0)) {
 					// System.out.println(" DRAG dist="+dist+" deltat="+deltat);
 					String[] ids = panel.getWordSelection(); // may be null
-
+					
 					panel.expandSelectionTo(ids);
 					return;
 				}
 			}
 		});
-
+		
 		browser.addMouseWheelListener(new MouseWheelListener() {
-
+			
 			@Override
 			public void mouseScrolled(MouseEvent e) {
-
+				
 				if ((e.stateMask & SWT.CTRL) == SWT.CTRL) {
 					if (e.count > 0) {
 						TXMBrowserEditor.zoomIn(getBrowser());
@@ -735,20 +741,20 @@
 				}
 			}
 		});
-
+		
 		KeyListener kListener = new KeyListener() {
-
+			
 			boolean debug = true;
-
+			
 			@Override
 			public void keyReleased(KeyEvent e) {
-
+				
 				if (debug) Log.finest(" KEY RELEASED: " + e); //$NON-NLS-1$
 			}
-
+			
 			@Override
 			public void keyPressed(KeyEvent e) {
-
+				
 				if (debug) Log.finest(" KEY PRESSED: " + e); //$NON-NLS-1$
 				if (e.keyCode == 'f' && (e.stateMask & SWT.CTRL) != 0) {
 					synopticEditionEditor.getSearchEditionToolbar().openSearch(getTextSelection());
@@ -757,34 +763,34 @@
 		};
 		getBrowser().setCapture(true);
 		getBrowser().addKeyListener(kListener);
-
+		
 		getBrowser().addProgressListener(progressListener);
 	}
-
+	
 	/**
 	 * Bypass BrowserViewer restriction on the getBrowser method
 	 */
 	@Override
 	public Browser getBrowser() {
-
+		
 		return super.getBrowser();
 	}
-
+	
 	/**
 	 * Bypass BrowserViewer restriction on the getBrowser method
 	 */
 	public String getDOM() {
-
+		
 		return "";// execute("return document.innerHTML"; //$NON-NLS-1$
 	}
-
+	
 	public ISelectionProvider getSelectionProvider() {
-
+		
 		return selProvider;
 	}
-
+	
 	public void setHighlightWordsById(RGBA color, HashSet<String> wordids) {
-
+		
 		for (String wordid : wordids) {
 			if (this.highlightedColorPerWordIDS.get(wordid) != null) {
 				removeHighlightWordsById(color, wordid);
@@ -794,32 +800,32 @@
 			hs.add(color);
 		}
 	}
-
+	
 	public void addHighlightWordsById(RGBA color, String wordid) {
-
+		
 		if (!this.highlightedColorPerWordIDS.containsKey(wordid)) {
 			this.highlightedColorPerWordIDS.put(wordid, new ArrayList<RGBA>());
 		}
 		this.highlightedColorPerWordIDS.get(wordid).add(color);
 	}
-
+	
 	/**
 	 * Can be called to refresh the page word styles but only when the page is loaded
 	 */
 	public void updateWordStyles() {
-
+		
 		progressListener.completed(null);
 	}
-
+	
 	public void addHighlightWordsById(RGBA color, Collection<String> wordids) {
-
+		
 		for (String wordid : wordids) {
 			addHighlightWordsById(color, wordid);
 		}
 	}
-
+	
 	public void removeHighlightWordsById(RGBA color, Collection<String> wordids) {
-
+		
 		// System.out.println("Call removeHighlightWordsById: "+wordids+" color="+color);
 		StringBuffer buffer = new StringBuffer();
 		for (String wordid : wordids) {
@@ -828,22 +834,22 @@
 				buffer.append(String.format(clearhighlightscript, wordid) + "\n"); //$NON-NLS-1$
 			}
 		}
-
+		
 		if (buffer.length() > 0) execute(buffer.toString());
 	}
-
+	
 	public void removeHighlightWordsById(RGBA color, String wordid) {
-
+		
 		if (highlightedColorPerWordIDS.get(wordid) == null) return; // nothing to do
-
+		
 		// System.out.println("remove color="+color+" from id="+wordid);
 		this.highlightedColorPerWordIDS.get(wordid).remove(color);
-
+		
 		if (this.highlightedColorPerWordIDS.get(wordid).size() == 0) {
 			this.highlightedColorPerWordIDS.remove(wordid);
 		}
 	}
-
+	
 	/**
 	 * Open the page containing the word with ID=$line_wordid
 	 * 
@@ -851,10 +857,10 @@
 	 * @return true if the page changed
 	 */
 	public boolean backToText(Text text, String line_wordid) {
-
+		
 		// String name = currentEdition.getName();
 		Edition edition = text.getEdition(editionName);
-
+		
 		if (edition == null) {
 			String s = EditionUIMessages.bind(EditionUIMessages.noEditionFoundForTextEqualsP0AndEditionEqualsP1, text, editionName);
 			Log.warning(s);
@@ -876,17 +882,17 @@
 				updateWordStyles(); // no need to change the page, but still update the focus&styles
 			}
 		}
-
+		
 		return false;
 	}
-
+	
 	/**
 	 * First page.
 	 */
 	public void firstPage() {
-
+		
 		if (currentEdition == null) return;
-
+		
 		// System.out.println(Messages.TxmBrowser_1+currentPage);
 		currentPage = currentEdition.getFirstPage();
 		currentText = currentEdition.getText();
@@ -894,12 +900,12 @@
 			System.out.println(EditionUIMessages.bind(EditionUIMessages.failToRetrieveFirstPageOfEditionEqualsP0AndTextEqualsP1, currentEdition.getName(), currentText.getName()));
 			return;
 		}
-
+		
 		reloadPage();
-
+		
 		// page_label.setText(makePageLabel());
 	}
-
+	
 	public static String fromEncodeString = "\"-&-'-<->-`- -¡-¢-£-¥-§-©-«-®-°-±-´-µ-¶-·-»-¿-À-Á-Â-Ã-Ä-Æ-Ç-È-É-Ê-Ë-Ì-Í-Î-Ï-Ñ-Ò-Ó-Ô-Õ-Ö-Ø-Ù-Ú-Û-Ü-ß-à-á-â-ã-ä-å-æ-ç-è-é-ê-ë-ì-í-î-ï-ð-ñ-ò-ó-ô-õ-ö-÷-ø-ù-ú-û-ü-ý-ÿ-Ā-ā-ĉ-Č-č-ē-ĝ-ģ-ĥ-Ī-ī-ĵ-ő-œ-ŕ-ř-ŝ-Š-š-Ū-ū-ŭ-ű-ŵ-ŷ-π-ḧ-ẅ-ẍ-ẑ-ỳ- - -–-—-‘-’-•-′-″-€-™-←-↑-→-↓-↖-↗-↘-↙-⌘-⏏-☑-✔"; //$NON-NLS-1$
 	public static String toEncodeString = "%22-%26-%27-%3C-%3E-%60-%C2%A0-%C2%A1-%C2%A2-%C2%A3-%C2%A5-%C2%A7-%C2%A9-%C2%AB-%C2%AE-%C2%B0-%C2%B1-%C2%B4-%C2%B5-%C2%B6-%C2%B7-%C2%BB-%C2%BF-%C3%80-%C3%81-%C3%82-%C3%83-%C3%84-%C3%86-%C3%87-%C3%88-%C3%89-%C3%8A-%C3%8B-%C3%8C-%C3%8D-%C3%8E-%C3%8F-%C3%91-%C3%92-%C3%93-%C3%94-%C3%95-%C3%96-%C3%98-%C3%99-%C3%9A-%C3%9B-%C3%9C-%C3%9F-%C3%A0-%C3%A1-%C3%A2-%C3%A3-%C3%A4-%C3%A5-%C3%A6-%C3%A7-%C3%A8-%C3%A9-%C3%AA-%C3%AB-%C3%AC-%C3%AD-%C3%AE-%C3%AF-%C3%B0-%C3%B1-%C3%B2-%C3%B3-%C3%B4-%C3%B5-%C3%B6-%C3%B7-%C3%B8-%C3%B9-%C3%BA-%C3%BB-%C3%BC-%C3%BD-%C3%BF-%C4%80-%C4%81-%C4%89-%C4%8C-%C4%8D-%C4%93-%C4%9D-%C4%A3-%C4%A5-%C4%AA-%C4%AB-%C4%B5-%C5%91-%C5%93-%C5%95-%C5%99-%C5%9D-%C5%A0-%C5%A1-%C5%AA-%C5%AB-%C5%AD-%C5%B1-%C5%B5-%C5%B7-%CF%80-%E1%B8%A7-%E1%BA%85-%E1%BA%8D-%E1%BA%91-%E1%BB%B3-%E2%80%82-%E2%80%83-%E2%80%93-%E2%80%94-%E2%80%98-%E2%80%99-%E2%80%A2-%E2%80%B2-%E2%80%B3-%E2%82%AC-%E2%84%A2-%E2%86%90-%E2%86%91-%E2%86%92-%E2%86%93-%E2%86%96-%E2%86%97-%E2%86%98-%E2%86%99-%E2%8C%98-%E2%8F%8F-%E2%98%91-%E2%9C%94"; //$NON-NLS-1$
 	private static String[] fromEncode, toEncode;
@@ -916,16 +922,16 @@
 		}
 		return url;
 	}
-
+	
 	@Override
 	public void setURL(String url) {
-
+		
 		if (!this.browser.isDisposed()) {
 			if (fromEncode != null) {
 				url = encodeURL(url);
 			}
 			super.setURL(url);
-
+			
 			//			if ("webkit".equals(this.browser.getBrowserType())) {
 			//				String u = URLUtils.encodeURL(url);
 			//				Log.finer("setting encoded URL: "+u);
@@ -946,17 +952,17 @@
 			//				// TODO Auto-generated catch block
 			//				e.printStackTrace();
 			//			}
-
+			
 		}
 	}
-
+	
 	/**
 	 * Last page.
 	 */
 	public void lastPage() {
 		// System.out.println(Messages.TxmBrowser_2+currentPage);
 		if (currentEdition == null) return;
-
+		
 		if (currentPage != null && currentPage.getFile().equals(currentEdition.getLastPage().getFile())) {
 			return;
 		}
@@ -964,18 +970,18 @@
 		currentText = currentEdition.getText();
 		reloadPage();
 	}
-
+	
 	/**
 	 * Previous page.
 	 */
 	public void previousPage() {
-
+		
 		if (currentEdition == null) return;
-
+		
 		// System.out.println(Messages.TxmBrowser_3+currentPage);
 		if (currentPage != null) {
 			Page previous = currentEdition.getPreviousPage(currentPage);
-
+			
 			if (previous == currentPage) {
 				previousText(true);
 			}
@@ -990,16 +996,16 @@
 		}
 		// page_label.setText(makePageLabel());
 	}
-
-
-
+	
+	
+	
 	/**
 	 * Next page.
 	 */
 	public void nextPage() {
-
+		
 		if (currentEdition == null) return;
-
+		
 		// System.out.println(Messages.TxmBrowser_4+currentPage);
 		if (currentPage != null) {
 			Page next = currentEdition.getNextPage(currentPage);
@@ -1017,10 +1023,10 @@
 		}
 		// page_label.setText(makePageLabel());
 	}
-
-
+	
+	
 	public void firstText() {
-
+		
 		// Text current = this.currentPage.getEdition().getText();
 		Project project = currentText.getProject();
 		String id;
@@ -1032,7 +1038,7 @@
 			return;
 		}
 		Text firstText = project.getText(id);
-
+		
 		if (firstText != null) {
 			String editionName = currentEdition.getName();
 			Edition tmp = firstText.getEdition(editionName);
@@ -1050,12 +1056,12 @@
 			reloadPage();
 		}
 	}
-
+	
 	/**
 	 * Next text.
 	 */
 	public void lastText() {
-
+		
 		// Text current = this.currentPage.getEdition().getText();
 		Project project = currentText.getProject();
 		String id;
@@ -1068,7 +1074,7 @@
 			return;
 		}
 		Text lastText = project.getText(id);
-
+		
 		if (lastText != null) {
 			String editionName = currentEdition.getName();
 			Edition tmp = lastText.getEdition(editionName);
@@ -1076,7 +1082,7 @@
 				System.out.println(EditionUIMessages.bind(EditionUIMessages.noEditionWithNameEqualsP0AvailableForTextEqualsP1, editionName, lastText.getName()));
 				return;
 			}
-
+			
 			currentEdition = tmp;
 			currentPage = currentEdition.getFirstPage();
 			currentText = lastText;
@@ -1084,20 +1090,20 @@
 				StatusLine.setMessage("No text next"); //$NON-NLS-1$
 				return;
 			}
-
+			
 			reloadPage();
 			// page_label.setText(makePageLabel());
 		}
 		// System.out.println("Next texts "+nextText);
 	}
-
+	
 	/**
 	 * Previous text.
 	 * 
 	 * @param fromNextText if true it means the user was reading the next text and then we show the last page of the previous text
 	 */
 	public void previousText(boolean fromNextText) {
-
+		
 		Project project = currentText.getProject();
 		String id;
 		try {
@@ -1118,10 +1124,10 @@
 			return;
 		}
 		Text previousText = project.getText(id);
-
+		
 		if (previousText != null) {
 			String editionName = currentEdition.getName();
-
+			
 			Edition tmp = previousText.getEdition(editionName);
 			if (tmp == null) {
 				System.out.println(EditionUIMessages.bind(EditionUIMessages.noEditionWithNameEqualsP0AvailableForTextEqualsP1, editionName, previousText.getName()));
@@ -1135,7 +1141,7 @@
 			else {
 				currentPage = currentEdition.getFirstPage();
 			}
-
+			
 			if (currentPage == null) {
 				StatusLine.setMessage("No previous text"); //$NON-NLS-1$
 				return;
@@ -1144,12 +1150,12 @@
 		}
 		// System.out.println("Previous texts "+previousText);
 	}
-
+	
 	/**
 	 * Next text.
 	 */
 	public void nextText() {
-
+		
 		// Text current = this.currentPage.getEdition().getText();
 		Project project = currentText.getProject();
 		String id;
@@ -1171,7 +1177,7 @@
 			return;
 		}
 		Text nextText = project.getText(id);
-
+		
 		if (nextText != null) {
 			String editionName = currentEdition.getName();
 			Edition tmp = nextText.getEdition(editionName);
@@ -1180,34 +1186,34 @@
 				return;
 			}
 			currentEdition = tmp;
-
+			
 			currentPage = currentEdition.getFirstPage();
 			currentText = nextText;
 			if (currentPage == null) {
 				StatusLine.setMessage("No text next"); //$NON-NLS-1$
 				return;
 			}
-
+			
 			reloadPage();
 			// page_label.setText(makePageLabel());
 		}
 		// System.out.println("Next texts "+nextText);
 	}
-
-
+	
+	
 	public void setText(Text text, boolean refresh) {
-
+		
 		// String editionName = currentEdition.getName();
 		Edition tmp = text.getEdition(this.editionName);
 		if (tmp == null) {
 			System.out.println(EditionUIMessages.bind(EditionUIMessages.noEditionWithNameEqualsP0AvailableForTextEqualsP1, this.editionName, text.getName()));
 			return;
 		}
-
+		
 		currentEdition = tmp;
-
+		
 		currentText = text;
-
+		
 		if (refresh) {
 			currentPage = currentEdition.getFirstPage();
 			if (currentPage == null) {
@@ -1218,44 +1224,44 @@
 		}
 		// page_label.setText(makePageLabel());
 	}
-
+	
 	/**
 	 * Gets the current page.
 	 *
 	 * @return the current page
 	 */
 	public Page getCurrentPage() {
-
+		
 		return currentPage;
 	}
-
+	
 	/**
 	 * Gets the current text.
 	 *
 	 * @return the current page
 	 */
 	public Text getCurrentText() {
-
+		
 		return currentText;
 	}
-
+	
 	/**
 	 * Make page label.
 	 *
 	 * @return the string
 	 */
 	public String makePageLabel() {
-
+		
 		return currentPage.getName() + " / " + currentPage.getEdition().getNumPages(); //$NON-NLS-1$
 	}
-
+	
 	/**
 	 * Show page.
 	 *
 	 * @param page the page
 	 */
 	public void showPage(Page page) {
-
+		
 		if (currentEdition == null) return;
 		// System.out.println("SHOW PAGE "+page);
 		currentEdition = page.getEdition();
@@ -1263,15 +1269,15 @@
 		currentPage = page;
 		reloadPage();
 	}
-
+	
 	/**
 	 * Reload the browser with the currentPage URL
 	 */
 	public void reloadPage() {
-
+		
 		this.setURL(currentPage.toURL());
 	}
-
+	
 	// /**
 	// * Sets the edition.
 	// *
@@ -1280,7 +1286,7 @@
 	// public void setEdition(Edition edition) {
 	// this.currentEdition = edition;
 	// }
-
+	
 	String EMPTYSELECTIONTEST =
 			"if (typeof window.getSelection != \"undefined\") {" + // modern Web browsers //$NON-NLS-1$
 					"var sel = window.getSelection();" + //$NON-NLS-1$
@@ -1291,7 +1297,7 @@
 					"}" + //$NON-NLS-1$
 					"}" + //$NON-NLS-1$
 					"return false"; //$NON-NLS-1$
-
+	
 	String SCRIPT01 = 
 			"var html = \"\";" + //$NON-NLS-1$
 					"if (typeof window.getSelection != \"undefined\") {" + // modern Web browsers //$NON-NLS-1$
@@ -1311,20 +1317,20 @@
 					"}" + //$NON-NLS-1$
 					"}" + //$NON-NLS-1$
 					"return html"; //$NON-NLS-1$
-
+	
 	public String getTextSelectionDOM() {
-
+		
 		String t = ((String) evaluate(SCRIPT01));
 		Log.finest("HTML text selection=" + t); //$NON-NLS-1$
 		return t;
 	}
-
+	
 	/**
 	 * 
 	 * @return array of 2 word id, if only one word is selected 2nd value is null
 	 */
 	public String[] getWordSelection() {
-
+		
 		// System.out.println("getWordSelection");
 		String SCRIPT02_getspans = ""// functions //$NON-NLS-1$
 				+ "var all = [];" //$NON-NLS-1$
@@ -1359,10 +1365,10 @@
 				+ "\n}" //$NON-NLS-1$
 				// +"alert('result='+all)"
 				+ "\nreturn all;"; //$NON-NLS-1$
-
+		
 		// System.out.println(functions);
 		// System.out.println(SCRIPT02_getspans);
-
+		
 		Object ret = evaluate(SCRIPT02_getspans);
 		if (ret instanceof Object[]) {
 			Log.finer("selection word ids=" + Arrays.toString((Object[]) ret)); //$NON-NLS-1$
@@ -1386,203 +1392,228 @@
 			return null;
 		}
 	}
-
+	
 	public boolean isTextSelectionEmpty() {
 		return browser.evaluate(EMPTYSELECTIONTEST).equals(true);
 	}
-
+	
 	public String getTextSelection() {
-
+		
 		// System.out.println("DOM="+getTextSelectionDOM());
 		String dom = getTextSelectionDOM();
 		if (dom == null) return ""; //$NON-NLS-1$
-
+		
 		String rez = dom.replaceAll("<[^>]+>", ""); //$NON-NLS-1$ //$NON-NLS-2$
 		// System.out.println("STR="+rez);
 		return rez;
 	}
-
+	
 	@Override
 	public void addSelectionChangedListener(ISelectionChangedListener listener) {}
-
+	
 	@Override
 	public ISelection getSelection() {
-
+		
 		return new SynopticTextSelection(this);
 	}
-
+	
 	@Override
 	public void removeSelectionChangedListener(
 			ISelectionChangedListener listener) {}
-
+	
 	@Override
 	public void setSelection(ISelection selection) {}
-
+	
 	static public class SynopticTextSelection implements ISelection {
-
+		
 		String str;
-
+		
 		public SynopticTextSelection(EditionPanel panel) {
-
+			
 			this.str = panel.getTextSelection();
 		}
-
+		
 		@Override
 		public boolean isEmpty() {
-
+			
 			return str != null && str.length() > 0;
 		}
-
+		
 		public String getTextSelection() {
-
+			
 			return str;
 		}
 	}
-
+	
 	public Edition getEdition() {
-
+		
 		return currentEdition;
 	}
-
+	
 	public MenuManager getMenuManager() {
-
+		
 		return menuManager;
 	}
-
+	
 	public void initMenu() {
-
+		
 		// create a new menu
 		menuManager = new MenuManager();
-
+		
 		Menu menu = menuManager.createContextMenu(this.getBrowser());
-
+		
 		menu.addMenuListener(new MenuListener() {
-
+			
 			@Override
 			public void menuShown(MenuEvent e) {
-
+				
 				Menu menu = menuManager.getMenu();
 				if (menu == null) return;
 				new MenuItem(menu, SWT.SEPARATOR);
-
+				
 				MenuItem searchItem = new MenuItem(menu, SWT.NONE);
 				searchItem.setText(EditionUIMessages.Search);
 				searchItem.addSelectionListener(new SelectionListener() {
-
+					
 					@Override
 					public void widgetSelected(SelectionEvent e) {
-
+						
 						String text = EditionPanel.this.getTextSelection();
 						synopticEditionEditor.getSearchEditionToolbar().openSearch(text);
 					}
-
+					
 					@Override
 					public void widgetDefaultSelected(SelectionEvent e) {}
 				});
-
-				MenuItem copyItem = new MenuItem(menu, SWT.NONE);
-				copyItem.setText(EditionUIMessages.copyTextSelection);
-				copyItem.addSelectionListener(new SelectionListener() {
-
-					@Override
-					public void widgetSelected(SelectionEvent e) {
-
-						String text = EditionPanel.this.getTextSelection();
-						if (text != null && text.length() > 0) {
-							IOClipboard.write(text);
+				
+				String dom = EditionPanel.this.getTextSelectionDOM();
+				if (dom != null && dom.length() > 0) {
+					MenuItem copyItem = new MenuItem(menu, SWT.NONE);
+					copyItem.setText(EditionUIMessages.copyTextSelection);
+					copyItem.addSelectionListener(new SelectionListener() {
+						
+						@Override
+						public void widgetSelected(SelectionEvent e) {
+							
+							String text = EditionPanel.this.getTextSelection();
+							if (text != null && text.length() > 0) {
+								IOClipboard.write(text);
+							}
 						}
+						
+						@Override
+						public void widgetDefaultSelected(SelectionEvent e) {}
+					});
+					
+					Object currentHref = EditionPanel.this.getBrowser().evaluate("return document.currentHoverElement.getAttribute('href')");
+					if (currentHref != null) {
+						MenuItem copyLink = new MenuItem(menu, SWT.NONE);
+						copyLink.setText("Copy link");
+						copyLink.addSelectionListener(new SelectionListener() {
+							
+							@Override
+							public void widgetSelected(SelectionEvent e) {
+								
+								String text = EditionPanel.this.getTextSelectionDOM();
+								if (text != null && text.length() > 0) {
+									
+									if (currentHref != null) {
+										IOClipboard.write(currentHref.toString());
+									}
+								}
+							}
+							
+							@Override
+							public void widgetDefaultSelected(SelectionEvent e) {}
+						});
 					}
-
-					@Override
-					public void widgetDefaultSelected(SelectionEvent e) {}
-				});
-				String text = EditionPanel.this.getTextSelection();
-				copyItem.setEnabled(text != null && text.length() > 0);
-
+				}
+				
+				
 				MenuItem zoomInItem = new MenuItem(menu, SWT.NONE);
 				zoomInItem.setText(EditionUIMessages.ZoomIn);
 				zoomInItem.addSelectionListener(new SelectionListener() {
-
+					
 					@Override
 					public void widgetSelected(SelectionEvent e) {
 						TXMBrowserEditor.zoomIn(browser);
 					}
-
+					
 					@Override
 					public void widgetDefaultSelected(SelectionEvent e) {}
 				});
-
+				
 				MenuItem zoomOutItem = new MenuItem(menu, SWT.NONE);
 				zoomOutItem.setText(EditionUIMessages.ZoomOut);
 				zoomOutItem.addSelectionListener(new SelectionListener() {
-
+					
 					@Override
 					public void widgetSelected(SelectionEvent e) {
-
+						
 						TXMBrowserEditor.zoomOut(browser);
 					}
-
+					
 					@Override
 					public void widgetDefaultSelected(SelectionEvent e) {}
 				});
-
+				
 				MenuItem zoomResetItem = new MenuItem(menu, SWT.NONE);
 				zoomResetItem.setText(EditionUIMessages.InitialZoom);
 				zoomResetItem.addSelectionListener(new SelectionListener() {
-
+					
 					@Override
 					public void widgetSelected(SelectionEvent e) {
-
+						
 						TXMBrowserEditor.zoomReset(browser);
 					}
-
+					
 					@Override
 					public void widgetDefaultSelected(SelectionEvent e) {}
 				});
-
+				
 				MenuItem reloadItem = new MenuItem(menu, SWT.NONE);
 				reloadItem.setText(EditionUIMessages.reload);
 				reloadItem.addSelectionListener(new SelectionListener() {
-
+					
 					@Override
 					public void widgetSelected(SelectionEvent e) {
-
+						
 						EditionPanel.this.getBrowser().refresh();
 					}
-
+					
 					@Override
 					public void widgetDefaultSelected(SelectionEvent e) {}
 				});
 				MenuItem backItem = new MenuItem(menu, SWT.NONE);
 				backItem.setText(EditionUIMessages.back);
 				backItem.addSelectionListener(new SelectionListener() {
-
+					
 					@Override
 					public void widgetSelected(SelectionEvent e) {
-
+						
 						EditionPanel.this.getBrowser().back();
 					}
-
+					
 					@Override
 					public void widgetDefaultSelected(SelectionEvent e) {}
 				});
 				MenuItem forwardItem = new MenuItem(menu, SWT.NONE);
 				forwardItem.setText(EditionUIMessages.forward);
 				forwardItem.addSelectionListener(new SelectionListener() {
-
+					
 					@Override
 					public void widgetSelected(SelectionEvent e) {
-
+						
 						EditionPanel.this.getBrowser().forward();
 					}
-
+					
 					@Override
 					public void widgetDefaultSelected(SelectionEvent e) {}
 				});
-
+				
 				MenuItem propertiesItem = new PagePropertiesMenu(getBrowser(), menu, SWT.NONE);
 			}
-
+			
 			@Override
 			public void menuHidden(MenuEvent e) {
 				// TODO Auto-generated method stub
@@ -1606,22 +1637,22 @@
 		// replace the menu
 		this.getBrowser().setMenu(menu);
 	}
-
+	
 	public void initSelectionProvider() {
-
+		
 		selProvider = new ISelectionProvider() {
-
+			
 			@Override
 			public void setSelection(ISelection selection) {}
-
+			
 			@Override
 			public void removeSelectionChangedListener(ISelectionChangedListener listener) {}
-
+			
 			@Override
 			public ISelection getSelection() {
-
+				
 				ITextSelection sel = new ITextSelection() {
-
+					
 					@Override
 					public boolean isEmpty() {
 						if (EditionPanel.this.isDisposed()) return true;
@@ -1629,49 +1660,49 @@
 						//System.out.println("EMPTY? "+r);
 						return r;
 					}
-
+					
 					@Override
 					public String getText() {
 						if (EditionPanel.this.isDisposed()) return null;
 						return EditionPanel.this.getTextSelection();
 					}
-
+					
 					@Override
 					public int getStartLine() {
-
+						
 						return 0;
 					}
-
+					
 					@Override
 					public int getOffset() {
-
+						
 						return 0;
 					}
-
+					
 					@Override
 					public int getLength() {
-
+						
 						return 0;
 					}
-
+					
 					@Override
 					public int getEndLine() {
-
+						
 						return 0;
 					}
 				};
 				return sel;
 			}
-
+			
 			@Override
 			public void addSelectionChangedListener(ISelectionChangedListener listener) {}
 		};
 	}
-
-
-
+	
+	
+	
 	public void goToPage(String text, String name) {
-
+		
 		if (text != null) {
 			Text newText = this.synopticEditionEditor.getCorpus().getProject().getText(text);
 			if (newText == null) {
@@ -1681,7 +1712,7 @@
 				setText(newText, false);
 			}
 		}
-
+		
 		Page next = currentEdition.getPageForName(name);
 		// System.out.println(Messages.TxmBrowser_4+currentPage);
 		if (next != null && !next.equals(this.currentPage)) {
@@ -1692,25 +1723,25 @@
 			System.out.println(EditionUIMessages.bind(EditionUIMessages.pageNotFoundP0, name));
 		}
 	}
-
+	
 	public void setFocusedWordID(String focusid) {
-
+		
 		this.focusedWordID = focusid;
 	}
-
+	
 	public void setHighlightedArea(HashSet<int[]> positions) {
-
+		
 		Log.finer("Highlight area: not implemented"); //$NON-NLS-1$
 	}
-
+	
 	public void expandSelectionTo(String[] ids) {
-
+		
 		// expand selection
 		if (ids == null) return;
 		if (ids.length == 0) return;
 		// TODO: enable the feature for Windows computers
 		// if (System.getProperty("os.name").toLowerCase().contains("windows")) return;
-
+		
 		// this.getBrowser().evaluate("alert('expand selection');");
 		// System.out.println("EXPAND SELECTION TO "+Arrays.toString(ids));
 		String id1 = ids[0];
@@ -1734,51 +1765,51 @@
 				+ "sel.addRange(range);\n" //$NON-NLS-1$
 				+ "\n" //$NON-NLS-1$
 				+ "return null;"; //$NON-NLS-1$
-
+		
 		// System.out.println("Eval...\n"+SCRIPT02_expand);
 		evaluate(SCRIPT02_expand);
 		return;
 	}
-
+	
 	public void addFontWeightWordsById(String weight, List<String> wordids) {
-
+		
 		for (String wordid : wordids) {
 			addFontWeightWordsById(weight, wordid);
 		}
 	}
-
+	
 	public void addFontWeightWordsById(String weight, String wordid) {
-
+		
 		this.fontWeightPerWordIDS.put(wordid, weight);
 	}
-
+	
 	public void removeFontWeightWordsById(String wordid) {
-
+		
 		this.fontWeightPerWordIDS.remove(wordid);
 	}
-
+	
 	public void removeFontWeightWordsById(List<String> wordids) {
-
+		
 		for (String wordid : wordids) {
 			removeFontWeightWordsById(wordid);
 		}
 	}
-
+	
 	/**
 	 * Clears all highlighted words.
 	 */
 	public void removeHighlightWords() {
-
+		
 		// FIXME: SJ: this code leads to a concurrency modification exception on Windows
 		// Set<String> keys = highlightedColorPerWordIDS.keySet();
 		// for (String key : keys) {
 		// highlightedColorPerWordIDS.remove(key);
 		// }
-
+		
 		// SJ: new version tests
 		highlightedColorPerWordIDS.clear();
-
-
-
+		
+		
+		
 	}
 }
