Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added backgroundColorSpan support v3 #1041

Merged
merged 34 commits into from
May 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
f00c599
New Feature, support for BackgroundColorSpan:
felipevaladares May 26, 2020
8dd7d9a
- Added new icons for ToolbarAction.BACKGROUND
felipevaladares May 26, 2020
34175a8
- Example of multiple bg colors
felipevaladares May 26, 2020
6ae030b
- General improvements, removing code that is not necessary
felipevaladares May 26, 2020
cc8533d
- Fix bug when handling with multiple bg colors
felipevaladares May 26, 2020
ded1c56
- Fix ktlint issue
felipevaladares May 26, 2020
536d95d
- Fix bug https://github.com/wordpress-mobile/AztecEditor-Android/iss…
felipevaladares Jun 30, 2020
c6a1bcf
- Improved bg color implementation, fix bugs when using multiple back…
felipevaladares Jul 2, 2020
3213bc2
- Fix lint errors
felipevaladares Jul 2, 2020
a96ef7c
-
felipevaladares Jul 2, 2020
ba6962d
- Fix broken test, changing to 'em' because it comes first on the ita…
felipevaladares Jul 2, 2020
a95d50e
- Removing bg color button from toolbar, Added BackgroundColorButton …
felipevaladares Jul 3, 2020
936884e
- Removing bg color from ToolbarAction
felipevaladares Jul 3, 2020
40503ef
- Fix highlight color not appearing when BackgroundColorSpan is applied
felipevaladares Jul 3, 2020
c876547
- Fix lint error, added alpha for custom implementations on AztecBack…
felipevaladares Jul 3, 2020
3a99a6e
- Added possibility to clear references from toolbar and editor, to f…
felipevaladares Jul 6, 2020
a00fd4a
- Fix lint error
felipevaladares Jul 6, 2020
76266cb
Merge tag 'v1.3.45' into feature/background-color-span-support
lvcasasanta Jan 21, 2021
aa13895
Fix the bug that keeps background button highlighted
lvcasasanta Jan 22, 2021
b25b30b
Returning removeInlineCssStyle method
lvcasasanta Jan 22, 2021
4c1566e
Removing attributes from constructor
lvcasasanta Jan 22, 2021
3523beb
Visual Editor is using "blue_dark" #005082
lvcasasanta Jan 22, 2021
810fe3d
Remove unnecessary check
lvcasasanta Jan 22, 2021
b58d9bd
lint: address ktlint concerns
yuvalgnessin-qz Jan 27, 2021
4261e37
test: fix broken unit tests and add BG color tests
yuvalgnessin-qz Jan 27, 2021
bdbce24
Revert "Remove unnecessary check"
yuvalgnessin-qz Feb 2, 2021
ab286ed
fix: disable BG color if it is not added as a plugin
yuvalgnessin-qz Feb 8, 2021
baad141
fix: add null check for toolbar action views
yuvalgnessin-qz Mar 12, 2021
ca1e1e0
Merge branch 'develop' into feature/background-color-span-support-v3
yuvalgnessin-qz Jan 24, 2023
a583de2
fix: use ContextCompat in MainActivity
yuvalgnessin-qz Jan 24, 2023
76e9c03
Merge branch 'trunk' into feature/background-color-span-support-v3-up…
yuvalgnessin-qz Apr 4, 2023
4fb183b
style: fix whitespace, imports, and comments messed up by upstream merge
yuvalgnessin-qz Apr 4, 2023
25a55b6
fix: revert Felipe's changes that introduced bugs caught by tests
yuvalgnessin-qz Apr 4, 2023
714318b
fix: remove background color spans when removing inline CSS styles
yuvalgnessin-qz Apr 4, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions app/src/main/kotlin/org/wordpress/aztec/demo/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.content.res.AppCompatResources
import androidx.core.app.ActivityCompat.OnRequestPermissionsResultCallback
import androidx.core.content.ContextCompat
import androidx.core.content.FileProvider
import org.wordpress.android.util.AppLog
import org.wordpress.android.util.ImageUtils
Expand All @@ -48,6 +49,8 @@ import org.wordpress.aztec.IHistoryListener
import org.wordpress.aztec.ITextFormat
import org.wordpress.aztec.glideloader.GlideImageLoader
import org.wordpress.aztec.glideloader.GlideVideoThumbnailLoader
import org.wordpress.aztec.plugins.BackgroundColorButton
import org.wordpress.aztec.plugins.CssBackgroundColorPlugin
import org.wordpress.aztec.plugins.CssUnderlinePlugin
import org.wordpress.aztec.plugins.IMediaToolbarButton
import org.wordpress.aztec.plugins.shortcodes.AudioShortcodePlugin
Expand Down Expand Up @@ -92,6 +95,7 @@ open class MainActivity : AppCompatActivity(),
private val BOLD = "<b>Bold</b><br>"
private val ITALIC = "<i style=\"color:darkred\">Italic</i><br>"
private val UNDERLINE = "<u style=\"color:lime\">Underline</u><br>"
private val BACKGROUND = "<span style=\"background-color:#005082\">BACK<b>GROUND</b></span><br>"
private val STRIKETHROUGH = "<s style=\"color:#ff666666\" class=\"test\">Strikethrough</s><br>" // <s> or <strike> or <del>
private val ORDERED = "<ol style=\"color:green\"><li>Ordered</li><li>should have color</li></ol>"
private val TASK_LIST = "<ul type=\"task-list\">\n" +
Expand Down Expand Up @@ -193,6 +197,7 @@ open class MainActivity : AppCompatActivity(),
BOLD +
ITALIC +
UNDERLINE +
BACKGROUND +
STRIKETHROUGH +
TASK_LIST +
ORDERED +
Expand Down Expand Up @@ -484,9 +489,13 @@ open class MainActivity : AppCompatActivity(),
aztec.visualEditor.setCalypsoMode(false)
aztec.sourceEditor?.setCalypsoMode(false)

aztec.visualEditor.setBackgroundSpanColor(ContextCompat.getColor(this, R.color.blue_dark))

aztec.sourceEditor?.displayStyledAndFormattedHtml(EXAMPLE)

aztec.addPlugin(CssUnderlinePlugin())
aztec.addPlugin(CssBackgroundColorPlugin())
aztec.addPlugin(BackgroundColorButton(visualEditor))
}

if (savedInstanceState == null) {
Expand Down
21 changes: 20 additions & 1 deletion aztec/src/main/kotlin/org/wordpress/aztec/AztecTagHandler.kt
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@ import android.text.Spanned
import androidx.appcompat.content.res.AppCompatResources
import org.wordpress.aztec.plugins.IAztecPlugin
import org.wordpress.aztec.plugins.html2visual.IHtmlTagHandler
import org.wordpress.aztec.source.CssStyleFormatter
import org.wordpress.aztec.spans.AztecAudioSpan
import org.wordpress.aztec.spans.AztecBackgroundColorSpan
import org.wordpress.aztec.spans.AztecHorizontalRuleSpan
import org.wordpress.aztec.spans.AztecImageSpan
import org.wordpress.aztec.spans.AztecListItemSpan
Expand All @@ -41,6 +43,7 @@ import org.wordpress.aztec.spans.AztecVideoSpan
import org.wordpress.aztec.spans.HiddenHtmlSpan
import org.wordpress.aztec.spans.IAztecAttributedSpan
import org.wordpress.aztec.spans.IAztecNestable
import org.wordpress.aztec.spans.IAztecSpan
import org.wordpress.aztec.spans.createAztecQuoteSpan
import org.wordpress.aztec.spans.createHeadingSpan
import org.wordpress.aztec.spans.createHiddenHtmlBlockSpan
Expand All @@ -51,6 +54,7 @@ import org.wordpress.aztec.spans.createParagraphSpan
import org.wordpress.aztec.spans.createPreformatSpan
import org.wordpress.aztec.spans.createTaskListSpan
import org.wordpress.aztec.spans.createUnorderedListSpan
import org.wordpress.aztec.util.ColorConverter
import org.wordpress.aztec.util.getLast
import org.xml.sax.Attributes
import java.util.Locale
Expand Down Expand Up @@ -87,7 +91,7 @@ class AztecTagHandler(val context: Context, val plugins: List<IAztecPlugin> = Ar
return true
}
SPAN -> {
val span = createHiddenHtmlSpan(tag, AztecAttributes(attributes), nestingLevel, alignmentRendering)
val span = handleBackgroundColorSpanTag(attributes, tag, nestingLevel)
handleElement(output, opening, span)
return true
}
Expand Down Expand Up @@ -170,6 +174,21 @@ class AztecTagHandler(val context: Context, val plugins: List<IAztecPlugin> = Ar
return false
}

private fun handleBackgroundColorSpanTag(attributes: Attributes, tag: String, nestingLevel: Int): IAztecSpan {
val attrs = AztecAttributes(attributes)
return if (CssStyleFormatter.containsStyleAttribute(
attrs,
CssStyleFormatter.CSS_BACKGROUND_COLOR_ATTRIBUTE
) || (tagStack.isNotEmpty() && tagStack.last() is AztecBackgroundColorSpan)
) {
val att = CssStyleFormatter.getStyleAttribute(attrs, CssStyleFormatter.CSS_BACKGROUND_COLOR_ATTRIBUTE)
val color = ColorConverter.getColorInt(att)
AztecBackgroundColorSpan(color)
} else {
createHiddenHtmlSpan(tag, attrs, nestingLevel, alignmentRendering)
}
}

/**
* This method takes the checkbox input inside a list item and applies a parameter to the parent list item.
* We convert <li><input type=checkbox checked />Test</li>
Expand Down
9 changes: 8 additions & 1 deletion aztec/src/main/kotlin/org/wordpress/aztec/AztecText.kt
Original file line number Diff line number Diff line change
Expand Up @@ -405,6 +405,10 @@ open class AztecText : AppCompatEditText, TextWatcher, UnknownHtmlSpan.OnUnknown
isInCalypsoMode = isCompatibleWithCalypso
}

fun setBackgroundSpanColor(color: Int) {
inlineFormatter.backgroundSpanColor = color
}

fun setGutenbergMode(isCompatibleWithGutenberg: Boolean) {
isInGutenbergMode = isCompatibleWithGutenberg
}
Expand Down Expand Up @@ -1304,6 +1308,7 @@ open class AztecText : AppCompatEditText, TextWatcher, UnknownHtmlSpan.OnUnknown
AztecTextFormat.FORMAT_CITE,
AztecTextFormat.FORMAT_UNDERLINE,
AztecTextFormat.FORMAT_STRIKETHROUGH,
AztecTextFormat.FORMAT_BACKGROUND,
AztecTextFormat.FORMAT_HIGHLIGHT,
AztecTextFormat.FORMAT_CODE -> inlineFormatter.toggle(textFormat)
AztecTextFormat.FORMAT_BOLD,
Expand Down Expand Up @@ -1344,6 +1349,7 @@ open class AztecText : AppCompatEditText, TextWatcher, UnknownHtmlSpan.OnUnknown
AztecTextFormat.FORMAT_CITE,
AztecTextFormat.FORMAT_UNDERLINE,
AztecTextFormat.FORMAT_STRIKETHROUGH,
AztecTextFormat.FORMAT_BACKGROUND,
AztecTextFormat.FORMAT_MARK,
AztecTextFormat.FORMAT_HIGHLIGHT,
AztecTextFormat.FORMAT_CODE -> return inlineFormatter.containsInlineStyle(format, selStart, selEnd)
Expand All @@ -1360,7 +1366,7 @@ open class AztecText : AppCompatEditText, TextWatcher, UnknownHtmlSpan.OnUnknown
}
}

fun setToolbar(toolbar: IAztecToolbar) {
fun setToolbar(toolbar: IAztecToolbar?) {
formatToolbar = toolbar
}

Expand Down Expand Up @@ -1844,6 +1850,7 @@ open class AztecText : AppCompatEditText, TextWatcher, UnknownHtmlSpan.OnUnknown
inlineFormatter.removeInlineStyle(AztecTextFormat.FORMAT_STRIKETHROUGH, start, end)
inlineFormatter.removeInlineStyle(AztecTextFormat.FORMAT_UNDERLINE, start, end)
inlineFormatter.removeInlineStyle(AztecTextFormat.FORMAT_CODE, start, end)
inlineFormatter.removeInlineStyle(AztecTextFormat.FORMAT_BACKGROUND, start, end)
inlineFormatter.removeInlineStyle(AztecTextFormat.FORMAT_MARK, start, end)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ enum class AztecTextFormat : ITextFormat {
FORMAT_FONT,
FORMAT_MONOSPACE,
FORMAT_CODE,
FORMAT_BACKGROUND,
FORMAT_MARK,
FORMAT_HIGHLIGHT
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package org.wordpress.aztec.formatting

import android.graphics.Typeface
import android.text.Spanned
import android.text.style.BackgroundColorSpan
import android.text.style.ForegroundColorSpan
import android.text.style.StyleSpan
import androidx.annotation.ColorRes
Expand All @@ -12,14 +13,16 @@ import org.wordpress.aztec.AztecText
import org.wordpress.aztec.AztecTextFormat
import org.wordpress.aztec.Constants
import org.wordpress.aztec.ITextFormat
import org.wordpress.aztec.R
import org.wordpress.aztec.spans.AztecBackgroundColorSpan
import org.wordpress.aztec.spans.AztecCodeSpan
import org.wordpress.aztec.spans.AztecStrikethroughSpan
import org.wordpress.aztec.spans.AztecStyleBoldSpan
import org.wordpress.aztec.spans.AztecStyleCiteSpan
import org.wordpress.aztec.spans.AztecStyleItalicSpan
import org.wordpress.aztec.spans.AztecStyleEmphasisSpan
import org.wordpress.aztec.spans.AztecStyleStrongSpan
import org.wordpress.aztec.spans.AztecStyleItalicSpan
import org.wordpress.aztec.spans.AztecStyleSpan
import org.wordpress.aztec.spans.AztecStyleStrongSpan
import org.wordpress.aztec.spans.AztecUnderlineSpan
import org.wordpress.aztec.spans.HighlightSpan
import org.wordpress.aztec.spans.IAztecExclusiveInlineSpan
Expand All @@ -33,6 +36,8 @@ import org.wordpress.aztec.watchers.TextChangedEvent
*/
class InlineFormatter(editor: AztecText, val codeStyle: CodeStyle, private val highlightStyle: HighlightStyle) : AztecFormatter(editor) {

var backgroundSpanColor: Int? = null

data class CodeStyle(val codeBackground: Int, val codeBackgroundAlpha: Float, val codeColor: Int)
data class HighlightStyle(@ColorRes val color: Int)

Expand Down Expand Up @@ -93,6 +98,7 @@ class InlineFormatter(editor: AztecText, val codeStyle: CodeStyle, private val h
AztecTextFormat.FORMAT_EMPHASIS,
AztecTextFormat.FORMAT_CITE,
AztecTextFormat.FORMAT_STRIKETHROUGH,
AztecTextFormat.FORMAT_BACKGROUND,
AztecTextFormat.FORMAT_UNDERLINE,
AztecTextFormat.FORMAT_CODE -> {
applyInlineStyle(item, textChangedEvent.inputStart, textChangedEvent.inputEnd)
Expand Down Expand Up @@ -146,6 +152,11 @@ class InlineFormatter(editor: AztecText, val codeStyle: CodeStyle, private val h
return
}

if (textFormat == AztecTextFormat.FORMAT_BACKGROUND) {
//clear previous background before applying a new one to avoid problems when using multiple bg colors
removeBackgroundInSelection(selectionStart, selectionEnd)
}

var precedingSpan: IAztecInlineSpan? = null
var followingSpan: IAztecInlineSpan? = null

Expand Down Expand Up @@ -211,6 +222,34 @@ class InlineFormatter(editor: AztecText, val codeStyle: CodeStyle, private val h
joinStyleSpans(start, end)
}

private fun removeBackgroundInSelection(selStart: Int, selEnd: Int) {
val spans = editableText.getSpans(selStart, selEnd, AztecBackgroundColorSpan::class.java)
spans.forEach { span ->
if (span != null) {
val currentSpanStart = editableText.getSpanStart(span)
val currentSpanEnd = editableText.getSpanEnd(span)
val color = span.backgroundColor
editableText.removeSpan(span)
if (selEnd < currentSpanEnd) {
editableText.setSpan(
AztecBackgroundColorSpan(color),
selEnd,
currentSpanEnd,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
)
}
if (selStart > currentSpanStart) {
editableText.setSpan(
AztecBackgroundColorSpan(color),
currentSpanStart,
selStart,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
)
}
}
}
}

private fun applyMarkInlineStyle(start: Int = selectionStart, end: Int = selectionEnd) {
val previousSpans = editableText.getSpans(start, end, MarkSpan::class.java)
previousSpans.forEach {
Expand Down Expand Up @@ -247,6 +286,7 @@ class InlineFormatter(editor: AztecText, val codeStyle: CodeStyle, private val h
AztecStrikethroughSpan::class.java -> AztecTextFormat.FORMAT_STRIKETHROUGH
AztecUnderlineSpan::class.java -> AztecTextFormat.FORMAT_UNDERLINE
AztecCodeSpan::class.java -> AztecTextFormat.FORMAT_CODE
AztecBackgroundColorSpan::class.java -> return AztecTextFormat.FORMAT_BACKGROUND
MarkSpan::class.java -> AztecTextFormat.FORMAT_MARK
HighlightSpan::class.java -> AztecTextFormat.FORMAT_HIGHLIGHT
else -> null
Expand All @@ -265,6 +305,7 @@ class InlineFormatter(editor: AztecText, val codeStyle: CodeStyle, private val h
editableText.removeSpan(it)
}
}

// remove the CSS style span
removeInlineCssStyle()

Expand All @@ -282,9 +323,11 @@ class InlineFormatter(editor: AztecText, val codeStyle: CodeStyle, private val h
joinStyleSpans(start, end)
}

fun removeInlineCssStyle(start: Int = selectionStart, end: Int = selectionEnd) {
val spans = editableText.getSpans(start, end, ForegroundColorSpan::class.java)
spans.forEach {
private fun removeInlineCssStyle(start: Int = selectionStart, end: Int = selectionEnd) {
editableText.getSpans(start, end, ForegroundColorSpan::class.java).forEach {
editableText.removeSpan(it)
}
editableText.getSpans(start, end, BackgroundColorSpan::class.java).forEach {
editableText.removeSpan(it)
}
}
Expand All @@ -298,6 +341,10 @@ class InlineFormatter(editor: AztecText, val codeStyle: CodeStyle, private val h
if (firstSpan is StyleSpan && secondSpan is StyleSpan) {
return firstSpan.style == secondSpan.style
}
// special check for BackgroundSpan
if (firstSpan is AztecBackgroundColorSpan && secondSpan is AztecBackgroundColorSpan) {
return firstSpan.backgroundColor == secondSpan.backgroundColor
}

return firstSpan.javaClass == secondSpan.javaClass
}
Expand Down Expand Up @@ -393,6 +440,7 @@ class InlineFormatter(editor: AztecText, val codeStyle: CodeStyle, private val h
AztecTextFormat.FORMAT_STRIKETHROUGH -> AztecStrikethroughSpan()
AztecTextFormat.FORMAT_UNDERLINE -> AztecUnderlineSpan()
AztecTextFormat.FORMAT_CODE -> AztecCodeSpan(codeStyle)
AztecTextFormat.FORMAT_BACKGROUND -> AztecBackgroundColorSpan(backgroundSpanColor ?: R.color.background)
AztecTextFormat.FORMAT_HIGHLIGHT -> {
HighlightSpan(highlightStyle = highlightStyle, context = editor.context)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package org.wordpress.aztec.plugins

import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import org.wordpress.aztec.AztecText
import org.wordpress.aztec.R
import org.wordpress.aztec.toolbar.AztecToolbar
import org.wordpress.aztec.toolbar.IToolbarAction
import org.wordpress.aztec.toolbar.ToolbarAction

class BackgroundColorButton(private val visualEditor: AztecText) : IToolbarButton {

override val action: IToolbarAction = ToolbarAction.BACKGROUND
override val context = visualEditor.context!!

override fun toggle() {
visualEditor.toggleFormatting(action.textFormats.first())
}

override fun inflateButton(parent: ViewGroup) {
LayoutInflater.from(context).inflate(R.layout.background_color_button, parent)
}

override fun toolbarStateAboutToChange(toolbar: AztecToolbar, enable: Boolean) {
toolbar.findViewById<View>(action.buttonId).isEnabled = enable
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package org.wordpress.aztec.plugins

import android.text.SpannableStringBuilder
import org.wordpress.aztec.plugins.visual2html.ISpanPreprocessor
import org.wordpress.aztec.source.CssStyleFormatter
import org.wordpress.aztec.spans.AztecBackgroundColorSpan

class CssBackgroundColorPlugin : ISpanPreprocessor {

override fun beforeSpansProcessed(spannable: SpannableStringBuilder) {
spannable.getSpans(0, spannable.length, AztecBackgroundColorSpan::class.java).forEach {
if (!CssStyleFormatter.containsStyleAttribute(it.attributes, CssStyleFormatter.CSS_BACKGROUND_COLOR_ATTRIBUTE)) {
CssStyleFormatter.addStyleAttribute(it.attributes, CssStyleFormatter.CSS_BACKGROUND_COLOR_ATTRIBUTE, it.getColorHex())
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ class CssStyleFormatter {

/**
* Check the provided [attributedSpan] for the *style* attribute. If found, parse out the
* supported CSS style properties and use the results to create a [ForegroundColorSpan],
* supported CSS style properties and use the results to create a [ForegroundColorSpan] and/or [BackgroundColorSpan]
* then add it to the provided [text].
*
* Must be called immediately after the base [IAztecAttributedSpan] has been processed.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package org.wordpress.aztec.spans

import android.graphics.Color
import android.text.TextPaint
import android.text.style.BackgroundColorSpan
import org.wordpress.aztec.AztecAttributes

class AztecBackgroundColorSpan(
val color: Int
) : BackgroundColorSpan(color), IAztecInlineSpan {

var alpha: Int = 220
var tag: String = "span"
override var attributes: AztecAttributes = AztecAttributes()

fun getColorHex(): String {
return java.lang.String.format("#%06X", 0xFFFFFF and color)
}

override fun updateDrawState(textPaint: TextPaint) {
textPaint.bgColor = Color.argb(alpha, Color.red(color), Color.green(color), Color.blue(color))
}

override val TAG = tag
}
Loading