Skip to content

Commit b1a43ff

Browse files
committed
Merge branch 'master' of github.com:/Intermesh/groupoffice
2 parents 4033136 + 0a7e16c commit b1a43ff

5 files changed

Lines changed: 41 additions & 64 deletions

File tree

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
- Files: fix external link to folder in folder panel
22
- Support: new icon for link to prevent confusion with old tickets module
3+
- Core / email: Improved converting url to anchors so text cursor won't jump to last line
34

4-
23-06-2025: 25.0.32
5+
- 23-06-2025: 25.0.32
56
- LDAPServer: Fix primary key error
67

78
20-06-2025: 25.0.31

www/modules/z-push/backend/go/MailStore.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ public function ChangeFolder($folderid, $oldid, $displayname, $type) {
3737
//$this->imap_reopenFolder($folderid);
3838

3939
$imap = $this->_imapLogon();
40+
if(!$imap) {
41+
return false;
42+
}
4043

4144
//remove m/ from the combined stuff
4245
if (!empty($folderid)) {

www/modules/z-push/backend/go/Store.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,10 @@ public function getImapAccount(){
2222
try{
2323
self::$_account = \GO\Email\Model\Account::model()->findByPk($settings->account_id);
2424
if(!self::$_account){
25-
ZLog::Write(LOGLEVEL_FATAL, 'E-mail account not found!');
25+
ZLog::Write(LOGLEVEL_INFO, 'E-mail account not found!');
2626
}
2727
}catch(\GO\Base\Exception\AccessDenied $e){
28-
ZLog::Write(LOGLEVEL_FATAL, 'GoBaseBackendDiff->getImapAccount() ~~ ACCESS DENIED to e-mail account configured in sync settings('.(string)$e->getMessage().')');
28+
ZLog::Write(LOGLEVEL_WARN, 'GoBaseBackendDiff->getImapAccount() ~~ ACCESS DENIED to e-mail account configured in sync settings('.(string)$e->getMessage().')');
2929
}
3030
}else
3131
{

www/views/Extjs3/javascript/form/HtmlEditor.js

Lines changed: 33 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -237,76 +237,49 @@ Ext.extend(GO.form.HtmlEditor, Ext.form.HtmlEditor, {
237237
this.debounceTimeout = setTimeout( () => {
238238
clearTimeout(this.debounceTimeout);
239239
this.debounceTimeout = undefined;
240+
this.convertUrisToAnchors();
241+
}, 500);
242+
},
240243

241-
const index = this.getCaretCharacterOffsetWithin();
242-
var h = this.getEditorBody().innerHTML;
243-
var anchored = Autolinker.link(h, {
244-
stripPrefix: false,
245-
stripTrailingSlash: false,
246-
className: "normal-link",
247-
newWindow: true,
248-
phone: false,
249-
urls: {
250-
schemeMatches : true,
251-
wwwMatches : false,
252-
tldMatches : false
253-
}
254-
});
255244

256-
if(h != anchored) {
245+
convertUrisToAnchors: function() {
246+
const walk = (node) => {
257247

258-
this.getEditorBody().innerHTML = anchored;
259-
this.setCaretPosition(index);
248+
if(node.nodeType == Node.ELEMENT_NODE && node.tagName == "A") {
249+
// don't traverse into anchor tags
250+
return;
260251
}
261252

262-
console.warn("autolink");
263-
264-
}, 500);
265-
},
266-
267-
268-
getCaretCharacterOffsetWithin: function () {
269-
const win = this.getWin(), doc = this.getDoc(), element = this.getEditorBody();
270-
let caretOffset = 0;
271-
const sel = win.getSelection();
272-
if (sel.rangeCount > 0) {
273-
const range = sel.getRangeAt(0);
274-
const preCaretRange = range.cloneRange();
275-
preCaretRange.selectNodeContents(element);
276-
preCaretRange.setEnd(range.endContainer, range.endOffset);
277-
caretOffset = preCaretRange.toString().length;
278-
}
279-
return caretOffset;
280-
},
253+
//walk nodes recursively
254+
node.childNodes.forEach(walk);
281255

282-
setCaretPosition: function (offset) {
283-
const win = this.getWin(), doc = this.getDoc(), element = this.getEditorBody();
284-
let currentOffset = 0;
285-
const nodeStack = [element];
286-
let node, found = false;
287-
288-
while (nodeStack.length && !found) {
289-
node = nodeStack.pop();
290-
if (node.nodeType === Node.TEXT_NODE) {
291-
const nextOffset = currentOffset + node.length;
292-
if (offset <= nextOffset) {
293-
const range = win.document.createRange();
294-
range.setStart(node, offset - currentOffset);
295-
range.collapse(true);
296-
const sel = win.getSelection();
297-
sel.removeAllRanges();
298-
sel.addRange(range);
299-
found = true;
300-
} else {
301-
currentOffset = nextOffset;
256+
if(node.nodeType == Node.TEXT_NODE) {
257+
if(node == this.getDoc().getSelection().anchorNode) {
258+
return;
302259
}
303-
} else {
304-
let i = node.childNodes.length;
305-
while (i--) {
306-
nodeStack.push(node.childNodes[i]);
260+
261+
if (node.textContent && node.textContent.indexOf("http") > -1) {
262+
const anchored = this.replaceUriWithAnchor(node.textContent);
263+
if (anchored != node.textContent) {
264+
const tmp = document.createElement("span");
265+
tmp.innerHTML = anchored;
266+
node.replaceWith(tmp);
267+
}
307268
}
308269
}
309270
}
271+
272+
walk(this.getEditorBody());
273+
},
274+
275+
replaceUriWithAnchor : function(html) {
276+
// Regular expression to match URIs that are not inside anchor tags
277+
const uriRegex = /(https?:\/\/[^\s]+|ftp:\/\/[^\s]+)/ig;
278+
279+
// Replace matched URIs with anchor tags
280+
return html.replace(uriRegex, (url) => {
281+
return `<a href="${url}" target="_blank" rel="noopener noreferrer">${url}</a>`;
282+
});
310283
},
311284

312285
onDrop: function(e) {

0 commit comments

Comments
 (0)