Index: sdk/lib/_internal/lib/js_string.dart |
diff --git a/sdk/lib/_internal/lib/js_string.dart b/sdk/lib/_internal/lib/js_string.dart |
index 66938214274b10605a277b25ee9dbe9c9aa5c890..6482d8bf0dc0c08f8bab289be3b2604cfd66506f 100644 |
--- a/sdk/lib/_internal/lib/js_string.dart |
+++ b/sdk/lib/_internal/lib/js_string.dart |
@@ -180,35 +180,80 @@ class JSString extends Interceptor implements String, JSIndexable { |
String trim() { |
const int CARRIAGE_RETURN = 0x0D; |
const int SPACE = 0x20; |
+ const int NEL = 0x85; |
+ const int BOM = 0xFEFF; |
+ // Start by doing JS trim. Then check if it leaves a NEL or BOM at |
+ // either end of the string. |
+ String result = JS("String", "#.trim()", this); |
+ |
+ if (result.length == 0) return result; |
+ int firstCode = result.codeUnitAt(0); |
int startIndex = 0; |
- while (startIndex < this.length) { |
- int codeUnit = this.codeUnitAt(startIndex); |
- if (codeUnit == SPACE || |
- codeUnit == CARRIAGE_RETURN || |
- _isWhitespace(codeUnit)) { |
- startIndex++; |
- } else { |
- break; |
+ if (firstCode == NEL || firstCode == BOM) { |
+ startIndex++; |
+ while (startIndex < result.length) { |
+ int codeUnit = result.codeUnitAt(startIndex); |
+ if (codeUnit == SPACE || |
+ codeUnit == CARRIAGE_RETURN || |
+ _isWhitespace(codeUnit)) { |
+ startIndex++; |
+ } else { |
+ break; |
+ } |
} |
+ if (startIndex == result.length) return ""; |
} |
- if (startIndex == this.length) return ""; |
- int endIndex = this.length; |
+ int endIndex = result.length; |
// We know that there is at least one character that is non-whitespace. |
// Therefore we don't need to verify that endIndex > startIndex. |
- while (true) { |
- int codeUnit = this.codeUnitAt(endIndex - 1); |
- if (codeUnit == SPACE || |
- codeUnit == CARRIAGE_RETURN || |
- _isWhitespace(codeUnit)) { |
- endIndex--; |
- } else { |
- break; |
+ int lastCode = result.codeUnitAt(endIndex - 1); |
+ if (lastCode == NEL || lastCode == BOM) { |
+ endIndex--; |
+ while (true) { |
+ int codeUnit = result.codeUnitAt(endIndex - 1); |
+ if (codeUnit == SPACE || |
+ codeUnit == CARRIAGE_RETURN || |
+ _isWhitespace(codeUnit)) { |
+ endIndex--; |
+ } else { |
+ break; |
+ } |
} |
} |
- if (startIndex == 0 && endIndex == this.length) return this; |
- return JS('String', r'#.substring(#, #)', this, startIndex, endIndex); |
+ if (startIndex == 0 && endIndex == result.length) return result; |
+ return JS('String', r'#.substring(#, #)', result, startIndex, endIndex); |
+ } |
+ |
+ String repeat(int times, [String separator = ""]) { |
+ if (times < 0) throw new RangeError.value(times); |
+ if (times == 0) return ""; |
+ if (separator.isEmpty) { |
+ return JS('String', "new Array(# + 1).join(#)", times, this); |
+ } else { |
+ var list = new JSArray.growable(times); |
+ for (int i = 0; i < times; i++) list[i] = this; |
+ return JS('String', "#.join(#)", list, separator); |
+ } |
+ } |
+ |
+ String padLeft(int newLength, String padding) { |
+ if (padding.length != 1) throw new ArgumentError(padding); |
+ int delta = newLength - this.length; |
+ if (delta <= 0) return this; |
+ var list = new JSArray.growable(delta + 1); |
+ list[delta] = this; |
+ return JS("String", "#.join(#)", list, padding); |
+ } |
+ |
+ String padRight(int newLength, String padding) { |
+ if (padding.length != 1) throw new ArgumentError(padding); |
+ int delta = newLength - this.length; |
+ if (delta <= 0) return this; |
+ var list = new JSArray.growable(delta + 1); |
+ list[0] = this; |
+ return JS("String", "#.join(#)", list, padding); |
} |
List<int> get codeUnits => new _CodeUnits(this); |