mirror of
https://github.com/fastmail/Squire.git
synced 2025-01-08 16:00:06 -05:00
Add make/remove link sugar.
Also: Add getSelectedText method. Fix bug in setting HTML after undo/redo in Opera.
This commit is contained in:
parent
6726a0b33c
commit
a2ef14e218
4 changed files with 89 additions and 12 deletions
16
Readme.md
16
Readme.md
|
@ -118,6 +118,10 @@ Sets the HTML value for the editor. The value supplied should not contain `<body
|
||||||
|
|
||||||
Returns self.
|
Returns self.
|
||||||
|
|
||||||
|
### getSelectedText ###
|
||||||
|
|
||||||
|
Returns the text currently selected in the editor.
|
||||||
|
|
||||||
#### insertImage ####
|
#### insertImage ####
|
||||||
|
|
||||||
Inserts an image at the current cursor location.
|
Inserts an image at the current cursor location.
|
||||||
|
@ -217,11 +221,19 @@ Returns self.
|
||||||
|
|
||||||
### makeLink ###
|
### makeLink ###
|
||||||
|
|
||||||
Makes the currently selected text a link.
|
Makes the currently selected text a link. If no text is selected, the URL or email will be inserted as text at the current cursor point and made into a link.
|
||||||
|
|
||||||
#### Parameters ####
|
#### Parameters ####
|
||||||
|
|
||||||
* **url**: The url to link to.
|
* **url**: The url or email to link to.
|
||||||
|
|
||||||
|
#### Returns ####
|
||||||
|
|
||||||
|
Returns self.
|
||||||
|
|
||||||
|
### removeLink ###
|
||||||
|
|
||||||
|
Removes any link that is currently at least partially selected.
|
||||||
|
|
||||||
#### Returns ####
|
#### Returns ####
|
||||||
|
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -197,8 +197,11 @@ document.addEventListener( 'DOMContentLoaded', function () {
|
||||||
};
|
};
|
||||||
|
|
||||||
var setHTML = function ( html ) {
|
var setHTML = function ( html ) {
|
||||||
body.innerHTML = html;
|
var node = body;
|
||||||
body.fixCursor();
|
node.innerHTML = html;
|
||||||
|
do {
|
||||||
|
node.fixCursor();
|
||||||
|
} while ( node = node.getNextBlock() );
|
||||||
};
|
};
|
||||||
|
|
||||||
var insertElement = function ( el, range ) {
|
var insertElement = function ( el, range ) {
|
||||||
|
@ -478,7 +481,7 @@ document.addEventListener( 'DOMContentLoaded', function () {
|
||||||
return range;
|
return range;
|
||||||
};
|
};
|
||||||
|
|
||||||
var removeFormat = function ( tag, attributes, range ) {
|
var removeFormat = function ( tag, attributes, range, partial ) {
|
||||||
// Add bookmark
|
// Add bookmark
|
||||||
saveRangeToBookmark( range );
|
saveRangeToBookmark( range );
|
||||||
|
|
||||||
|
@ -552,9 +555,11 @@ document.addEventListener( 'DOMContentLoaded', function () {
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if ( !partial ) {
|
||||||
formatTags.forEach( function ( node ) {
|
formatTags.forEach( function ( node ) {
|
||||||
examineNode( node, node );
|
examineNode( node, node );
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Now wrap unselected nodes in the tag
|
// Now wrap unselected nodes in the tag
|
||||||
toWrap.forEach( function ( item ) {
|
toWrap.forEach( function ( item ) {
|
||||||
|
@ -581,7 +586,7 @@ document.addEventListener( 'DOMContentLoaded', function () {
|
||||||
return range;
|
return range;
|
||||||
};
|
};
|
||||||
|
|
||||||
var changeFormat = function ( add, remove, range ) {
|
var changeFormat = function ( add, remove, range, partial ) {
|
||||||
// Normalise the arguments and get selection
|
// Normalise the arguments and get selection
|
||||||
if ( !range && !( range = getSelection() ) ) {
|
if ( !range && !( range = getSelection() ) ) {
|
||||||
return;
|
return;
|
||||||
|
@ -593,7 +598,7 @@ document.addEventListener( 'DOMContentLoaded', function () {
|
||||||
|
|
||||||
if ( remove ) {
|
if ( remove ) {
|
||||||
range = removeFormat( remove.tag.toUpperCase(),
|
range = removeFormat( remove.tag.toUpperCase(),
|
||||||
remove.attributes || {}, range );
|
remove.attributes || {}, range, partial );
|
||||||
}
|
}
|
||||||
if ( add ) {
|
if ( add ) {
|
||||||
range = addFormat( add.tag.toUpperCase(),
|
range = addFormat( add.tag.toUpperCase(),
|
||||||
|
@ -1421,6 +1426,10 @@ document.addEventListener( 'DOMContentLoaded', function () {
|
||||||
return this;
|
return this;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
getSelectedText: function () {
|
||||||
|
return getSelection().getTextContent();
|
||||||
|
},
|
||||||
|
|
||||||
insertImage: function ( src ) {
|
insertImage: function ( src ) {
|
||||||
var img = createElement( 'IMG', {
|
var img = createElement( 'IMG', {
|
||||||
src: src
|
src: src
|
||||||
|
@ -1450,6 +1459,17 @@ document.addEventListener( 'DOMContentLoaded', function () {
|
||||||
removeUnderline: command( changeFormat, null, { tag: 'U' } ),
|
removeUnderline: command( changeFormat, null, { tag: 'U' } ),
|
||||||
|
|
||||||
makeLink: function ( url ) {
|
makeLink: function ( url ) {
|
||||||
|
url = encodeURI( url );
|
||||||
|
var range = getSelection();
|
||||||
|
if ( range.collapsed ) {
|
||||||
|
var protocolEnd = url.indexOf( ':' ) + 1;
|
||||||
|
if ( protocolEnd ) {
|
||||||
|
while ( url[ protocolEnd ] === '/' ) { protocolEnd += 1; }
|
||||||
|
}
|
||||||
|
range._insertNode(
|
||||||
|
doc.createTextNode( url.slice( protocolEnd ) )
|
||||||
|
);
|
||||||
|
}
|
||||||
changeFormat({
|
changeFormat({
|
||||||
tag: 'A',
|
tag: 'A',
|
||||||
attributes: {
|
attributes: {
|
||||||
|
@ -1457,7 +1477,15 @@ document.addEventListener( 'DOMContentLoaded', function () {
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
tag: 'A'
|
tag: 'A'
|
||||||
});
|
}, range );
|
||||||
|
focus();
|
||||||
|
return this;
|
||||||
|
},
|
||||||
|
|
||||||
|
removeLink: function () {
|
||||||
|
changeFormat( null, {
|
||||||
|
tag: 'A'
|
||||||
|
}, getSelection(), true );
|
||||||
focus();
|
focus();
|
||||||
return this;
|
return this;
|
||||||
},
|
},
|
||||||
|
|
|
@ -18,6 +18,8 @@ var indexOf = Array.prototype.indexOf;
|
||||||
|
|
||||||
var ELEMENT_NODE = 1, // Node.ELEMENT_NODE
|
var ELEMENT_NODE = 1, // Node.ELEMENT_NODE
|
||||||
TEXT_NODE = 3, // Node.TEXT_NODE
|
TEXT_NODE = 3, // Node.TEXT_NODE
|
||||||
|
SHOW_TEXT = 4, // NodeFilter.SHOW_TEXT,
|
||||||
|
FILTER_ACCEPT = 1, // NodeFilter.FILTER_ACCEPT,
|
||||||
START_TO_START = 0, // Range.START_TO_START
|
START_TO_START = 0, // Range.START_TO_START
|
||||||
START_TO_END = 1, // Range.START_TO_END
|
START_TO_END = 1, // Range.START_TO_END
|
||||||
END_TO_END = 2, // Range.END_TO_END
|
END_TO_END = 2, // Range.END_TO_END
|
||||||
|
@ -49,6 +51,41 @@ var getNodeAfter = function ( node, offset ) {
|
||||||
};
|
};
|
||||||
|
|
||||||
implement( Range, {
|
implement( Range, {
|
||||||
|
getTextContent: function () {
|
||||||
|
this.moveBoundariesDownTree();
|
||||||
|
|
||||||
|
var startContainer = this.startContainer,
|
||||||
|
endContainer = this.endContainer,
|
||||||
|
root = this.commonAncestorContainer,
|
||||||
|
walker = root.ownerDocument.createTreeWalker(
|
||||||
|
root, SHOW_TEXT, function ( node ) {
|
||||||
|
return FILTER_ACCEPT;
|
||||||
|
}, false ),
|
||||||
|
textnode = walker.currentNode = startContainer,
|
||||||
|
textContent = '',
|
||||||
|
value;
|
||||||
|
|
||||||
|
do {
|
||||||
|
value = textnode.data;
|
||||||
|
if ( value && ( /\S/.test( value ) ) ) {
|
||||||
|
if ( textnode === endContainer ) {
|
||||||
|
value = value.slice( 0, this.endOffset );
|
||||||
|
}
|
||||||
|
if ( textnode === startContainer ) {
|
||||||
|
value = value.slice( this.startOffset );
|
||||||
|
}
|
||||||
|
textContent += value;
|
||||||
|
}
|
||||||
|
if ( textnode === endContainer ) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} while ( textnode = walker.nextNode() );
|
||||||
|
|
||||||
|
return textContent;
|
||||||
|
},
|
||||||
|
|
||||||
|
// ---
|
||||||
|
|
||||||
_insertNode: function ( node ) {
|
_insertNode: function ( node ) {
|
||||||
// Insert at start.
|
// Insert at start.
|
||||||
var startContainer = this.startContainer,
|
var startContainer = this.startContainer,
|
||||||
|
|
Loading…
Reference in a new issue