Skip to content

Commit fe554bb

Browse files
authored
Merge branch 'develop' into issue/464-missing-suggestions
2 parents 311e819 + 462503f commit fe554bb

File tree

20 files changed

+254
-36
lines changed

20 files changed

+254
-36
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
# Changelog
22

3+
## [Unreleased]
4+
### Fixed
5+
- Paragraphs with attributes being removed
36

47
## [1.0-beta.10](https://github.com/wordpress-mobile/AztecEditor-Android/releases/tag/v1.0-beta.10) - 2017-10-06
58
### Fixed

README.md

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,58 @@ documents in Android.
88

99
Supports Android 4.1+ (API 16 - Jelly Bean)
1010

11+
## Getting started
12+
13+
Declare the main components in your layout:
14+
15+
Visual editor
16+
```XML
17+
<org.wordpress.aztec.AztecText
18+
android:id="@+id/visual"
19+
android:layout_width="match_parent"
20+
android:layout_height="match_parent"
21+
android:scrollbars="vertical"
22+
android:imeOptions="flagNoExtractUi"
23+
aztec:historyEnable="false" />
24+
```
25+
Source editor
26+
```XML
27+
<org.wordpress.aztec.source.SourceViewEditText
28+
android:id="@+id/source"
29+
android:layout_width="match_parent"
30+
android:layout_height="match_parent"
31+
android:inputType="textNoSuggestions|textMultiLine"
32+
android:scrollbars="vertical"
33+
android:imeOptions="flagNoExtractUi"
34+
aztec:codeBackgroundColor="@android:color/transparent"
35+
aztec:codeTextColor="@android:color/white" />
36+
```
37+
38+
Toolbar
39+
```XML
40+
<org.wordpress.aztec.toolbar.AztecToolbar
41+
android:id="@+id/formatting_toolbar"
42+
android:layout_width="match_parent"
43+
android:layout_height="@dimen/format_bar_height"
44+
android:layout_alignParentBottom="true" />
45+
```
46+
47+
Inflate the views:
48+
```kotlin
49+
val visualEditor = findViewById<AztecText>(R.id.visual)
50+
val sourceEditor = findViewById<SourceViewEditText>(R.id.source)
51+
val toolbar = findViewById<AztecToolbar>(R.id.formatting_toolbar)
52+
```
53+
54+
Configure Aztec with a provided image & video loaders:
55+
```kotlin
56+
Aztec.with(visualEditor, sourceEditor, toolbar, context)
57+
.setImageGetter(GlideImageLoader(context))
58+
.setVideoThumbnailGetter(GlideVideoThumbnailLoader(context))
59+
```
60+
61+
For more options, such as edit history, listeners and plugins please refer to the [demo app implementation](https://github.com/wordpress-mobile/AztecEditor-Android/blob/9fdc1958ca1e1ad5de6fba15dabe251bcf0fc7b6/app/src/main/kotlin/org/wordpress/aztec/demo/MainActivity.kt#L331-L346).
62+
1163
## Build and test
1264

1365
Build the library, build the example project and run unit tests:
@@ -39,7 +91,7 @@ On your device, under Settings -> Accessibility -> Touch & hold delay, set the d
3991
Run the instrumentation tests:
4092

4193
```shell
42-
$ adb shell am instrument -w -r -e package org.wordpress.aztec.demo -e debug false org.wordpress.aztec.test/android.support.test.runner.AndroidJUnitRunner
94+
$ ./gradlew cAT
4395
```
4496

4597
## Integrating Aztec in your project

app/src/androidTest/kotlin/org/wordpress/aztec/demo/tests/ImageTests.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ class ImageTests : BaseTest() {
5050

5151
@Test
5252
fun testAddTwoPhotos() {
53-
val regex = Regex(".*<img src=.+>.*<img src=.+>.*")
53+
val regex = Regex(".*<img src=.+>.*<img src=.+>.*", RegexOption.DOT_MATCHES_ALL)
5454

5555
createImageIntentFilter()
5656
addPhotoWithHTML()

app/src/androidTest/kotlin/org/wordpress/aztec/demo/tests/MixedTextFormattingTests.kt

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,21 @@ class MixedTextFormattingTests : BaseTest() {
6666
.verifyHTML(html2)
6767
}
6868

69+
@Test
70+
fun testRetainParagraphFormatting() {
71+
// Paragraph are only retained if they have at least one attribute
72+
// https://github.com/wordpress-mobile/AztecEditor-Android/pull/483#discussion_r151377857
73+
val text = "some text"
74+
val html = "<p a=\"ok\">$text</p>"
75+
76+
EditorPage()
77+
.toggleHtml()
78+
.insertHTML(html)
79+
.toggleHtml()
80+
.toggleHtml()
81+
.verifyHTML(html)
82+
}
83+
6984
@Test
7085
fun testRetainHeadingFormatting() {
7186
val text = "some text"

app/src/main/kotlin/org/wordpress/aztec/demo/MainActivity.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ import org.wordpress.aztec.toolbar.IAztecToolbarClickListener
5757
import org.wordpress.aztec.watchers.BlockElementWatcher
5858
import org.xml.sax.Attributes
5959
import java.io.File
60+
import java.util.Random
6061

6162
open class MainActivity : AppCompatActivity(),
6263
AztecText.OnImeBackListener,
@@ -252,8 +253,7 @@ open class MainActivity : AppCompatActivity(),
252253
}
253254

254255
private fun generateAttributesForMedia(mediaPath: String, isVideo: Boolean): Pair<String, AztecAttributes> {
255-
val id = (Math.random() * Int.MAX_VALUE).toString()
256-
256+
val id = Random().nextInt(Integer.MAX_VALUE).toString()
257257
val attrs = AztecAttributes()
258258
attrs.setValue("src", mediaPath) // Temporary source value. Replace with URL after uploaded.
259259
attrs.setValue("id", id)
@@ -346,7 +346,7 @@ open class MainActivity : AppCompatActivity(),
346346
.addPlugin(AudioShortcodePlugin())
347347

348348
BlockElementWatcher(visualEditor)
349-
.add(CaptionHandler())
349+
.add(CaptionHandler(visualEditor))
350350
.install(visualEditor)
351351

352352
// initialize the text & HTML

aztec/src/main/kotlin/org/wordpress/aztec/AztecTagHandler.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ class AztecTagHandler(val context: Context, val plugins: List<IAztecPlugin> = Ar
9898
return true
9999
}
100100
IMAGE -> {
101-
handleMediaElement(opening, output, AztecImageSpan(context, loadingDrawable, AztecAttributes(attributes)))
101+
handleMediaElement(opening, output, AztecImageSpan(context, loadingDrawable, nestingLevel, AztecAttributes(attributes)))
102102
return true
103103
}
104104
VIDEO -> {

aztec/src/main/kotlin/org/wordpress/aztec/AztecText.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -905,7 +905,7 @@ class AztecText : AppCompatEditText, TextWatcher, UnknownHtmlSpan.OnUnknownHtmlT
905905

906906
parser.syncVisualNewlinesOfBlockElements(output)
907907

908-
Format.postProcessSpanedText(output, isInCalypsoMode)
908+
Format.postProcessSpannedText(output, isInCalypsoMode)
909909

910910
return EndOfBufferMarkerAdder.removeEndOfTextMarker(parser.toHtml(output, withCursorTag))
911911
}
@@ -1064,7 +1064,7 @@ class AztecText : AppCompatEditText, TextWatcher, UnknownHtmlSpan.OnUnknownHtmlT
10641064

10651065
clearMetaSpans(output)
10661066
parser.syncVisualNewlinesOfBlockElements(output)
1067-
Format.postProcessSpanedText(output, isInCalypsoMode)
1067+
Format.postProcessSpannedText(output, isInCalypsoMode)
10681068

10691069
// do not copy unnecessary block hierarchy, just the minimum required
10701070
var deleteNext = false

aztec/src/main/kotlin/org/wordpress/aztec/formatting/LineBlockFormatter.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,8 @@ class LineBlockFormatter(editor: AztecText) : AztecFormatter(editor) {
133133

134134
fun insertImage(drawable: Drawable?, attributes: Attributes, onImageTappedListener: OnImageTappedListener?,
135135
onMediaDeletedListener: AztecText.OnMediaDeletedListener?) {
136-
val span = AztecImageSpan(editor.context, drawable, AztecAttributes(attributes), onImageTappedListener,
136+
val nestingLevel = IAztecNestable.getNestingLevelAt(editableText, selectionStart)
137+
val span = AztecImageSpan(editor.context, drawable, nestingLevel, AztecAttributes(attributes), onImageTappedListener,
137138
onMediaDeletedListener, editor)
138139
insertMedia(span)
139140
}

aztec/src/main/kotlin/org/wordpress/aztec/plugins/IToolbarButton.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package org.wordpress.aztec.plugins
33
import android.content.Context
44
import android.view.KeyEvent
55
import android.view.ViewGroup
6+
import org.wordpress.aztec.toolbar.AztecToolbar
67
import org.wordpress.aztec.toolbar.IToolbarAction
78
import org.wordpress.aztec.toolbar.RippleToggleButton
89

@@ -40,4 +41,11 @@ interface IToolbarButton : IAztecPlugin {
4041
* @param parent view to be the parent of the generated hierarchy.
4142
*/
4243
fun inflateButton(parent: ViewGroup)
44+
45+
/**
46+
* Signals the ToolbarButton that the toolbar is about to change its enabled/disabled state
47+
*
48+
* This method is called when the toolbar buttons get "disabled/enabled"
49+
*/
50+
fun toolbarStateAboutToChange(toolbar: AztecToolbar, enable: Boolean)
4351
}

aztec/src/main/kotlin/org/wordpress/aztec/source/Format.kt

Lines changed: 32 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -108,11 +108,10 @@ internal object Format {
108108
}
109109

110110
// Pretty it up for the source editor
111-
val blocklist = "blockquote|ul|ol|li|table|thead|tbody|tfoot|tr|th|td|h[1-6]|fieldset"
112-
val blocklist1 = blocklist + "|div|p"
111+
val blocklist = "blockquote|ul|ol|li|table|thead|tbody|tfoot|tr|th|td|h[1-6]|fieldset|div|p"
113112

114-
content = replaceAll(content, "\\s*</($blocklist1)>\\s*", "</$1>\n")
115-
content = replaceAll(content, "\\s*<((?:$blocklist1)(?: [^>]*)?)>", "\n<$1>")
113+
content = replaceAll(content, "\\s*</($blocklist)>\\s*", "</$1>\n")
114+
content = replaceAll(content, "\\s*<((?:$blocklist)(?: [^>]*)?)>", "\n<$1>")
116115

117116
content = replaceAll(content, "\\s*<(!--.*?--|hr)>\\s*", "\n\n<$1>\n\n")
118117

@@ -153,7 +152,7 @@ internal object Format {
153152
}
154153

155154
// Unmark special paragraph closing tags
156-
content = replaceAll(content, "</p#>", "</p>\n")
155+
content = replaceAll(content, "</p#>", "</p>")
157156
content = replaceAll(content, "\\s*(<p [^>]+>[\\s\\S]*?</p>)", "\n$1")
158157

159158
// Trim whitespace
@@ -307,13 +306,15 @@ internal object Format {
307306
}
308307

309308
// we don't need paragraph spans in calypso at this point
310-
text.getSpans(0, text.length, ParagraphSpan::class.java).forEach {
311-
text.removeSpan(it)
312-
}
309+
text.getSpans(0, text.length, ParagraphSpan::class.java)
310+
.filter { it.attributes.isEmpty() }
311+
.forEach {
312+
text.removeSpan(it)
313+
}
313314
}
314315
}
315316

316-
fun postProcessSpanedText(text: SpannableStringBuilder, isCalypsoFormat: Boolean) {
317+
fun postProcessSpannedText(text: SpannableStringBuilder, isCalypsoFormat: Boolean) {
317318
if (isCalypsoFormat) {
318319
val spans = text.getSpans(0, text.length, EndOfParagraphMarker::class.java)
319320
spans.sortByDescending { text.getSpanStart(it) }
@@ -324,20 +325,36 @@ internal object Format {
324325
val spanEnd = text.getSpanEnd(it)
325326

326327
if (text[spanStart] == '\n' && text.getSpans(spanEnd, spanEnd + 1, IAztecParagraphStyle::class.java)
327-
.filter { it !is ParagraphSpan && text.getSpanStart(it) == spanEnd }.isEmpty()) {
328+
.filter { (it !is ParagraphSpan || !it.attributes.isEmpty()) && text.getSpanStart(it) == spanEnd }.isEmpty()) {
328329
text.insert(spanEnd, "\n")
329330
}
330331

331332
if (text.getSpans(spanStart, spanEnd, AztecQuoteSpan::class.java)
332-
.filter { text.getSpanEnd(it) == spanEnd }.isEmpty()) {
333+
.filter { text.getSpanEnd(it) == spanEnd }.isEmpty() &&
334+
text.getSpans(spanStart, spanEnd, ParagraphSpan::class.java)
335+
.filter { !it.attributes.isEmpty() }.isEmpty()) {
333336
text.getSpans(spanStart, spanEnd, AztecVisualLinebreak::class.java).forEach { text.removeSpan(it) }
334337
}
335338
}
336339

337-
// we don't care about actual ParagraphSpan in calypso - paragraphs are made from double newline
338-
text.getSpans(0, text.length, ParagraphSpan::class.java).forEach {
339-
text.removeSpan(it)
340-
}
340+
// split up paragraphs that contain double newlines
341+
text.getSpans(0, text.length, ParagraphSpan::class.java)
342+
.forEach {
343+
val start = text.getSpanStart(it)
344+
val end = text.getSpanEnd(it)
345+
val double = text.indexOf("\n\n", start)
346+
if (double != -1 && double < end) {
347+
text.setSpan(it, start, double + 1, text.getSpanFlags(it))
348+
text.setSpan(AztecVisualLinebreak(), double + 1, double + 2, text.getSpanFlags(it))
349+
}
350+
}
351+
352+
// we don't care about actual ParagraphSpan in calypso that don't have attributes or are empty (paragraphs are made from double newline)
353+
text.getSpans(0, text.length, ParagraphSpan::class.java)
354+
.filter { it.attributes.isEmpty() || text.getSpanStart(it) == text.getSpanEnd(it) - 1 }
355+
.forEach {
356+
text.removeSpan(it)
357+
}
341358
}
342359
}
343360

0 commit comments

Comments
 (0)