Skip to content

Commit 8abdf5a

Browse files
feat(custom-elems): Add custom selection elements
1 parent 4b264b8 commit 8abdf5a

File tree

2 files changed

+49
-3
lines changed

2 files changed

+49
-3
lines changed

src/content.js

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,24 @@ export function getTagsByName (host, range, tagName) {
180180
})
181181
}
182182

183+
export function getTagsByNameAndAttributes (host, range, elem) {
184+
return getTags(host, range, (node) => {
185+
return node.nodeName === elem.nodeName.toUpperCase() &&
186+
areSameAttributes(node.attributes, elem.attributes)
187+
})
188+
}
189+
190+
export function areSameAttributes (attrs1, attrs2) {
191+
if (attrs1.length !== attrs2.length) return false
192+
193+
for (var i = 0; i < attrs1.length; i++) {
194+
const attr = attrs2[attrs1[i].name]
195+
if (!(attr && attr.value === attrs1[i].value)) return false
196+
}
197+
198+
return true
199+
}
200+
183201
// Get all tags that start or end inside the range
184202
export function getInnerTags (range, filterFunc) {
185203
return range.getNodes([nodeType.elementNode], filterFunc)
@@ -233,11 +251,11 @@ export function expandTo (host, range, elem) {
233251
}
234252

235253
export function toggleTag (host, range, elem) {
236-
const elems = getTagsByName(host, range, elem.nodeName)
254+
const elems = getTagsByNameAndAttributes(host, range, elem)
237255

238256
if (elems.length === 1 &&
239257
isExactSelection(range, elems[0], 'visible')) {
240-
return removeFormatting(host, range, elem.nodeName)
258+
return removeFormattingElem(host, range, elem)
241259
}
242260

243261
return forceWrap(host, range, elem)
@@ -249,7 +267,7 @@ export function isWrappable (range) {
249267

250268
export function forceWrap (host, range, elem) {
251269
let restoredRange = restoreRange(host, range, () => {
252-
nuke(host, range, elem.nodeName)
270+
nukeElem(host, range, elem)
253271
})
254272

255273
// remove all tags if the range is not wrappable
@@ -285,6 +303,12 @@ export function unwrap (elem) {
285303
: $elem.remove()
286304
}
287305

306+
export function removeFormattingElem (host, range, elem) {
307+
return restoreRange(host, range, () => {
308+
nukeElem(host, range, elem)
309+
})
310+
}
311+
288312
export function removeFormatting (host, range, tagName) {
289313
return restoreRange(host, range, () => {
290314
nuke(host, range, tagName)
@@ -301,6 +325,18 @@ export function nuke (host, range, tagName) {
301325
})
302326
}
303327

328+
// Unwrap all tags this range is affected by.
329+
// Can also affect content outside of the range.
330+
export function nukeElem (host, range, node) {
331+
getTags(host, range).forEach((elem) => {
332+
if (elem.nodeName !== 'BR' && (!node ||
333+
(elem.nodeName === node.nodeName.toUpperCase() &&
334+
areSameAttributes(elem.attributes, node.attributes)))) {
335+
unwrap(elem)
336+
}
337+
})
338+
}
339+
304340
// Insert a single character (or string) before or after the
305341
// the range.
306342
export function insertCharacter (range, character, atStart) {

src/selection.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,16 @@ export default class Selection extends Cursor {
119119
this.setSelection()
120120
}
121121

122+
toggleCustom ({elem, attributes}) {
123+
const customElem = this.createElement(elem, attributes)
124+
this.toggle(customElem)
125+
}
126+
127+
makeCustom ({elem, attributes}) {
128+
const customElem = this.createElement(elem, attributes)
129+
this.forceWrap(customElem)
130+
}
131+
122132
makeBold () {
123133
const bold = this.createElement(config.boldMarkup.name, config.boldMarkup.attribs)
124134
this.forceWrap(bold)

0 commit comments

Comments
 (0)